mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-28 04:00:09 +01:00
281 lines
7.7 KiB
Text
281 lines
7.7 KiB
Text
|
|
#!/bin/bash
|
||
|
|
|
||
|
|
set -e
|
||
|
|
|
||
|
|
###############################################################################
|
||
|
|
# Script to create a virtual machine for testing NetworkManager.
|
||
|
|
#
|
||
|
|
# Commands:
|
||
|
|
# - build: build a new VM, named "$VM" ("nm").
|
||
|
|
# - run: start the VM.
|
||
|
|
# - exec: run bash inside the VM, connecting via ssh (this is the default).
|
||
|
|
# - stop: stop the VM.
|
||
|
|
# - reexec: stop and exec.
|
||
|
|
# - clean: stop the VM and delete the image.
|
||
|
|
#
|
||
|
|
# Commands exec and reexec accepts extra arguments, which are the command to
|
||
|
|
# execute in the VM instead of opening an ssh session.
|
||
|
|
#
|
||
|
|
# NetworkManager directories:
|
||
|
|
#
|
||
|
|
# The NetworkManager root directory is mounted in the VM as a filesystem share.
|
||
|
|
# You can run `make install` and run tests.
|
||
|
|
#
|
||
|
|
# Create a symlink ./.git/NetworkManager-ci, to share the CI directory too.
|
||
|
|
#
|
||
|
|
# Required packages:
|
||
|
|
#
|
||
|
|
# Your host needs libvirt, libvirt-nss and guestfs-tools. To access the VM with
|
||
|
|
# `ssh root@$VM`, configure /etc/nsswitch.conf as explained in
|
||
|
|
# https://libvirt.org/nss.html (otherwise, `nm-in-vm exec` won't work, either).
|
||
|
|
#
|
||
|
|
# Prepare for testing:
|
||
|
|
#
|
||
|
|
# There is a script nm-env-prepare.sh to generate a net1 interface for testing.
|
||
|
|
# Currently NM-ci requires a working eth1, so use this before running a CI test:
|
||
|
|
# `nm-env-prepare.sh --prefix eth -i 1 && sleep 1 && nmcli device connect eth1`
|
||
|
|
#
|
||
|
|
# Additional VMs:
|
||
|
|
#
|
||
|
|
# By default, the VM named 'nm' is created, but additional ones can be created:
|
||
|
|
# $ VM=nm2 nm-in-vm build
|
||
|
|
# $ VM=nm2 nm-in-vm exec
|
||
|
|
# $ VM=nm2 nm-in-vm stop
|
||
|
|
#
|
||
|
|
# Choosing a different OS:
|
||
|
|
#
|
||
|
|
# By default Fedora is used, but you can choose a different OS. Most from the
|
||
|
|
# list `virt-builder --list` will work.
|
||
|
|
# $ OS_VERSION=debian-12 nm-in-vm build
|
||
|
|
# $ nm-in-vm exec
|
||
|
|
# $ nm-in-vm stop
|
||
|
|
###############################################################################
|
||
|
|
|
||
|
|
# Check for libvirt
|
||
|
|
if ! (command -v virsh && command -v virt-builder && command -v virt-install) &>/dev/null; then
|
||
|
|
echo "libvirt and guestfs-tools are required" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
# set defaults if user didn't define these values
|
||
|
|
VM=${VM:="nm"}
|
||
|
|
OS_VERSION=${OS_VERSION:=}
|
||
|
|
RAM=${RAM:=2048}
|
||
|
|
IMAGE_SIZE=${IMAGE_SIZE:=10G}
|
||
|
|
ROOT_PASSWORD=${ROOT_PASSWORD:=nm}
|
||
|
|
LIBVIRT_POOL=${LIBVIRT_POOL:=default} # only useful if BASEDIR_VM_IMAGE is empty
|
||
|
|
BASEDIR_VM_IMAGE=${BASEDIR_VM_IMAGE:=}
|
||
|
|
BASEDIR_NM=${BASEDIR_NM:=}
|
||
|
|
BASEDIR_NM_CI=${BASEDIR_NM_CI:=}
|
||
|
|
HOST_BRIDGE=${HOST_BRIDGE:=virbr0}
|
||
|
|
SSH_LOG_LEVEL=${SSH_LOG_LEVEL:=ERROR}
|
||
|
|
|
||
|
|
if [[ -z $OS_VERSION ]]; then
|
||
|
|
# if running Fedora, select same version, else select latest Fedora
|
||
|
|
if grep -q "^ID=fedora$" /etc/os-release 2>/dev/null ; then
|
||
|
|
OS_VERSION="$(sed -n 's/^VERSION_ID=\([0-9]\+\)$/fedora-\1/p' /etc/os-release)"
|
||
|
|
else
|
||
|
|
OS_VERSION=$(virt-builder --list | grep '^fedora' | sort | tail -n 1 | cut -d" " -f 1)
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ -z $BASEDIR_NM ]]; then
|
||
|
|
BASEDIR_NM="$(readlink -f "$(dirname -- "$BASH_SOURCE")/..")"
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ -z $BASEDIR_NM_CI && -d "$BASEDIR_NM/.git/NetworkManager-ci" ]]; then
|
||
|
|
BASEDIR_NM_CI="$(readlink -f "$BASEDIR_NM/.git/NetworkManager-ci")"
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ -z $BASEDIR_VM_IMAGE ]]; then
|
||
|
|
libvirt_pool_path_xml=$(virsh pool-dumpxml $LIBVIRT_POOL | grep -F '<path>')
|
||
|
|
if [[ $libvirt_pool_path_xml =~ \<path\>(.*)\</path\> ]]; then
|
||
|
|
BASEDIR_VM_IMAGE=${BASH_REMATCH[1]}
|
||
|
|
else
|
||
|
|
BASEDIR_VM_IMAGE=$BASEDIR_NM
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
|
||
|
|
# compute some values that depends on user selectable variables
|
||
|
|
basedir_vm_image=$(readlink -f "$BASEDIR_VM_IMAGE")
|
||
|
|
vm_image_file="$VM.qcow2"
|
||
|
|
os_variant=${OS_VERSION//-/} # virt-install --os-variant value, deduced from OS_VERSION
|
||
|
|
os_variant=${os_variant/centosstream/centos-stream}
|
||
|
|
|
||
|
|
##############################################################################
|
||
|
|
|
||
|
|
do_build() {
|
||
|
|
local t
|
||
|
|
t=$'\t'
|
||
|
|
|
||
|
|
if vm_is_installed; then
|
||
|
|
echo "The virtual machine '$VM' is already installed, skiping build" >&2
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
if vm_image_exists; then
|
||
|
|
echo "The image '$basedir_vm_image/$vm_image_file' already exists, skiping build" >&2
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ -n $BASEDIR_NM_CI ]]; then
|
||
|
|
nm_ci_mkdir=("--mkdir" "$BASEDIR_NM_CI")
|
||
|
|
nm_ci_fstab=("--append-line" "/etc/fstab:/NM_CI${t}$BASEDIR_NM_CI${t}9p${t}trans=virtio,rw,_netdev${t}0${t}0")
|
||
|
|
nm_ci_fs=("--filesystem" "$BASEDIR_NM_CI,/NM_CI")
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo "Creating VM"
|
||
|
|
echo " - VM NAME: $VM"
|
||
|
|
echo " - OS VERSION: $OS_VERSION"
|
||
|
|
echo " - SIZE: $IMAGE_SIZE"
|
||
|
|
echo " - RAM: $RAM"
|
||
|
|
echo " - ROOT PASSWORD: $ROOT_PASSWORD"
|
||
|
|
echo " - IMAGE PATH: $basedir_vm_image/$vm_image_file"
|
||
|
|
echo " - NM DIR: $BASEDIR_NM"
|
||
|
|
echo " - NM CI DIR: $([[ -n $BASEDIR_NM_CI ]] && echo "$BASEDIR_NM_CI" || echo '<none>')"
|
||
|
|
echo " - HOST BRIDGE: $HOST_BRIDGE"
|
||
|
|
|
||
|
|
virt-builder "$OS_VERSION" \
|
||
|
|
--output "$basedir_vm_image/$vm_image_file" \
|
||
|
|
--size "$IMAGE_SIZE" \
|
||
|
|
--format qcow2 \
|
||
|
|
--arch x86_64 \
|
||
|
|
--hostname "$VM" \
|
||
|
|
--root-password password:nm \
|
||
|
|
--ssh-inject root \
|
||
|
|
--mkdir "$BASEDIR_NM" \
|
||
|
|
--append-line "/etc/fstab:/NM${t}$BASEDIR_NM${t}9p${t}trans=virtio,rw,_netdev${t}0${t}0" \
|
||
|
|
"${nm_ci_mkdir[@]}" \
|
||
|
|
"${nm_ci_fstab[@]}" \
|
||
|
|
--update
|
||
|
|
|
||
|
|
virt-install \
|
||
|
|
--name "$VM" \
|
||
|
|
--ram "$RAM" \
|
||
|
|
--disk "path=$basedir_vm_image/$vm_image_file,format=qcow2" \
|
||
|
|
--os-variant "$os_variant" \
|
||
|
|
--filesystem "$BASEDIR_NM,/NM" \
|
||
|
|
"${nm_ci_fs[@]}" \
|
||
|
|
--network "bridge=$HOST_BRIDGE" \
|
||
|
|
--import \
|
||
|
|
--autoconsole none \
|
||
|
|
--noreboot
|
||
|
|
}
|
||
|
|
|
||
|
|
do_clean() {
|
||
|
|
vm_is_running && virsh shutdown "$VM" &>/dev/null
|
||
|
|
vm_is_installed && virsh undefine "$VM" &>/dev/null
|
||
|
|
rm -f "$basedir_vm_image/$vm_image_file"
|
||
|
|
}
|
||
|
|
|
||
|
|
do_run() {
|
||
|
|
vm_is_installed || do_build
|
||
|
|
vm_is_running && return 0
|
||
|
|
virsh start "$VM" >&2
|
||
|
|
}
|
||
|
|
|
||
|
|
do_exec() {
|
||
|
|
do_run
|
||
|
|
|
||
|
|
local failed=0
|
||
|
|
while ! ping -c 1 "$VM" &>/dev/null; do
|
||
|
|
failed=$((failed + 1))
|
||
|
|
(( failed < 15 )) || die "Timeout trying to ping the VM"
|
||
|
|
sleep 1
|
||
|
|
done
|
||
|
|
|
||
|
|
ssh \
|
||
|
|
-o StrictHostKeyChecking=no \
|
||
|
|
-o UserKnownHostsFile=/dev/null \
|
||
|
|
-o LogLevel="$SSH_LOG_LEVEL" \
|
||
|
|
"root@$VM" "$@"
|
||
|
|
}
|
||
|
|
|
||
|
|
do_reexec() {
|
||
|
|
vm_is_running && do_stop
|
||
|
|
|
||
|
|
local waited=0
|
||
|
|
while vm_is_running; do
|
||
|
|
waited=$((waited + 1))
|
||
|
|
(( waited < 30 )) || die "Timeout waiting for VM shutdown"
|
||
|
|
sleep 1
|
||
|
|
done
|
||
|
|
|
||
|
|
do_exec "$@"
|
||
|
|
}
|
||
|
|
|
||
|
|
do_stop() {
|
||
|
|
vm_is_running && virsh shutdown "$VM" >&2
|
||
|
|
}
|
||
|
|
|
||
|
|
###############################################################################
|
||
|
|
|
||
|
|
vm_image_exists() {
|
||
|
|
[[ -f "$basedir_vm_image/$vm_image_file" ]] || return 1
|
||
|
|
}
|
||
|
|
|
||
|
|
vm_is_installed() {
|
||
|
|
virsh list --all --name | grep --fixed-strings --line-regexp "$VM" &>/dev/null || return 1
|
||
|
|
}
|
||
|
|
|
||
|
|
vm_is_running() {
|
||
|
|
virsh list --name | grep --fixed-strings --line-regexp "$VM" &>/dev/null || return 1
|
||
|
|
}
|
||
|
|
|
||
|
|
usage() {
|
||
|
|
echo "nm-in-vm [-h|--help] build|run|exec|stop|reexec|clean"
|
||
|
|
}
|
||
|
|
|
||
|
|
help() {
|
||
|
|
usage
|
||
|
|
echo
|
||
|
|
awk '/^####*$/ { if (on) exit; on=-1; } !/^####*$/ { if (on) print(substr($0,3)) }' "$BASH_SOURCE"
|
||
|
|
echo
|
||
|
|
}
|
||
|
|
|
||
|
|
die() {
|
||
|
|
echo "$1" >&2
|
||
|
|
exit 1
|
||
|
|
}
|
||
|
|
|
||
|
|
###############################################################################
|
||
|
|
|
||
|
|
cmd=
|
||
|
|
|
||
|
|
while (( $# > 0 )); do
|
||
|
|
case "$1" in
|
||
|
|
build|run|exec|reexec|stop|clean)
|
||
|
|
cmd="$1"
|
||
|
|
shift
|
||
|
|
;;
|
||
|
|
-h|--help)
|
||
|
|
help
|
||
|
|
exit 0
|
||
|
|
;;
|
||
|
|
--)
|
||
|
|
shift
|
||
|
|
break
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
[[ $cmd != "" ]] && break
|
||
|
|
echo "Invalid argument '$1'" >&2
|
||
|
|
echo $(usage) >&2
|
||
|
|
exit 1
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
done
|
||
|
|
|
||
|
|
if [[ $cmd == "" ]]; then
|
||
|
|
cmd=exec
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ $UID == 0 ]]; then
|
||
|
|
die "cannot run as root"
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ $cmd != exec && $cmd != reexec && $# != 0 ]]; then
|
||
|
|
die "Extra arguments are only allowed with exec|reexec command"
|
||
|
|
fi
|
||
|
|
|
||
|
|
do_$cmd "$@"
|