1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-10-18 00:50:07 +00:00

feat(install): add openSUSE and SLES 15 distribution support and compute bootstrap

This commit is contained in:
catborise 2026-09-25 20:03:02 +03:00
parent 75f73f1607
commit 88288f965d
5 changed files with 244 additions and 54 deletions

View file

@ -32,7 +32,7 @@ WebVirtCloud is a virtualization web interface for admins and users. It can dele
## Quick Install with Installer (Beta) ## Quick Install with Installer (Beta)
Install an OS and run specified commands. Installer supported OSes: Ubuntu 20.04/22.04/24.04, Debian 10/11/12, Rocky/Alma/OEL/RHEL 10. Install an OS and run specified commands. Installer supported OSes: Ubuntu 20.04/22.04/24.04, Debian 10/11/12, Rocky/Alma/OEL/RHEL 9/10, openSUSE Leap 15.x / Tumbleweed, and SLES 15.
It can be installed on a virtual machine, physical host or on a KVM host. It can be installed on a virtual machine, physical host or on a KVM host.
```bash ```bash
@ -169,6 +169,26 @@ python manage.py migrate
python manage.py runserver 0.0.0.0:8000 python manage.py runserver 0.0.0.0:8000
``` ```
#### openSUSE Leap 15.x / Tumbleweed / SLES 15:
```bash
# 1. Install system prerequisites
sudo zypper --non-interactive install -y git python3-devel python3-pip python3-virtualenv libvirt-devel python3-libvirt python3-lxml openldap2-devel cyrus-sasl-devel libopenssl-devel libxslt-devel libxml2-devel gcc pkg-config
# 2. Create virtual environment with system site packages
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
# 3. Install Python dependencies
pip install -r conf/requirements.txt
pip install -r dev/requirements.txt
# 4. Initialize configuration and run local dev server
cp webvirtcloud/settings.py.template webvirtcloud/settings.py
sed -i -E 's/SECRET_KEY = .*/SECRET_KEY = "'$(python3 conf/runit/secret_generator.py)'"/' webvirtcloud/settings.py
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
```
#### Configure the supervisor for RHEL Based OS #### Configure the supervisor for RHEL Based OS
Add the following after the [include] line (after **files = ...** actually): Add the following after the [include] line (after **files = ...** actually):

View file

