Skip to content

Commit f988bf9

Browse files
MickLeskProxmoxVE Developer
andauthored
Refactor code structure for improved readability and maintainability (#533)
* Refactor code structure for improved readability and maintainability * fix: update references from error_handler.func to error-handler.func for consistency --------- Co-authored-by: ProxmoxVE Developer <dev@localhost>
1 parent 541fa9a commit f988bf9

9 files changed

Lines changed: 17178 additions & 10795 deletions

File tree

scripts/core/alpine-install.func

Lines changed: 186 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -4,184 +4,237 @@
44
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
55

66
if ! command -v curl >/dev/null 2>&1; then
7-
apk update && apk add curl >/dev/null 2>&1
7+
apk update && apk add curl >/dev/null 2>&1
88
fi
99
source "$(dirname "${BASH_SOURCE[0]}")/core.func"
1010
source "$(dirname "${BASH_SOURCE[0]}")/error-handler.func"
1111
load_functions
1212
catch_errors
1313

14+
# Persist diagnostics setting inside container (exported from build.func)
15+
# so addon scripts running later can find the user's choice
16+
if [[ ! -f /usr/local/community-scripts/diagnostics ]]; then
17+
mkdir -p /usr/local/community-scripts
18+
echo "DIAGNOSTICS=${DIAGNOSTICS:-no}" >/usr/local/community-scripts/diagnostics
19+
fi
20+
1421
# Get LXC IP address (must be called INSIDE container, after network is up)
1522
get_lxc_ip
1623

24+
# ------------------------------------------------------------------------------
25+
# post_progress_to_api()
26+
#
27+
# - Lightweight progress ping from inside the container
28+
# - Updates the existing telemetry record status
29+
# - Arguments:
30+
# * $1: status (optional, default: "configuring")
31+
# - Signals that the installation is actively progressing (not stuck)
32+
# - Fire-and-forget: never blocks or fails the script
33+
# - Only executes if DIAGNOSTICS=yes and RANDOM_UUID is set
34+
# ------------------------------------------------------------------------------
35+
post_progress_to_api() {
36+
command -v curl &>/dev/null || return 0
37+
[[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0
38+
[[ -z "${RANDOM_UUID:-}" ]] && return 0
39+
40+
local progress_status="${1:-configuring}"
41+
42+
curl -fsS -m 5 -X POST "https://telemetry.community-scripts.org/telemetry" \
43+
-H "Content-Type: application/json" \
44+
-d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"lxc\",\"nsapp\":\"${app:-unknown}\",\"status\":\"${progress_status}\"}" &>/dev/null || true
45+
}
46+
1747
# This function enables IPv6 if it's not disabled and sets verbose mode
1848
verb_ip6() {
19-
set_std_mode # Set STD mode based on VERBOSE
20-
21-
if [ "${IPV6_METHOD:-}" = "disable" ]; then
22-
msg_info "Disabling IPv6 (this may affect some services)"
23-
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
24-
$STD sysctl -w net.ipv6.conf.default.disable_ipv6=1
25-
$STD sysctl -w net.ipv6.conf.lo.disable_ipv6=1
26-
mkdir -p /etc/sysctl.d
27-
$STD tee /etc/sysctl.d/99-disable-ipv6.conf >/dev/null <<EOF
49+
set_std_mode # Set STD mode based on VERBOSE
50+
51+
if [ "${IPV6_METHOD:-}" = "disable" ]; then
52+
msg_info "Disabling IPv6 (this may affect some services)"
53+
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
54+
$STD sysctl -w net.ipv6.conf.default.disable_ipv6=1
55+
$STD sysctl -w net.ipv6.conf.lo.disable_ipv6=1
56+
mkdir -p /etc/sysctl.d
57+
$STD tee /etc/sysctl.d/99-disable-ipv6.conf >/dev/null <<EOF
2858
net.ipv6.conf.all.disable_ipv6 = 1
2959
net.ipv6.conf.default.disable_ipv6 = 1
3060
net.ipv6.conf.lo.disable_ipv6 = 1
3161
EOF
32-
$STD rc-update add sysctl default
33-
msg_ok "Disabled IPv6"
34-
fi
35-
}
36-
37-
set -Eeuo pipefail
38-
trap 'error_handler $? $LINENO "$BASH_COMMAND"' ERR
39-
trap on_exit EXIT
40-
trap on_interrupt INT
41-
trap on_terminate TERM
42-
43-
error_handler() {
44-
local exit_code="$1"
45-
local line_number="$2"
46-
local command="$3"
47-
48-
if [[ "$exit_code" -eq 0 ]]; then
49-
return 0
50-
fi
51-
52-
printf "\e[?25h"
53-
echo -e "\n${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}\n"
54-
exit "$exit_code"
55-
}
56-
57-
on_exit() {
58-
local exit_code="$?"
59-
[[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile"
60-
exit "$exit_code"
61-
}
62-
63-
on_interrupt() {
64-
echo -e "\n${RD}Interrupted by user (SIGINT)${CL}"
65-
exit 130
66-
}
67-
68-
on_terminate() {
69-
echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}"
70-
exit 143
62+
$STD rc-update add sysctl default
63+
msg_ok "Disabled IPv6"
64+
fi
7165
}
7266

7367
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
7468
setting_up_container() {
75-
msg_info "Setting up Container OS"
76-
while [ $i -gt 0 ]; do
77-
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
78-
break
79-
fi
80-
echo 1>&2 -en "${CROSS}${RD} No Network! "
81-
sleep $RETRY_EVERY
82-
i=$((i - 1))
83-
done
84-
85-
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
86-
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
87-
echo -e "${NETWORK}Check Network Settings"
88-
exit 1
89-
fi
90-
msg_ok "Set up Container OS"
91-
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}"
69+
msg_info "Setting up Container OS"
70+
while [ $i -gt 0 ]; do
71+
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
72+
break
73+
fi
74+
echo 1>&2 -en "${CROSS}${RD} No Network! "
75+
sleep $RETRY_EVERY
76+
i=$((i - 1))
77+
done
78+
79+
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
80+
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
81+
echo -e "${NETWORK}Check Network Settings"
82+
exit 121
83+
fi
84+
msg_ok "Set up Container OS"
85+
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}"
86+
post_progress_to_api
9287
}
9388

9489
# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected
9590
network_check() {
96-
set +e
97-
trap - ERR
98-
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
99-
ipv4_status="${GN}✔${CL} IPv4"
100-
else
101-
ipv4_status="${RD}✖${CL} IPv4"
102-
read -r -p "Internet NOT connected. Continue anyway? <y/N> " prompt
103-
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
104-
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
105-
else
106-
echo -e "${NETWORK}Check Network Settings"
107-
exit 1
108-
fi
109-
fi
110-
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
111-
if [[ -z "$RESOLVEDIP" ]]; then
112-
msg_error "Internet: ${ipv4_status} DNS Failed"
113-
else
114-
msg_ok "Internet: ${ipv4_status} DNS: ${BL}${RESOLVEDIP}${CL}"
115-
fi
116-
set -e
117-
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
91+
set +e
92+
trap - ERR
93+
ipv4_connected=false
94+
95+
# Check IPv4 connectivity to Cloudflare, Google & Quad9 DNS servers
96+
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
97+
msg_ok "IPv4 Internet Connected"
98+
ipv4_connected=true
99+
else
100+
msg_error "IPv4 Internet Not Connected"
101+
fi
102+
103+
if [[ $ipv4_connected == false ]]; then
104+
read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
105+
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
106+
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
107+
else
108+
echo -e "${NETWORK}Check Network Settings"
109+
exit 122
110+
fi
111+
fi
112+
113+
# DNS resolution checks for GitHub-related domains
114+
GIT_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com" "git.community-scripts.org")
115+
GIT_STATUS="Git DNS:"
116+
DNS_FAILED=false
117+
118+
for HOST in "${GIT_HOSTS[@]}"; do
119+
RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | grep -E '(^([0-9]{1,3}\.){3}[0-9]{1,3}$)|(^[a-fA-F0-9:]+$)' | head -n1)
120+
if [[ -z "$RESOLVEDIP" ]]; then
121+
GIT_STATUS+="$HOST:($DNSFAIL)"
122+
DNS_FAILED=true
123+
else
124+
GIT_STATUS+=" $HOST:($DNSOK)"
125+
fi
126+
done
127+
128+
if [[ "$DNS_FAILED" == true ]]; then
129+
fatal "$GIT_STATUS"
130+
else
131+
msg_ok "$GIT_STATUS"
132+
fi
133+
134+
set -e
135+
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
118136
}
119137

120-
# This function updates the Container OS by running apt-get update and upgrade
138+
# This function updates the Container OS by running apk upgrade with mirror fallback
121139
update_os() {
122-
msg_info "Updating Container OS"
123-
$STD apk -U upgrade
124-
source "$(dirname "${BASH_SOURCE[0]}")/tools.func"
125-
msg_ok "Updated Container OS"
140+
msg_info "Updating Container OS"
141+
if ! $STD apk -U upgrade; then
142+
msg_warn "apk update failed (dl-cdn.alpinelinux.org), trying alternate mirrors..."
143+
local alpine_mirrors="mirror.init7.net ftp.halifax.rwth-aachen.de mirrors.edge.kernel.org alpine.mirror.wearetriple.com mirror.leaseweb.com uk.alpinelinux.org dl-2.alpinelinux.org dl-4.alpinelinux.org"
144+
local apk_ok=false
145+
for m in $(printf '%s\n' $alpine_mirrors | shuf); do
146+
if timeout 2 bash -c "echo >/dev/tcp/$m/80" 2>/dev/null; then
147+
msg_custom "${INFO}" "${YW}" "Attempting mirror: ${m}"
148+
cat <<EOF >/etc/apk/repositories
149+
http://$m/alpine/latest-stable/main
150+
http://$m/alpine/latest-stable/community
151+
EOF
152+
if $STD apk -U upgrade; then
153+
msg_ok "CDN set to ${m}: tests passed"
154+
apk_ok=true
155+
break
156+
else
157+
msg_warn "Mirror ${m} failed"
158+
fi
159+
fi
160+
done
161+
if [[ "$apk_ok" != true ]]; then
162+
msg_error "All Alpine mirrors failed. Check network or try again later."
163+
exit 1
164+
fi
165+
fi
166+
local tools_content
167+
tools_content=$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) || {
168+
msg_error "Failed to download tools.func"
169+
exit 115
170+
}
171+
source /dev/stdin <<<"$tools_content"
172+
if ! declare -f fetch_and_deploy_gh_release >/dev/null 2>&1; then
173+
msg_error "tools.func loaded but incomplete — missing expected functions"
174+
exit 115
175+
fi
176+
msg_ok "Updated Container OS"
177+
post_progress_to_api
126178
}
127179

