Repository navigation
Expand file tree
/
Copy pathmain_installer.sh
More file actions
executable file
·1443 lines (1247 loc) · 49.7 KB
/
Copy pathmain_installer.sh
File metadata and controls
executable file
·1443 lines (1247 loc) · 49.7 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
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/bash
# Main Intel Platform Installer
# Copyright (C) 2026 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
# ----------------------------------------------------------------------------
# Restart handling (issues #986 and #987)
# ----------------------------------------------------------------------------
# Two related problems, fixed together because they interact.
#
# #987: reboot messages were scattered across three scripts in three registers
# ("required", "recommended", "may be required"), and the closing line printed
# on every run whether or not anything had changed. Printing it unconditionally
# teaches users to ignore it. Ubuntu already has a convention for this,
# /run/reboot-required, which the kernel package creates automatically, with
# reasons in /run/reboot-required.pkgs. Each installer now records why, and one
# banner is shown at the end, only when a restart is genuinely needed.
#
# #986: the installer now records restart requirements once, then lets the
# component installers decide whether a reboot is needed. GPU/NPU steps may
# request a restart, but the main flow should not hardcode a specific kernel
# series or duplicate that policy.
#
# DEVKIT_AUTO_INSTALL=1 therefore installs everything in one pass, defers
# verification, RESTARTS THE MACHINE, and prints the summary on the next boot.
# In that mode the #987 banner is suppressed: telling someone to reboot
# manually and then rebooting for them would be contradictory.
#
# sudo DEVKIT_AUTO_INSTALL=1 ./main_installer.sh
REBOOT_REQUIRED_FILE="/run/reboot-required"
REBOOT_REQUIRED_REASONS="/run/reboot-required.pkgs"
export REBOOT_REQUIRED_FILE REBOOT_REQUIRED_REASONS
REBOOT_MARKER_DIR="/var/lib/intel-devkit"
REBOOT_MARKER_FILE="${REBOOT_MARKER_DIR}/pending-reboot.boot_id"
export REBOOT_MARKER_FILE
DEVKIT_AUTO_INSTALL="${DEVKIT_AUTO_INSTALL:-0}"
export DEVKIT_AUTO_INSTALL
readonly REBOOT_GRACE_SECONDS=10
SUMMARY_STATE_DIR="/var/lib/intel-devkit"
SUMMARY_UNIT="intel-devkit-summary.service"
SUMMARY_UNIT_PATH="/etc/systemd/system/${SUMMARY_UNIT}"
SUMMARY_WRAPPER="${SUMMARY_STATE_DIR}/summary.sh"
# Fail fast, treat unset variables as errors, and catch pipeline failures
set -euo pipefail
# Script directory (where main_installer.sh is located)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
# Status indicators - using ASCII for better compatibility
S_ERROR="[ERROR]"
S_VALID="[✓]"
S_WARNING="[!]"
# Colours used by the restart banners. Defined here because set -u makes an
# unset reference fatal, and empty when the output is not a terminal so the
# escape codes do not end up in the log file.
if [ -t 1 ]; then
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m'
else
YELLOW=''
GREEN=''
NC=''
fi
# Error handler: reports failing command and line number
error_trap() {
local exit_code=$?
local cmd="${BASH_COMMAND:-unknown}"
local line_no=${BASH_LINENO[0]:-?}
echo "${S_ERROR} Script exited with code ${exit_code} at line ${line_no} (command: ${cmd})"
echo "See log for details: ${LOG_FILE:-/var/log/intel-platform-installer.log}"
exit ${exit_code}
}
trap 'error_trap' ERR
trap 'echo "Script interrupted"; exit 130' INT TERM
# Default values
export INSTALL_CAMERA=false
export INSTALL_OPENVINO=false
export TELEMETRY_CONSENT=""
# Optional extras. Nothing here is installed unless the user asks for it,
# either through the selection menu or --with-extras=<list>.
INSTALL_DOCKER=false
INSTALL_QMASSA=false
INSTALL_DLSTREAMER=false
# How extras were requested: unset, menu, list or none.
EXTRAS_MODE="unset"
EXTRAS_LIST=""
# Outcome tracking, reported in the closing notice.
EXTRAS_INSTALLED=()
EXTRAS_FAILED=()
# Log file configuration
LOG_FILE="/var/log/intel-platform-installer.log"
current_boot_id() {
cat /proc/sys/kernel/random/boot_id 2>/dev/null || echo "unknown"
}
mark_reboot_pending() {
mkdir -p "$REBOOT_MARKER_DIR" 2>/dev/null || return 0
current_boot_id > "$REBOOT_MARKER_FILE" 2>/dev/null || true
}
clear_reboot_pending() {
rm -f "$REBOOT_MARKER_FILE" 2>/dev/null || true
}
is_post_reboot_pass() {
[ -f "$REBOOT_MARKER_FILE" ] || return 1
local marker_boot_id current_id
marker_boot_id=$(cat "$REBOOT_MARKER_FILE" 2>/dev/null || echo "")
current_id=$(current_boot_id)
[ -n "$marker_boot_id" ] && [ "$marker_boot_id" != "$current_id" ]
}
# Initialize logging
setup_logging() {
# Create log directory if it doesn't exist
mkdir -p "$(dirname "$LOG_FILE")"
# Rotate existing log file if it's too large (>10MB)
if [ -f "$LOG_FILE" ] && [ "$(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE" 2>/dev/null || echo 0)" -gt 10485760 ]; then
mv "$LOG_FILE" "${LOG_FILE}.old"
echo "Previous log file rotated to ${LOG_FILE}.old"
fi
# Create/clear log file with timestamp header
{
echo "========================================================================"
echo "Intel Platform Installer Log"
echo "========================================================================"
echo "Installation started: $(date '+%Y-%m-%d %H:%M:%S')"
echo "Script: $0"
echo "Arguments: $*"
echo "User: $(whoami)"
echo "Working Directory: $(pwd)"
echo "System Info: $(uname -a)"
echo "========================================================================"
echo ""
} > "$LOG_FILE"
# Ensure log file has proper permissions
chmod 644 "$LOG_FILE"
# Set up output redirection to both terminal and log file
exec > >(tee -a "$LOG_FILE")
exec 2>&1
echo "$S_VALID Logging initialized: $LOG_FILE"
}
# Usage function
usage() {
echo "Intel Platform Installer"
echo "========================"
echo ""
echo "Usage: sudo ./main_installer.sh [options]"
echo ""
echo "Drivers and OpenVINO are always installed. Optional extras are not."
echo ""
echo "Options:"
echo " --with-extras Choose optional components from a menu"
echo " --with-extras=<list> Install the listed components without asking"
echo " --no-extras Skip the menu and install no extras"
echo " --telemetry=yes|no Answer the telemetry question without prompting"
echo " -h, --help Show this help"
echo ""
echo "Components accepted by --with-extras:"
echo " docker Docker Engine, with the Compose and Buildx plugins"
echo " qmassa Terminal Intel GPU usage monitor"
echo " dlstreamer Intel DL Streamer, GStreamer media analytics elements"
echo " all Every component above"
echo " none No components, same as --no-extras"
echo ""
echo "Environment:"
echo " DEVKIT_AUTO_INSTALL=1 Unattended mode. Installs everything in a single"
echo " pass even when the kernel must be replaced, then"
echo " RESTARTS THE SYSTEM and prints the verification"
echo " summary automatically on the next boot."
echo " Default: off (two reboots, run the script twice)."
echo ""
echo "Examples:"
echo " sudo ./main_installer.sh"
echo " Drivers and OpenVINO. On a terminal you are asked about extras."
echo ""
echo " sudo ./main_installer.sh --with-extras=docker"
echo " Adds Docker, no prompt. Suitable for scripted and CI runs."
echo ""
echo " sudo ./main_installer.sh --with-extras=all"
echo " Adds every optional component, no prompt."
echo ""
echo " sudo DLSTREAMER_VERSION=2026.1.0 ./main_installer.sh --with-extras=dlstreamer"
echo " Pins the DL Streamer release instead of taking the latest."
echo ""
}
# Check if running with appropriate privileges
check_privileges() {
if [ "$EUID" -ne 0 ]; then
echo "$S_ERROR This script must be run with sudo or as root user"
exit 1
fi
}
download_scripts() {
local REPO_OWNER="open-edge-platform"
local REPO_NAME="edge-developer-kit-reference-scripts"
local BRANCH="main"
local BASE_URL="https://raw.githubusercontent.com/${REPO_OWNER}/${REPO_NAME}/refs/heads/${BRANCH}"
local DOWNLOAD_DIR
DOWNLOAD_DIR="$(pwd)"
local REQUIRED_SCRIPTS=(
"gpu_installer.sh"
"npu_installer.sh"
"openvino_installer.sh"
"print_summary_table.sh"
"dlstreamer_installer.sh"
)
# Add telemetry scripts if user consented
local ALL_SCRIPTS=("${REQUIRED_SCRIPTS[@]}")
if [ "$TELEMETRY_CONSENT" = "yes" ]; then
ALL_SCRIPTS+=("system_info.py" "telemetry.py")
echo "$S_VALID Including telemetry scripts (user consented)"
else
echo "$S_VALID Skipping telemetry scripts (user declined or not set)"
fi
# Download scripts.
# Only fetch a script that is not already present. This keeps the one-line
# install working (nothing on disk, everything is downloaded) while a run
# from a clone uses its own checked-out scripts instead of having them
# overwritten by the copies on the remote branch. Set DEVKIT_FORCE_DOWNLOAD=1
# to always pull the remote copy over any local one.
apt update
apt install -y curl
mkdir -p "$DOWNLOAD_DIR"
for script in "${ALL_SCRIPTS[@]}"; do
local url="$BASE_URL/$script"
local path="$DOWNLOAD_DIR/$script"
if [ -f "$path" ] && [ "${DEVKIT_FORCE_DOWNLOAD:-0}" != "1" ]; then
echo "Using local: $script"
continue
fi
if curl -fsSL "$url" -o "$path"; then
echo "Downloaded: $script"
else
echo "$S_ERROR Failed to download $script"
return 1
fi
done
# Check scripts
for script in "${REQUIRED_SCRIPTS[@]}"; do
local path="$DOWNLOAD_DIR/$script"
if [[ ! -f "$path" ]]; then
echo "Missing script: $script"
return 1
fi
done
echo "All scripts downloaded successfully"
# Change permissions
for script in "${REQUIRED_SCRIPTS[@]}"; do
local path="$DOWNLOAD_DIR/$script"
if [[ -f "$path" ]]; then
chmod +x "$path"
echo "Set executable: $script"
fi
done
}
# Verify a supported Ubuntu LTS release with Canonical kernel
verify_supported_ubuntu() {
echo "# Verifying supported Ubuntu LTS release with Canonical kernel..."
# Check OS release
if [ ! -f /etc/os-release ]; then
echo "$S_ERROR /etc/os-release file not found"
exit 1
fi
# shellcheck disable=SC1091
source /etc/os-release
# Check Ubuntu version
if [ "$ID" != "ubuntu" ] || [[ "$VERSION_ID" != "24.04" && "$VERSION_ID" != "26.04" ]]; then
echo "$S_ERROR This installer requires Ubuntu 24.04 or 26.04 LTS"
echo "Current OS: $PRETTY_NAME"
echo "Please upgrade to Ubuntu 24.04 or 26.04 LTS before running this script"
exit 1
fi
echo "$S_VALID Ubuntu $VERSION_ID LTS detected"
}
# Install NPU drivers (NPU-capable platforms only)
install_npu_drivers() {
# Explicit guard: Only install NPU drivers on NPU-capable platforms
if ! is_npu_capable; then
echo "$S_ERROR NPU drivers are only supported on NPU-capable platforms"
echo "Current platform: $CPU_MODEL"
echo "Skipping NPU driver installation"
return 0
fi
echo "Installing NPU drivers for $(npu_platform_label) platform..."
echo "$S_VALID NPU driver installation is supported on this $(npu_platform_label) platform"
# Execute the script instead of sourcing it to avoid context issues
# shellcheck disable=SC1091
if bash "$SCRIPT_DIR/npu_installer.sh"; then
echo "$S_VALID NPU drivers installed successfully"
return 0
else
echo "$S_ERROR NPU driver installation failed"
return 1
fi
}
# Check for GPU presence
check_intel_arc_gpu() {
echo "# Checking for GPU devices..."
# Check if lspci is available
if ! command -v lspci >/dev/null 2>&1; then
echo "$S_WARNING lspci command not found. Installing pciutils..."
apt-get update && apt-get install -y pciutils
fi
# Find any VGA/DISPLAY devices
local lspci_output
lspci_output=$(lspci -nn | grep -Ei 'VGA|DISPLAY')
if [ -z "$lspci_output" ]; then
echo "$S_WARNING No GPU devices detected"
echo "GPU driver installation will be skipped"
return 1
fi
echo "GPU devices detected:"
echo "$lspci_output"
# Enforce Intel vendor (8086) for GPU install; exit if non-Intel only
if echo "$lspci_output" | grep -Fq "[8086:"; then
echo "$S_VALID Intel (8086) GPU found - proceeding with Intel GPU driver installation"
return 0
else
# A display device with no Intel vendor is normal on Xeon and other
# server platforms, where the BMC provides the only VGA controller.
# Skip the GPU step rather than aborting the whole install.
echo "$S_WARNING No Intel (8086) GPU found among the detected devices"
echo "GPU driver installation will be skipped"
return 1
fi
}
# Install GPU drivers - only if any GPU is present
install_gpu_drivers() {
echo "# GPU Driver Installation Process"
if check_intel_arc_gpu; then
echo "Installing Intel GPU drivers..."
# Execute the script instead of sourcing it to avoid context issues
# shellcheck disable=SC1091
if bash "$SCRIPT_DIR/gpu_installer.sh"; then
echo "$S_VALID GPU drivers installed successfully"
# Optional: post verification hook could go here
return 0
else
# gpu_installer.sh already emitted detailed errors including
# OpenCL verification failures. Provide consolidated high-level status and exit.
echo "$S_ERROR GPU driver installation failed"
echo "$S_WARNING GPU driver installation had issues"
echo "$S_ERROR Exiting due to GPU installation failure"
exit 1
fi
else
echo "$S_WARNING Skipping GPU driver installation - no Intel GPU detected"
echo "This is normal on Xeon and other platforms without an Intel GPU"
return 0 # Not an error condition
fi
}
# Verify OpenCL setup for both iGPU and dGPU
verify_opencl_setup() {
echo "# Verifying OpenCL setup..."
# Wait a moment for drivers to load
sleep 3
# Check system-level GPU detection first
echo "System GPU detection:"
echo "1. PCI devices:"
lspci -nn | grep -Ei 'VGA|DISPLAY' | grep -i intel | while IFS= read -r line; do
echo " $line"
done
echo "2. DRM devices:"
if ls /dev/dri/ 2>/dev/null; then
for drm_device in /dev/dri/card* /dev/dri/render*; do
if [ -e "$drm_device" ]; then
ls -la "$drm_device"
fi
done
else
echo " No DRM devices found"
fi
echo "3. GPU kernel modules:"
lsmod | grep -E "i915|xe" || echo " No Intel GPU modules loaded"
if command -v clinfo >/dev/null 2>&1; then
echo "4. OpenCL platform detection:"
if clinfo -l 2>/dev/null; then
# Count detected devices
local platform_count device_count
platform_count=$(clinfo -l 2>/dev/null | grep -c "Platform" || echo "0")
device_count=$(clinfo -l 2>/dev/null | grep -c "Device" || echo "0")
echo "$S_VALID OpenCL setup verified:"
echo " Platforms: $platform_count"
echo " Devices: $device_count"
# Show detailed device information
echo "5. Detailed OpenCL device information:"
clinfo 2>/dev/null | grep -E "Platform|Device Name|Device Type|Driver Version" | head -10 || echo " Failed to get detailed info"
if [ "$device_count" -ge 2 ]; then
echo "$S_VALID Both iGPU and dGPU should be available"
elif [ "$device_count" -eq 1 ]; then
echo "$S_WARNING Only one GPU device detected"
echo "This might be normal if only iGPU or dGPU is functional"
else
echo "$S_WARNING No OpenCL devices detected despite installation"
fi
else
echo "$S_WARNING clinfo failed to list OpenCL devices"
echo "This indicates missing or incorrect OpenCL drivers"
# Enhanced diagnostic commands
echo "# Enhanced Troubleshooting:"
echo "1. OpenCL ICD files:"
if ls /etc/OpenCL/vendors/ 2>/dev/null; then
ls -la /etc/OpenCL/vendors/
echo " ICD file contents:"
for icd_file in /etc/OpenCL/vendors/*.icd; do
if [ -f "$icd_file" ]; then
echo " $(basename "$icd_file"): $(cat "$icd_file" 2>/dev/null || echo 'unreadable')"
fi
done
else
echo " No OpenCL vendor files found"
fi
echo "2. Intel OpenCL packages:"
dpkg -l | grep -E "intel.*opencl|intel.*level.*zero|libze" | head -10
echo "3. Library dependencies:"
if [ -f "/usr/lib/x86_64-linux-gnu/libOpenCL.so.1" ]; then
echo " libOpenCL.so.1: Found"
else
echo " libOpenCL.so.1: Missing"
fi
echo "4. User groups:"
echo " Current user groups: $(groups)"
echo ""
echo "# Common fixes to try:"
echo "1. Reboot the system: sudo reboot"
echo "2. Add user to groups: sudo usermod -aG video,render \$USER"
echo "3. Reinstall OpenCL: sudo apt reinstall intel-opencl-icd intel-level-zero-gpu"
echo "4. Check dmesg for GPU errors: dmesg | grep -i 'i915\\|gpu\\|drm'"
echo "5. Re-run GPU installer: sudo ./gpu_installer.sh"
return 1
fi
else
echo "$S_ERROR clinfo not available after GPU driver installation"
echo "This indicates the clinfo package was not properly installed"
return 1
fi
}
# Platform detection variables
PLATFORM_FAMILY=""
CPU_MODEL=""
IS_COREULTRA=false
IS_WCL=false
PTL_PLATFORM=false
# Detect platform information
detect_platform() {
echo "Detecting platform family..."
local wcl_regex='^Intel\(R\) Core\(TM\) (3|5|7) 3[0-9]{2}[[:alpha:]]*([[:space:]]|$)'
# Get CPU model
CPU_MODEL=$(grep -m1 "model name" /proc/cpuinfo | cut -d: -f2 | sed 's/^[ \t]*//' || echo "unknown")
# Detect platform family using a case statement for better readability
case "$CPU_MODEL" in
*Ultra*)
PLATFORM_FAMILY="coreultra"
IS_COREULTRA=true
;;
*Xeon*)
PLATFORM_FAMILY="xeon"
;;
*Atom*|*Core*N[0-9]*)
PLATFORM_FAMILY="atom"
;;
*Core*)
PLATFORM_FAMILY="core"
# For core family, detect if this is a WCL Core 3 300-series variant
if [[ "$CPU_MODEL" =~ $wcl_regex ]]; then
IS_WCL=true
fi
;;
*Processor*)
PLATFORM_FAMILY="processor"
;;
*)
PLATFORM_FAMILY="unknown"
;;
esac
echo " CPU Model: $CPU_MODEL"
echo " Platform Family: $PLATFORM_FAMILY"
}
# Check if Core Ultra platform
is_coreultra() {
[ "$IS_COREULTRA" = true ]
}
# Check if WCL platform
is_wcl() {
[ "$IS_WCL" = true ]
}
# Check if platform supports NPU installation
is_npu_capable() {
if is_coreultra; then
return 0
fi
if [ "$PLATFORM_FAMILY" = "core" ] && is_wcl; then
return 0
fi
return 1
}
# Platform label for NPU-capable systems
npu_platform_label() {
if is_coreultra; then
echo "Core Ultra"
elif is_wcl; then
echo "Intel® Core™ 3 300-series"
else
echo "NPU-capable"
fi
}
# Check if PTL platform
is_ptl_platform() {
[ "$PTL_PLATFORM" = true ]
}
install_openvino(){
echo ""
echo "========================================================================"
echo "# Installing OpenVINO toolkit..."
echo "========================================================================"
if [ -f "$SCRIPT_DIR/openvino_installer.sh" ]; then
echo "Found OpenVINO installer at: $SCRIPT_DIR/openvino_installer.sh"
echo "Starting OpenVINO installation process..."
if bash "$SCRIPT_DIR/openvino_installer.sh"; then
echo ""
echo "$S_VALID OpenVINO toolkit installed successfully"
# Verify installation by checking if virtual environment exists
if [ -d "/opt/intel/openvino_env" ]; then
echo "$S_VALID OpenVINO virtual environment confirmed at /opt/intel/openvino_env"
# Additional verification - check if OpenVINO can be imported
if /opt/intel/openvino_env/bin/python -c "import openvino" 2>/dev/null; then
echo "$S_VALID OpenVINO Python package verified and importable"
else
echo "$S_WARNING OpenVINO Python package may not be properly installed"
fi
else
echo "$S_WARNING OpenVINO virtual environment not found at /opt/intel/openvino_env"
fi
else
local exit_code=$?
echo ""
echo "$S_ERROR OpenVINO installation failed"
echo "Exit code: $exit_code"
echo "Please check the installation logs for details"
echo "Log file location: /var/log/intel-platform-installer.log"
return 1
fi
else
echo "$S_ERROR OpenVINO installer not found at $SCRIPT_DIR/openvino_installer.sh"
echo "Expected location: $SCRIPT_DIR/openvino_installer.sh"
echo "Current directory: $(pwd)"
echo "Available files in $SCRIPT_DIR:"
ls -la "$SCRIPT_DIR"/*.sh 2>/dev/null || echo "No .sh files found"
return 1
fi
echo "========================================================================"
}
summary(){
echo "Running Installation Summary"
# Execute the script instead of sourcing it to avoid context issues
# shellcheck disable=SC1091
bash "$SCRIPT_DIR/print_summary_table.sh"
}
# Install essential development tools
install_build_essentials() {
echo "# Installing essential development tools..."
apt-get update
if apt-get install -y build-essential gcc g++ make cmake pkg-config git curl wget; then
echo "$S_VALID Build essentials installed successfully"
else
echo "$S_ERROR Failed to install build essentials"
return 1
fi
}
# ---------------------------------------------------------------------------
# Additional software: Docker and qmassa (issue #1005)
# Installed after the drivers so a failure here cannot block the baseline.
# ---------------------------------------------------------------------------
RUSTUP_INSTALLED_BY_US=0
# Configure Docker to use the proxy from the environment, if one is set.
# Two layers need it separately:
# daemon -> systemd drop-in, used by docker pull/push
# client -> ~/.docker/config.json, used by docker build and injected into containers
# https://docs.docker.com/engine/daemon/proxy/
configure_docker_proxy() {
local http_p https_p no_p
http_p="${HTTP_PROXY:-${http_proxy:-}}"
https_p="${HTTPS_PROXY:-${https_proxy:-}}"
no_p="${NO_PROXY:-${no_proxy:-}}"
if [ -z "$http_p" ] && [ -z "$https_p" ]; then
echo "$S_VALID No proxy set in the environment, skipping Docker proxy configuration"
return 0
fi
echo "# Configuring Docker proxy from the environment..."
# Always bypass the loopback interface so local registries keep working.
case ",$no_p," in
*,localhost,*) : ;;
*) no_p="${no_p:+$no_p,}localhost,127.0.0.1,::1" ;;
esac
# systemd treats '%' as a specifier prefix, so a literal one must be doubled.
local http_sd https_sd no_sd
http_sd=${http_p//%/%%}
https_sd=${https_p//%/%%}
no_sd=${no_p//%/%%}
mkdir -p /etc/systemd/system/docker.service.d
{
echo "[Service]"
[ -n "$http_sd" ] && echo "Environment=\"HTTP_PROXY=$http_sd\""
[ -n "$https_sd" ] && echo "Environment=\"HTTPS_PROXY=$https_sd\""
[ -n "$no_sd" ] && echo "Environment=\"NO_PROXY=$no_sd\""
} > /etc/systemd/system/docker.service.d/http-proxy.conf
systemctl daemon-reload || true
systemctl restart docker || true
echo "$S_VALID Wrote /etc/systemd/system/docker.service.d/http-proxy.conf"
# Client config, merged so any existing settings survive.
local target_home target_user
for target_user in root "${SUDO_USER:-}"; do
[ -z "$target_user" ] && continue
target_home=$(getent passwd "$target_user" | cut -d: -f6)
[ -z "$target_home" ] && continue
mkdir -p "$target_home/.docker"
HTTP_P="$http_p" HTTPS_P="$https_p" NO_P="$no_p" \
python3 - "$target_home/.docker/config.json" <<'PYEOF' || true
import json, os, sys
path = sys.argv[1]
try:
with open(path) as fh:
cfg = json.load(fh)
except Exception:
cfg = {}
cfg.setdefault("proxies", {}).setdefault("default", {}).update({
k: v for k, v in (
("httpProxy", os.environ.get("HTTP_P", "")),
("httpsProxy", os.environ.get("HTTPS_P", "")),
("noProxy", os.environ.get("NO_P", "")),
) if v
})
with open(path, "w") as fh:
json.dump(cfg, fh, indent=2)
fh.write("\n")
PYEOF
chown -R "$target_user": "$target_home/.docker" 2>/dev/null || true
echo "$S_VALID Wrote $target_home/.docker/config.json"
done
systemctl show --property=Environment docker 2>/dev/null | head -1 || true
}
# https://docs.docker.com/engine/install/ubuntu/
install_docker() {
if command -v docker >/dev/null 2>&1; then
echo "$S_VALID Docker already installed: $(docker --version 2>/dev/null || echo unknown)"
else
echo "# Installing Docker Engine and Compose..."
# Distro packages conflict with Docker's own; remove any that are present.
local conflicting
conflicting=$(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc 2>/dev/null | cut -f1 || true)
if [ -n "$conflicting" ]; then
# shellcheck disable=SC2086
DEBIAN_FRONTEND=noninteractive apt-get remove -y $conflicting || true
fi
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
local codename arch
# shellcheck disable=SC1091
codename=$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
arch=$(dpkg --print-architecture)
tee /etc/apt/sources.list.d/docker.sources >/dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $codename
Components: stable
Architectures: $arch
Signed-By: /etc/apt/keyrings/docker.asc
EOF
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y \
docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker >/dev/null 2>&1 || true
echo "$S_VALID Docker installed: $(docker --version 2>/dev/null || echo unknown)"
fi
# Compose ships as a plugin, invoked as 'docker compose'
if docker compose version >/dev/null 2>&1; then
echo "$S_VALID Docker Compose installed: $(docker compose version --short 2>/dev/null || echo unknown)"
else
DEBIAN_FRONTEND=noninteractive apt-get install -y docker-compose-plugin || \
echo "$S_WARNING Docker Compose plugin not installed"
fi
# Proxy must be configured before the first pull, and after the daemon exists
configure_docker_proxy
# The docker group is created by the package but has no members, so the
# invoking user would still need sudo for every command.
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != "root" ]; then
usermod -aG docker "$SUDO_USER" || true
echo "$S_VALID Added '$SUDO_USER' to the docker group"
echo "$S_WARNING Log out and back in, or run 'newgrp docker', to use docker without sudo"
fi
}
# https://github.com/ulissesf/qmassa - cargo is the recommended install route
install_qmassa() {
if command -v qmassa >/dev/null 2>&1; then
echo "$S_VALID qmassa already installed: $(qmassa --version 2>/dev/null || echo unknown)"
return 0
fi
echo "# Installing qmassa (compiled from source)..."
DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential pkg-config libudev-dev curl ca-certificates
# qmassa needs a newer Rust than Ubuntu 24.04 ships, so use rustup.
if ! command -v cargo >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --default-toolchain stable --profile minimal --no-modify-path
RUSTUP_INSTALLED_BY_US=1
fi
# shellcheck disable=SC1090,SC1091
[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env"
if ! cargo install --locked --root /usr/local qmassa; then
echo "$S_ERROR qmassa build failed"
if [ "$RUSTUP_INSTALLED_BY_US" -eq 1 ]; then
rustup self uninstall -y >/dev/null 2>&1 || true
fi
return 1
fi
# Reclaim the toolchain, but only if this script installed it.
if [ "$RUSTUP_INSTALLED_BY_US" -eq 1 ]; then
rustup self uninstall -y >/dev/null 2>&1 || true
echo "$S_VALID Removed the temporary Rust toolchain"
fi
echo "$S_VALID qmassa installed: $(qmassa --version 2>/dev/null || echo unknown)"
echo "$S_WARNING qmassa needs root, or membership of the video and render groups, to report all stats"
}
# Delegates to the standalone installer, which handles the Intel repositories,
# the OpenVINO version check and the system-wide environment. DLSTREAMER_VERSION
# passes through the environment if the caller set it.
install_dlstreamer() {
if [ ! -f "$SCRIPT_DIR/dlstreamer_installer.sh" ]; then
echo "$S_ERROR DL Streamer installer not found at $SCRIPT_DIR/dlstreamer_installer.sh"
return 1
fi
echo "# Installing Intel DL Streamer..."
if ! bash "$SCRIPT_DIR/dlstreamer_installer.sh"; then
return 1
fi
echo "$S_VALID DL Streamer installed"
echo "$S_WARNING Log out and back in so the DL Streamer environment is applied"
}
# ---------------------------------------------------------------------------
# Optional extras: selection
# ---------------------------------------------------------------------------
parse_args() {
while [ $# -gt 0 ]; do
case "$1" in
--with-extras)
EXTRAS_MODE="menu"
;;
--with-extras=*)
EXTRAS_MODE="list"
EXTRAS_LIST="${1#*=}"
;;
--no-extras)
EXTRAS_MODE="none"
;;
--telemetry=yes|--telemetry=y)
export TELEMETRY_CONSENT="yes"
;;
--telemetry=no|--telemetry=n)
export TELEMETRY_CONSENT="no"
;;
--telemetry)
echo "$S_ERROR --telemetry requires a value: yes or no"
exit 1
;;
-h|--help)
usage
exit 0
;;
*)
echo "$S_ERROR Unknown option: $1"
echo "Run './main_installer.sh --help' for the list of options."
exit 1
;;
esac
shift
done
}
# Turn a comma separated list into the per component decisions.
apply_extras_list() {
local raw item
raw="$1"
local IFS=','
for item in $raw; do
case "$(echo "$item" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')" in
all)
INSTALL_DOCKER=true
INSTALL_QMASSA=true
INSTALL_DLSTREAMER=true
;;
docker)
INSTALL_DOCKER=true
;;
qmassa)
INSTALL_QMASSA=true
;;
dlstreamer)
INSTALL_DLSTREAMER=true
;;
none|"")
;;
*)
echo "$S_ERROR Unknown component: $item"
echo "Valid components: docker, qmassa, dlstreamer, all, none"
exit 1
;;
esac
done
}
# Plain prompt, used when whiptail is unavailable.
select_extras_text() {
local reply=""
echo ""
echo "Optional components, none of them required:"
echo " docker Docker Engine, with the Compose and Buildx plugins"
echo " qmassa Terminal Intel GPU usage monitor"
echo " dlstreamer Intel DL Streamer, GStreamer media analytics elements"
echo ""
read -r -p "Install which? [docker,qmassa,dlstreamer,all,none] (default none): " reply || reply=""
if [ -n "$reply" ]; then
apply_extras_list "$reply"
fi
}
# Checklist menu. Runs before logging starts, so it has the real terminal.
select_extras_menu() {
local choices="" status=0
if ! command -v whiptail >/dev/null 2>&1; then
select_extras_text
return 0
fi
# whiptail draws on stderr and returns its result on stdout, hence the
# descriptor swap. Cancel and Escape exit non-zero, which must not reach
# the ERR trap, so the status is captured rather than allowed to propagate.
set +e
choices=$(whiptail --title "Optional components" \
--checklist "\nNone of these are required. Space selects, Enter confirms.\n" \
14 76 3 \
"docker" "Docker Engine, Compose and Buildx plugins" OFF \
"qmassa" "Terminal Intel GPU usage monitor" OFF \
"dlstreamer" "DL Streamer media analytics elements" OFF \
3>&1 1>&2 2>&3)
status=$?
set -e
if [ "$status" -ne 0 ]; then
return 0
fi
case "$choices" in
*docker*) INSTALL_DOCKER=true ;;
esac
case "$choices" in
*qmassa*) INSTALL_QMASSA=true ;;
esac
case "$choices" in
*dlstreamer*) INSTALL_DLSTREAMER=true ;;
esac
}
# Decide what to install. Called before setup_logging so that any prompt
# reaches the terminal instead of the tee pipeline.
resolve_extras() {
case "$EXTRAS_MODE" in
list)
apply_extras_list "$EXTRAS_LIST"
;;
none)