@ -0,0 +1,30 @@
# Nginx configuration for openSUSE and SUSE Linux Enterprise Server (SLES)
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d and vhosts.d directories
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/vhosts.d/*.conf;
}

View file

@ -160,11 +160,11 @@ __gather_linux_system_info() {
# Let's convert CamelCase to Camel Case # Let's convert CamelCase to Camel Case
DISTRO_NAME=$(__camelcase_split "$DISTRO_NAME") DISTRO_NAME=$(__camelcase_split "$DISTRO_NAME")
fi fi
if [ "${DISTRO_NAME}" = "openSUSE project" ]; then if [ "${DISTRO_NAME}" = "openSUSE project" ] || [ "${DISTRO_NAME}" = "openSUSE" ] || [ "${DISTRO_NAME}" = "opensuse" ]; then
# lsb_release -si returns "openSUSE project" on openSUSE 12.3 # lsb_release -si returns "openSUSE project" on openSUSE 12.3
DISTRO_NAME="opensuse" DISTRO_NAME="opensuse"
fi fi
if [ "${DISTRO_NAME}" = "SUSE LINUX" ]; then if [ "${DISTRO_NAME}" = "SUSE LINUX" ] || [ "${DISTRO_NAME}" = "SLES" ] || [ "${DISTRO_NAME}" = "sles" ]; then
# lsb_release -si returns "SUSE LINUX" on SLES 11 SP3 # lsb_release -si returns "SUSE LINUX" on SLES 11 SP3
DISTRO_NAME="suse" DISTRO_NAME="suse"
fi fi
@ -223,8 +223,8 @@ __gather_linux_system_info() {
done < /etc/"${rsource}" done < /etc/"${rsource}"
;; ;;
os ) os )
nn=$(grep '^ID=' /etc/os-release | sed -e 's/^ID=\(.*\)$/\1/g') nn=$(grep '^ID=' /etc/os-release | sed -e 's/^ID=\(.*\)$/\1/g' | tr -d '"'\'')
rv=$(grep '^VERSION_ID=' /etc/os-release | sed -e 's/^VERSION_ID=\(.*\)$/\1/g') rv=$(grep '^VERSION_ID=' /etc/os-release | sed -e 's/^VERSION_ID=\(.*\)$/\1/g' | tr -d '"'\'')
[ "${rv}x" != "x" ] && v=$(__parse_version_string "$rv") || v="" [ "${rv}x" != "x" ] && v=$(__parse_version_string "$rv") || v=""
case $(echo "${nn}" | tr '[:upper:]' '[:lower:]') in case $(echo "${nn}" | tr '[:upper:]' '[:lower:]') in
arch ) arch )
@ -242,6 +242,12 @@ __gather_linux_system_info() {
echowarn "Unable to parse the Debian Version" echowarn "Unable to parse the Debian Version"
fi fi
;; ;;
opensuse* )
n="opensuse"
;;
sles*|sled*|suse* )
n="suse"
;;
* ) * )
n=${nn} n=${nn}
;; ;;
@ -305,10 +311,8 @@ __check_end_of_life_versions() {
;; ;;
opensuse) opensuse)
# openSUSE versions not supported # openSUSE: allow Leap 15.x and Tumbleweed
# if [ -n "$DISTRO_MAJOR_VERSION" ] && [ "$DISTRO_MAJOR_VERSION" -lt 12 ]; then
# <= 12.1
if { [ "$DISTRO_MAJOR_VERSION" -eq 12 ] && [ "$DISTRO_MINOR_VERSION" -eq 1 ]; } || [ "$DISTRO_MAJOR_VERSION" -lt 12 ]; then
echoerror "End of life distributions are not supported." echoerror "End of life distributions are not supported."
echoerror "Please consider upgrading to the next stable. See:" echoerror "Please consider upgrading to the next stable. See:"
echoerror " http://en.opensuse.org/Lifetime" echoerror " http://en.opensuse.org/Lifetime"
@ -317,16 +321,19 @@ __check_end_of_life_versions() {
;; ;;
suse) suse)
# SuSE versions not supported # SLES / SLED
# if [ -f /etc/SuSE-release ]; then
# < 11 SP2 SUSE_PATCHLEVEL=$(awk '/PATCHLEVEL/ {print $3}' /etc/SuSE-release )
SUSE_PATCHLEVEL=$(awk '/PATCHLEVEL/ {print $3}' /etc/SuSE-release ) if [ "x${SUSE_PATCHLEVEL}" = "x" ]; then
if [ "x${SUSE_PATCHLEVEL}" = "x" ]; then SUSE_PATCHLEVEL="00"
SUSE_PATCHLEVEL="00" fi
fi if { [ "$DISTRO_MAJOR_VERSION" -eq 11 ] && [ "$SUSE_PATCHLEVEL" -lt 02 ]; } || [ "$DISTRO_MAJOR_VERSION" -lt 11 ]; then
if { [ "$DISTRO_MAJOR_VERSION" -eq 11 ] && [ "$SUSE_PATCHLEVEL" -lt 02 ]; } || [ "$DISTRO_MAJOR_VERSION" -lt 11 ]; then echoerror "Versions lower than SuSE 11 SP2 are not supported."
echoerror "Versions lower than SuSE 11 SP2 are not supported." echoerror "Please consider upgrading to the next stable"
echoerror "Please consider upgrading to the next stable" exit 1
fi
elif [ -n "$DISTRO_MAJOR_VERSION" ] && [ "$DISTRO_MAJOR_VERSION" -lt 12 ]; then
echoerror "Versions lower than SUSE 12 are not supported."
exit 1 exit 1
fi fi
;; ;;
@ -546,58 +553,63 @@ daemons_running_fedora() {
# Opensuse Install Functions # Opensuse Install Functions
# #
install_opensuse() { install_opensuse() {
zypper -n install -l kvm libvirt bridge-utils python3-libguestfs supervisor || return 1 zypper -n install -l qemu-kvm libvirt libvirt-daemon-qemu libvirt-client bridge-utils python3-libguestfs supervisor || \
zypper -n install -l kvm libvirt bridge-utils python3-libguestfs python3-supervisor || \
zypper -n install -l kvm libvirt bridge-utils python3-libguestfs || return 1
return 0 return 0
} }
install_opensuse_post() { install_opensuse_post() {
if [ -f /etc/sysconfig/libvirtd ]; then if [ -f /etc/sysconfig/libvirtd ]; then
sed -i 's/#LIBVIRTD_ARGS/LIBVIRTD_ARGS/g' /etc/sysconfig/libvirtd sed -i 's/#LIBVIRTD_ARGS/LIBVIRTD_ARGS/g' /etc/sysconfig/libvirtd
else
echoerror "/etc/sysconfig/libvirtd not found. Exiting..."
exit 1
fi fi
if [ -f /etc/libvirt/libvirtd.conf ]; then if [ -f /etc/libvirt/libvirtd.conf ]; then
sed -i 's/#listen_tls/listen_tls/g' /etc/libvirt/libvirtd.conf sed -i 's/#listen_tls/listen_tls/g' /etc/libvirt/libvirtd.conf
sed -i 's/#listen_tcp/listen_tcp/g' /etc/libvirt/libvirtd.conf sed -i 's/#listen_tcp/listen_tcp/g' /etc/libvirt/libvirtd.conf
sed -i 's/#auth_tcp/auth_tcp/g' /etc/libvirt/libvirtd.conf sed -i 's/#auth_tcp/auth_tcp/g' /etc/libvirt/libvirtd.conf
else sed -i 's/#unix_sock_group = "libvirt"/unix_sock_group = "libvirt"/g' /etc/libvirt/libvirtd.conf
echoerror "/etc/libvirt/libvirtd.conf not found. Exiting..." sed -i 's/#unix_sock_rw_perms = "0770"/unix_sock_rw_perms = "0770"/g' /etc/libvirt/libvirtd.conf
exit 1 sed -i 's/#auth_unix_rw = "polkit"/auth_unix_rw = "none"/g' /etc/libvirt/libvirtd.conf
fi
if [ -f /etc/libvirt/virtqemud.conf ]; then
sed -i 's/#listen_tls/listen_tls/g' /etc/libvirt/virtqemud.conf
sed -i 's/#listen_tcp/listen_tcp/g' /etc/libvirt/virtqemud.conf
sed -i 's/#auth_tcp/auth_tcp/g' /etc/libvirt/virtqemud.conf
sed -i 's/#unix_sock_group = "libvirt"/unix_sock_group = "libvirt"/g' /etc/libvirt/virtqemud.conf
sed -i 's/#unix_sock_rw_perms = "0770"/unix_sock_rw_perms = "0770"/g' /etc/libvirt/virtqemud.conf
sed -i 's/#auth_unix_rw = "polkit"/auth_unix_rw = "none"/g' /etc/libvirt/virtqemud.conf
fi fi
if [ -f /etc/libvirt/qemu.conf ]; then if [ -f /etc/libvirt/qemu.conf ]; then
sed -i 's/#[ ]*vnc_listen.*/vnc_listen = "0.0.0.0"/g' /etc/libvirt/qemu.conf sed -i 's/#[ ]*vnc_listen.*/vnc_listen = "0.0.0.0"/g' /etc/libvirt/qemu.conf
sed -i 's/#[ ]*spice_listen.*/spice_listen = "0.0.0.0"/g' /etc/libvirt/qemu.conf sed -i 's/#[ ]*spice_listen.*/spice_listen = "0.0.0.0"/g' /etc/libvirt/qemu.conf
else
echoerror "/etc/libvirt/qemu.conf not found. Exiting..."
exit 1
fi fi
if [ -f /etc/supervisord.conf ]; then mkdir -p /etc/supervisord.d /etc/supervisor/conf.d
curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/daemon/gstfsd > /usr/local/bin/gstfsd if [ -f /etc/supervisord.conf ] || [ -f /etc/supervisor/supervisord.conf ]; then
chmod +x /usr/local/bin/gstfsd curl -fsSL https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/daemon/gstfsd > /usr/local/bin/gstfsd 2>/dev/null || true
curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/supervisor/gstfsd.conf > /etc/supervisor.d/gstfsd.ini chmod +x /usr/local/bin/gstfsd 2>/dev/null || true
else curl -fsSL https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/supervisor/gstfsd.conf > /etc/supervisord.d/gstfsd.ini 2>/dev/null || true
echoerror "Supervisor not found. Exiting..."
exit 1
fi fi
return 0 return 0
} }
daemons_running_opensuse() { daemons_running_opensuse() {
if [ -f /usr/lib/systemd/system/libvirtd.service ]; then systemctl enable --now libvirtd.service 2>/dev/null || systemctl enable --now virtqemud.service 2>/dev/null || true
systemctl stop libvirtd.service > /dev/null 2>&1 systemctl enable --now libvirt-guests.service 2>/dev/null || true
systemctl start libvirtd.service systemctl enable --now supervisord.service 2>/dev/null || systemctl enable --now supervisor.service 2>/dev/null || true
fi
if [ -f /usr/lib/systemd/system/libvirt-guests.service ]; then
systemctl stop libvirt-guests.service > /dev/null 2>&1
systemctl start libvirt-guests.service
fi
if [ -f /usr/lib/systemd/system/supervisord.service ]; then
systemctl stop supervisord.service > /dev/null 2>&1
systemctl start supervisord.service
fi
return 0 return 0
} }
install_suse() {
install_opensuse "$@"
}
install_suse_post() {
install_opensuse_post "$@"
}
daemons_running_suse() {
daemons_running_opensuse "$@"
}
# #
# Ended openSUSE Install Functions # Ended openSUSE Install Functions
# #