128180
# This function modifies the message of the day (motd) and SSH settings
129181
motd_ssh() {
130-
echo "export TERM='xterm-256color'" >>/root/.bashrc
131-
132-
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
133-
echo "echo -e \"\"" >"$PROFILE_FILE"
134-
echo -e "echo -e \"${BOLD}${APPLICATION} LXC Container${CL}"\" >>"$PROFILE_FILE"
135-
echo -e "echo -e \"${TAB}${GATEWAY}${YW} Provided by: ${GN}community-scripts ORG ${YW}| GitHub: ${GN}https://github.com/community-scripts/ProxmoxVE${CL}\"" >>"$PROFILE_FILE"
136-
echo "echo \"\"" >>"$PROFILE_FILE"
137-
echo -e "echo -e \"${TAB}${OS}${YW} OS: ${GN}\$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '\"') - Version: \$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '\"')${CL}\"" >>"$PROFILE_FILE"
138-
echo -e "echo -e \"${TAB}${HOSTNAME}${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE"
139-
echo -e "echo -e \"${TAB}${INFO}${YW} IP Address: ${GN}\$(ip -4 addr show eth0 | awk '/inet / {print \$2}' | cut -d/ -f1 | head -n 1)${CL}\"" >>"$PROFILE_FILE"
140-
141-
# Configure SSH if enabled
142-
if [[ "${SSH_ROOT}" == "yes" ]]; then
143-
# Enable sshd service
144-
$STD rc-update add sshd
145-
# Allow root login via SSH
146-
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
147-
# Start the sshd service
148-
$STD /etc/init.d/sshd start
149-
fi
182+
echo "export TERM='xterm-256color'" >>/root/.bashrc
183+
184+
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
185+
echo "echo -e \"\"" >"$PROFILE_FILE"
186+
echo -e "echo -e \"${BOLD}${APPLICATION} LXC Container${CL}"\" >>"$PROFILE_FILE"
187+
echo -e "echo -e \"${TAB}${GATEWAY}${YW} Provided by: ${GN}community-scripts ORG ${YW}| GitHub: ${GN}https://github.com/community-scripts/ProxmoxVE${CL}\"" >>"$PROFILE_FILE"
188+
echo "echo \"\"" >>"$PROFILE_FILE"
189+
echo -e "echo -e \"${TAB}${OS}${YW} OS: ${GN}\$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '\"') - Version: \$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '\"')${CL}\"" >>"$PROFILE_FILE"
190+
echo -e "echo -e \"${TAB}${HOSTNAME}${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE"
191+
echo -e "echo -e \"${TAB}${INFO}${YW} IP Address: ${GN}\$(ip -4 addr show eth0 | awk '/inet / {print \$2}' | cut -d/ -f1 | head -n 1)${CL}\"" >>"$PROFILE_FILE"
192+
193+
# Configure SSH if enabled
194+
if [[ "${SSH_ROOT}" == "yes" ]]; then
195+
# Enable sshd service
196+
$STD rc-update add sshd
197+
# Allow root login via SSH
198+
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
199+
# Start the sshd service
200+
$STD /etc/init.d/sshd start
201+
fi
202+
post_progress_to_api
150203
}
151204

152205
# Validate Timezone for some LXC's
153206
validate_tz() {
154-
[[ -f "/usr/share/zoneinfo/$1" ]]
207+
[[ -f "/usr/share/zoneinfo/$1" ]]
155208
}
156209

157210
# This function customizes the container and enables passwordless login for the root user
158211
customize() {
159-
if [[ "$PASSWORD" == "" ]]; then
160-
msg_info "Customizing Container"
161-
passwd -d root >/dev/null 2>&1
212+
if [[ "$PASSWORD" == "" ]]; then
213+
msg_info "Customizing Container"
214+
passwd -d root >/dev/null 2>&1
162215

163-
# Ensure agetty is available
164-
apk add --no-cache --force-broken-world util-linux >/dev/null 2>&1
216+
# Ensure agetty is available
217+
apk add --no-cache --force-broken-world util-linux >/dev/null 2>&1
165218

166-
# Create persistent autologin boot script
167-
mkdir -p /etc/local.d
168-
cat <<'EOF' >/etc/local.d/autologin.start
219+
# Create persistent autologin boot script
220+
mkdir -p /etc/local.d
221+
cat <<'EOF' >/etc/local.d/autologin.start
169222
#!/bin/sh
170223
sed -i 's|^tty1::respawn:.*|tty1::respawn:/sbin/agetty --autologin root --noclear tty1 38400 linux|' /etc/inittab
171224
kill -HUP 1
172225
EOF
173-
touch /root/.hushlogin
226+
touch /root/.hushlogin
174227

175-
chmod +x /etc/local.d/autologin.start
176-
rc-update add local >/dev/null 2>&1
228+
chmod +x /etc/local.d/autologin.start
229+
rc-update add local >/dev/null 2>&1
177230

178-
# Apply autologin immediately for current session
179-
/etc/local.d/autologin.start
231+
# Apply autologin immediately for current session
232+
/etc/local.d/autologin.start
180233

181-
msg_ok "Customized Container"
182-
fi
234+
msg_ok "Customized Container"
235+
fi
183236

184-
echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update
185-
chmod +x /usr/bin/update
186-
187-
}
237+
echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update
238+
chmod +x /usr/bin/update
239+
post_progress_to_api
240+
}

0 commit comments

Comments
 (0)