View file

@ -169,3 +169,16 @@ Built on Django REST Framework with `drf-nested-routers`, providing a structured
## 7. Architecture Highlights ## 7. Architecture Highlights
WebVirtCloud leverages a hybrid pattern: it combines the relational strengths of the **Django ORM** for persistent entities (users, compute host credentials, quotas, and permission delegations) with direct, real-time **libvirt C API bindings** for dynamic virtualization state (VM statuses, resource allocation, storage metrics, and live hardware statistics). This design ensures that the web console always reflects the true hypervisor state without risk of database desynchronization. WebVirtCloud leverages a hybrid pattern: it combines the relational strengths of the **Django ORM** for persistent entities (users, compute host credentials, quotas, and permission delegations) with direct, real-time **libvirt C API bindings** for dynamic virtualization state (VM statuses, resource allocation, storage metrics, and live hardware statistics). This design ensures that the web console always reflects the true hypervisor state without risk of database desynchronization.
---
## 8. Supported Distributions & Platform Matrix
WebVirtCloud installer and runtime dependencies support modern enterprise Linux distributions:
| Distribution Family | Target Versions | Package Manager | Init / Supervisor |
|---|---|---|---|
| **Ubuntu** | 20.04, 22.04 LTS, 24.04 LTS | `apt` | Systemd / Supervisor |
| **Debian** | 10, 11, 12 (Bookworm) | `apt` | Systemd / Supervisor / Runit |
| **RHEL / Rocky / Alma** | 9.x, 10.x | `dnf` | Systemd / Supervisord |
| **openSUSE / SLES** | openSUSE Leap 15.x, Tumbleweed, SLES 15 | `zypper` | Systemd / Supervisord |

View file

@ -160,6 +160,16 @@ install_packages () {
fi fi
done done
;; ;;
suse)
for p in $PACKAGES; do
if rpm -q "$p" >/dev/null 2>&1; then
echo " * $p already installed"
else
echo " * Installing $p"
log "zypper --non-interactive install -y $p"
fi
done
;;
esac esac
} }
@ -206,12 +216,17 @@ create_user () {
if [ "$distro" == "ubuntu" ] || [ "$distro" == "debian" ] || if [ "$distro" == "ubuntu" ] || [ "$distro" == "debian" ] ||
[[ "$distro" == "uos" && "$codename" == "eagle" ]]; then [[ "$distro" == "uos" && "$codename" == "eagle" ]]; then
adduser --quiet --disabled-password --gecos '""' "$APP_USER" adduser --quiet --disabled-password --gecos '""' "$APP_USER"
elif [ "$distro" == "suse" ]; then
useradd -m -s /bin/bash "$APP_USER" 2>/dev/null || adduser "$APP_USER"
else else
adduser "$APP_USER" useradd -m -s /bin/bash "$APP_USER" 2>/dev/null || adduser "$APP_USER"
fi fi
usermod -a -G "$nginx_group" "$APP_USER" usermod -a -G "$nginx_group" "$APP_USER" 2>/dev/null || true
usermod -a -G libvirt "$nginx_group" usermod -a -G libvirt "$nginx_group" 2>/dev/null || true
usermod -a -G kvm "$nginx_group" 2>/dev/null || true
usermod -a -G libvirt "$APP_USER" 2>/dev/null || true
usermod -a -G kvm "$APP_USER" 2>/dev/null || true
} }
run_as_app_user () { run_as_app_user () {
@ -371,6 +386,8 @@ if [ -f /etc/os-release ]; then
version="$(source /etc/os-release && echo "$VERSION_ID")" version="$(source /etc/os-release && echo "$VERSION_ID")"
# shellcheck disable=SC1091 # shellcheck disable=SC1091
codename="$(source /etc/os-release && echo "${VERSION_CODENAME:-$UBUNTU_CODENAME}")" codename="$(source /etc/os-release && echo "${VERSION_CODENAME:-$UBUNTU_CODENAME}")"
# shellcheck disable=SC1091
id_like="$(source /etc/os-release && echo "${ID_LIKE:-}")"
elif [[ -f /etc/lsb-release || -f /etc/debian_version ]]; then elif [[ -f /etc/lsb-release || -f /etc/debian_version ]]; then
if command -v lsb_release >/dev/null 2>&1; then if command -v lsb_release >/dev/null 2>&1; then
distro="$(lsb_release -is)" distro="$(lsb_release -is)"
@ -384,6 +401,11 @@ elif [[ -f /etc/lsb-release || -f /etc/debian_version ]]; then
elif [ -f /etc/centos-release ]; then elif [ -f /etc/centos-release ]; then
distro="centos" distro="centos"
version="8" version="8"
elif [ -f /etc/SuSE-release ]; then
distro="suse"
version="15"
codename=""
id_like="suse"
else else
distro="unsupported" distro="unsupported"
fi fi
@ -394,7 +416,7 @@ echo '
' '
echo "" echo ""
echo " Welcome to Webvirtcloud Installer for RHEL Based OSes, Debian and Ubuntu!" echo " Welcome to Webvirtcloud Installer for RHEL Based OSes, Debian, Ubuntu, and SUSE!"
echo "" echo ""
shopt -s nocasematch shopt -s nocasematch
case $distro in case $distro in
@ -425,6 +447,15 @@ case $distro in
supervisor_conf_path=/etc/supervisord.d supervisor_conf_path=/etc/supervisord.d
supervisor_file_name=webvirtcloud.ini supervisor_file_name=webvirtcloud.ini
;; ;;
*opensuse*|*sles*|*sled*|*suse*)
echo " The installer has detected $distro version $version."
distro=suse
nginx_group=nginx
nginxfile=/etc/nginx/conf.d/$APP_NAME.conf
supervisor_service=supervisord
supervisor_conf_path=/etc/supervisord.d
supervisor_file_name=webvirtcloud.ini
;;
*Uos*|*uos*) *Uos*|*uos*)
# codename may be fuyu, kongzi, eagle or empty string. # codename may be fuyu, kongzi, eagle or empty string.
output_expand="" output_expand=""
@ -456,8 +487,18 @@ case $distro in
supervisor_file_name=webvirtcloud.ini supervisor_file_name=webvirtcloud.ini
;; ;;
*) *)
echo " The installer was unable to determine your OS. Exiting for safety." if [[ "$id_like" =~ suse ]]; then
exit 1 echo " The installer has detected $distro (SUSE family) version $version."
distro=suse
nginx_group=nginx
nginxfile=/etc/nginx/conf.d/$APP_NAME.conf
supervisor_service=supervisord
supervisor_conf_path=/etc/supervisord.d
supervisor_file_name=webvirtcloud.ini
else
echo " The installer was unable to determine your OS. Exiting for safety."
exit 1
fi
;; ;;
esac esac
@ -684,6 +725,80 @@ case $distro in
restart_nginx restart_nginx
fi fi
;; ;;
suse)
# Install for openSUSE Leap 15.x / Tumbleweed / SLES 15
tzone=\'$(get_timezone)\'
echo -n "* Updating installed packages."
log "zypper --non-interactive refresh" & pid=$!
progress
echo "* Installing OS requirements."
PACKAGES="git python3-devel python3-pip python3-virtualenv libvirt-devel python3-libvirt python3-lxml openldap2-devel cyrus-sasl-devel libopenssl-devel libxslt-devel libxml2-devel gcc pkg-config nginx"
install_packages
set_hosts
# Supervisor on SUSE (available as python3-supervisor, supervisor, or via pip)
if ! command -v supervisord >/dev/null 2>&1; then
if zypper --non-interactive install -y python3-supervisor >/dev/null 2>&1; then
echo " * python3-supervisor installed via zypper"
elif zypper --non-interactive install -y supervisor >/dev/null 2>&1; then
echo " * supervisor installed via zypper"
else
echo " * Installing supervisor via pip3"
log "pip3 install supervisor"
fi
fi
# Ensure /etc/supervisord.d directory exists and is included in supervisord.conf
mkdir -p /etc/supervisord.d
if [ ! -f /etc/supervisord.conf ] && [ ! -f /etc/supervisor/supervisord.conf ]; then
if command -v echo_supervisord_conf >/dev/null 2>&1; then
echo_supervisord_conf > /etc/supervisord.conf
echo -e "\n[include]\nfiles = /etc/supervisord.d/*.ini\n" >> /etc/supervisord.conf
fi
elif [ -f /etc/supervisord.conf ] && ! grep -q "/etc/supervisord.d" /etc/supervisord.conf; then
echo -e "\n[include]\nfiles = /etc/supervisord.d/*.ini\n" >> /etc/supervisord.conf
fi
# Ensure systemd service for supervisord exists if installed via pip
if [ ! -f /usr/lib/systemd/system/supervisord.service ] && [ ! -f /etc/systemd/system/supervisord.service ]; then
supervisord_bin="$(command -v supervisord 2>/dev/null || echo "/usr/local/bin/supervisord")"
supervisorctl_bin="$(command -v supervisorctl 2>/dev/null || echo "/usr/local/bin/supervisorctl")"
cat > /etc/systemd/system/supervisord.service <<SVCEOF
[Unit]
Description=Process Monitoring and Control Daemon
After=network.target
[Service]
Type=forking
ExecStart=${supervisord_bin} -c /etc/supervisord.conf
ExecStop=${supervisorctl_bin} shutdown
ExecReload=${supervisorctl_bin} reload
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target
SVCEOF
systemctl daemon-reload >/dev/null 2>&1 || true
fi
install_webvirtcloud
echo "* Configuring Nginx."
configure_nginx
echo "* Configuring Supervisor."
configure_supervisor
set_firewall
restart_supervisor
restart_nginx
;;
esac esac