Browse Source

refactor: clean ups (#80)

- use builtin vm list to dynamically generate distros
- use builtin vm list to add custom distros in the .kivrc file
- support for --arch; add x86_64 and aarch64 default qcow2 images
- remove support for end of life distros
- support set -euo pipefail
- some shellcheck cleanups
- remove ISO generation in favour of --cloud-init flag
- add timeout when waiting for MAC address
- set default distro to rocky9
- bump default memory to 1536MB to support newer distributions
pull/81/head 1.0.0
Giovanni Torres 8 months ago committed by GitHub
parent
commit
ab3e56a3d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 7
      .kivrc
  2. 154
      README.md
  3. 471
      kvm-install-vm

7
.kivrc

@ -1,5 +1,12 @@
## .kivrc - Set custom defaults for kvm-install-vm
# Custom Images
# Format: "name|description|architecture|image download url|login user"
# Name should match what is in the os-info database
#BUILTIN_VMS+=("almalinux9:AlmaLinux 9 cloud image:x86_64:https://repo.almalinux.org/almalinux/9/cloud/images/AlmaLinux-9-cloud.qcow2|almalinux")
#BUILTIN_VMS+=("almalinux9:AlmaLinux 9 cloud image:aarch64:https://repo.almalinux.org/almalinux/9/cloud/images/AlmaLinux-9-cloud-arm64.qcow2|almalinux")
# Autostart
#AUTOSTART=false

154
README.md

@ -10,8 +10,7 @@ Tested on the latest Fedora.
You need to have the KVM hypervisor installed, along with a few other packages (naming of packages can differ on other distributions):
- genisoimage or mkisofs
- virt-install
- virt-install >= 3.0.0
- libguestfs-tools-c
- qemu-img
- libvirt-client
@ -22,13 +21,13 @@ To install the dependencies, run:
- Fedora example:
```
sudo dnf -y install genisoimage virt-install libguestfs-tools-c qemu-img libvirt-client wget libosinfo
sudo dnf -y install virt-install libguestfs-tools-c qemu-img libvirt-client wget libosinfo
```
- Ubuntu example:
```
sudo apt install -y genisoimage virtinst libguestfs-tools qemu-utils libvirt-clients wget libosinfo-bin
sudo apt install -y virtinst libguestfs-tools qemu-utils libvirt-clients wget libosinfo-bin
```
If you want to resolve guests by their hostnames, install the `libvirt-nss` package:
@ -41,7 +40,7 @@ sudo dnf -y install libvirt-nss
- Ubuntu example:
```
```bash
sudo apt install -y libnss-libvirt
```
@ -51,142 +50,38 @@ information.
### Usage
```
$ kvm-install-vm help
NAME
kvm-install-vm - Install virtual guests using cloud-init on a local KVM
hypervisor.
SYNOPSIS
kvm-install-vm COMMAND [OPTIONS]
DESCRIPTION
A bash wrapper around virt-install to build virtual machines on a local KVM
hypervisor. You can run it as a normal user which will use qemu:///session
to connect locally to your KVM domains.
COMMANDS
help - show this help or help for a subcommand
create - create a new guest domain
list - list all domains, running and stopped
remove - delete a guest domain
```bash
./kvm-install-vm help
```
#### Creating Guest VMs
```
$ kvm-install-vm help create
NAME
kvm-install-vm create [COMMANDS] [OPTIONS] VMNAME
DESCRIPTION
Create a new guest domain.
COMMANDS
help - show this help
OPTIONS
-a Autostart (default: false)
-b Bridge (default: virbr0)
-c Number of vCPUs (default: 1)
-d Disk Size (GB) (default: 10)
-D DNS Domain (default: example.local)
-f CPU Model / Feature (default: host)
-g Graphics type (default: spice)
-h Display help
-i Custom QCOW2 Image
-k SSH Public Key (default: $HOME/.ssh/id_rsa.pub)
-l Location of Images (default: $HOME/virt/images)
-L Location of VMs (default: $HOME/virt/vms)
-m Memory Size (MB) (default: 1024)
-M Mac address (default: auto-assigned)
-p Console port (default: auto)
-s Custom shell script
-t Linux Distribution (default: centos8)
-T Timezone (default: US/Eastern)
-u Custom user (default: $USER)
-y Assume yes to prompts (default: false)
-n Assume no to prompts (default: false)
-v Be verbose
DISTRIBUTIONS
NAME DESCRIPTION LOGIN
amazon2 Amazon Linux 2 ec2-user
centos8 CentOS 8 centos
centos7 CentOS 7 centos
centos7-atomic CentOS 7 Atomic Host centos
centos6 CentOS 6 centos
debian9 Debian 9 (Stretch) debian
debian10 Debian 10 (Buster) debian
fedora29 Fedora 29 fedora
fedora29-atomic Fedora 29 Atomic Host fedora
fedora30 Fedora 30 fedora
fedora31 Fedora 31 fedora
fedora32 Fedora 32 fedora
opensuse15 OpenSUSE Leap 15.2 opensuse
ubuntu1604 Ubuntu 16.04 LTS (Xenial Xerus) ubuntu
ubuntu1804 Ubuntu 18.04 LTS (Bionic Beaver) ubuntu
ubuntu2004 Ubuntu 20.04 LTS (Focal Fossa) ubuntu
EXAMPLES
kvm-install-vm create foo
Create VM with the default parameters: CentOS 8, 1 vCPU, 1GB RAM, 10GB
disk capacity.
kvm-install-vm create -c 2 -m 2048 -d 20 foo
Create VM with custom parameters: 2 vCPUs, 2GB RAM, and 20GB disk
capacity.
kvm-install-vm create -t debian9 foo
Create a Debian 9 VM with the default parameters.
kvm-install-vm create -T UTC foo
Create a default VM with UTC timezone.
```
```bash
# Create VM with the default parameters: Rocky Linux 9, 1 vCPU, 1.5GB RAM, 10GB disk capacity, x86_64 arch
kvm-install-vm create myvm
#### Deleting a Guest Domain
# Create VM with custom parameters: 2 vCPUs, 2GB RAM, and 20GB disk capacity.
kvm-install-vm create -c 2 -m 2048 -d 20 myvm
```
$ kvm-install-vm help remove
NAME
kvm-install-vm remove [COMMANDS] VMNAME
# Create a Debian 12 VM with the default parameters.
kvm-install-vm create -t debian12 myvm
DESCRIPTION
Destroys (stops) and undefines a guest domain. This also remove the
associated storage pool.
# Create a default VM with UTC timezone.
kvm-install-vm create -T UTC myvm
```
COMMANDS
help - show this help
#### Deleting a Guest Domain
EXAMPLE
kvm-install-vm remove foo
Remove (destroy and undefine) a guest domain. WARNING: This will
delete the guest domain and any changes made inside it!
```bash
# Remove (destroy and undefine) a guest domain. WARNING: This will delete the guest domain and any changes made inside it!
kvm-install-vm remove myvm
```
#### Attaching a new disk
```
$ kvm-install-vm help attach-disk
NAME
kvm-install-vm attach-disk [OPTIONS] [COMMANDS] VMNAME
DESCRIPTION
Attaches a new disk to a guest domain.
COMMANDS
help - show this help
OPTIONS
-d SIZE Disk size (GB)
-f FORMAT Disk image format (default: qcow2)
-s IMAGE Source of disk device
-t TARGET Disk device target
EXAMPLE
kvm-install-vm attach-disk -d 10 -s example-5g.qcow2 -t vdb foo
Attach a 10GB disk device named example-5g.qcow2 to the foo guest
domain.
```bash
# Attach a 10GB disk device named example-5g.qcow2 to the myvm guest domain.
kvm-install-vm attach-disk -d 10 -s example-5g.qcow2 -t vdb myvm
```
### Setting Custom Defaults
@ -234,8 +129,7 @@ execute the tests, run `./test.sh` in the root directory of the project.
### Use Cases
If you don't need to use Docker or Vagrant, don't want to make changes to a
production machine, or just want to spin up one or more VMs locally to test
things like:
production machine, want to tinker with the kernel or systemd, or just want to spin up one or more VMs locally to test things like:
- high availability
- clustering

471
kvm-install-vm

@ -1,5 +1,5 @@
#!/bin/bash
set -e
#!/usr/bin/env bash
set -euo pipefail
# Set program name variable - basename without subshell
prog=${0##*/}
@ -36,7 +36,7 @@ function usage_subcommand ()
case "$1" in
create)
printf "NAME\n"
printf " $prog create [COMMANDS] [OPTIONS] VMNAME\n"
printf " %s create [COMMANDS] [OPTIONS] VMNAME\n" "$prog"
printf "\n"
printf "DESCRIPTION\n"
printf " Create a new guest domain.\n"
@ -45,72 +45,52 @@ function usage_subcommand ()
printf " help - show this help\n"
printf "\n"
printf "OPTIONS\n"
printf " -a Autostart (default: false)\n"
printf " -b Bridge (default: virbr0)\n"
printf " -c Number of vCPUs (default: 1)\n"
printf " -d Disk Size (GB) (default: 10)\n"
printf " -D DNS Domain (default: example.local)\n"
printf " -f CPU Model / Feature (default: host)\n"
printf " -g Graphics type (default: spice)\n"
printf " -a Autostart (default: false)\n"
printf " -A Architecture (x86_64|aarch64) (default: x86_64)\n"
printf " -b Bridge (default: virbr0)\n"
printf " -c Number of vCPUs (default: 1)\n"
printf " -d Disk Size (GB) (default: 10)\n"
printf " -D DNS Domain (default: example.local)\n"
printf " -f CPU Model / Feature (default: host)\n"
printf " -g Graphics type (default: spice)\n"
printf " -h Display help\n"
printf " -i Custom QCOW2 Image\n"
printf " -k SSH Public Key (default: $HOME/.ssh/id_rsa.pub)\n"
printf " -l Location of Images (default: $HOME/virt/images)\n"
printf " -L Location of VMs (default: $HOME/virt/vms)\n"
printf " -m Memory Size (MB) (default: 1024)\n"
printf " -M Mac address (default: auto-assigned)\n"
printf " -p Console port (default: auto)\n"
printf " -k SSH Public Key (default: %s/.ssh/id_rsa.pub)\n" "$HOME"
printf " -l Location of Images (default: %s/virt/images)\n" "$HOME"
printf " -L Location of VMs (default: %s/virt/vms)\n" "$HOME"
printf " -m Memory Size (MB) (default: 1024)\n"
printf " -M Mac address (default: auto-assigned)\n"
printf " -p Console port (default: auto)\n"
printf " -s Custom shell script\n"
printf " -t Linux Distribution (default: centos8)\n"
printf " -T Timezone (default: US/Eastern)\n"
printf " -u Custom user (default: $USER)\n"
printf " -y Assume yes to prompts (default: false)\n"
printf " -n Assume no to prompts (default: false)\n"
printf " -t Linux Distribution (default: centos8)\n"
printf " -T Timezone (default: US/Eastern)\n"
printf " -u Custom user (default: %s)\n" "$USER"
printf " -y Assume yes to prompts (default: false)\n"
printf " -n Assume no to prompts (default: false)\n"
printf " -v Be verbose\n"
printf "\n"
printf "DISTRIBUTIONS\n"
printf " NAME DESCRIPTION LOGIN\n"
printf " amazon2 Amazon Linux 2 ec2-user\n"
printf " centos8 CentOS 8 centos\n"
printf " centos7 CentOS 7 centos\n"
printf " centos7-atomic CentOS 7 Atomic Host centos\n"
printf " centos6 CentOS 6 centos\n"
printf " debian9 Debian 9 (Stretch) debian\n"
printf " debian10 Debian 10 (Buster) debian\n"
printf " fedora29 Fedora 29 fedora\n"
printf " fedora29-atomic Fedora 29 Atomic Host fedora\n"
printf " fedora30 Fedora 30 fedora\n"
printf " fedora31 Fedora 31 fedora\n"
printf " fedora32 Fedora 32 fedora\n"
printf " fedora33 Fedora 33 fedora\n"
printf " fedora34 Fedora 34 fedora\n"
printf " opensuse15 OpenSUSE Leap 15.2 opensuse\n"
printf " ubuntu1604 Ubuntu 16.04 LTS (Xenial Xerus) ubuntu\n"
printf " ubuntu1804 Ubuntu 18.04 LTS (Bionic Beaver) ubuntu\n"
printf " ubuntu2004 Ubuntu 20.04 LTS (Focal Fossa) ubuntu\n"
printf " ubuntu2204 Ubuntu 22.04 LTS (Jammy Jellyfish) ubuntu\n"
printf " ubuntu2404 Ubuntu 24.04 LTS (Noble Numbat) ubuntu\n"
printf " rocky8.5 Rocky Linux rocky\n"
printf "\n"
list_available_vms
printf "\n"
printf "EXAMPLES\n"
printf " $prog create foo\n"
printf " %s create foo\n" "$prog"
printf " Create VM with the default parameters: CentOS 8, 1 vCPU, 1GB RAM, 10GB\n"
printf " disk capacity.\n"
printf "\n"
printf " $prog create -c 2 -m 2048 -d 20 foo\n"
printf " %s create -c 2 -m 2048 -d 20 foo\n" "$prog"
printf " Create VM with custom parameters: 2 vCPUs, 2GB RAM, and 20GB disk\n"
printf " capacity.\n"
printf "\n"
printf " $prog create -t debian9 foo\n"
printf " %s create -t debian9 foo\n" "$prog"
printf " Create a Debian 9 VM with the default parameters.\n"
printf "\n"
printf " $prog create -T UTC foo\n"
printf " %s create -T UTC foo\n" "$prog"
printf " Create a default VM with UTC timezone.\n"
printf "\n"
;;
remove)
printf "NAME\n"
printf " $prog remove [COMMANDS] VMNAME\n"
printf " %s remove [COMMANDS] VMNAME\n" "prog"
printf "\n"
printf "DESCRIPTION\n"
printf " Destroys (stops) and undefines a guest domain. This also remove the\n"
@ -120,18 +100,18 @@ function usage_subcommand ()
printf " help - show this help\n"
printf "\n"
printf "OPTIONS\n"
printf " -l Location of Images (default: $HOME/virt/images)\n"
printf " -L Location of VMs (default: $HOME/virt/vms)\n"
printf " -l Location of Images (default: %s/virt/images)\n" "$HOME"
printf " -L Location of VMs (default: %s/virt/vms)\n" "$HOME"
printf " -v Be verbose\n"
printf "\n"
printf "EXAMPLE\n"
printf " $prog remove foo\n"
printf " %s remove foo\n" "$prog"
printf " Remove (destroy and undefine) a guest domain. WARNING: This will\n"
printf " delete the guest domain and any changes made inside it!\n"
;;
attach-disk)
printf "NAME\n"
printf " $prog attach-disk [OPTIONS] [COMMANDS] VMNAME\n"
printf " %s attach-disk [OPTIONS] [COMMANDS] VMNAME\n" "$prog"
printf "\n"
printf "DESCRIPTION\n"
printf " Attaches a new disk to a guest domain.\n"
@ -146,19 +126,19 @@ function usage_subcommand ()
printf " -t TARGET Disk device target\n"
printf "\n"
printf "EXAMPLE\n"
printf " $prog attach-disk -d 10 -s example-5g.qcow2 -t vdb foo\n"
printf " %s attach-disk -d 10 -s example-5g.qcow2 -t vdb foo\n" "$prog"
printf " Attach a 10GB disk device named example-5g.qcow2 to the foo guest\n"
printf " domain.\n"
;;
list)
printf "NAME\n"
printf " $prog list\n"
printf " %s list\n" "$prog"
printf "\n"
printf "DESCRIPTION\n"
printf " Lists all running and stopped guest domains.\n"
;;
*)
printf "'$subcommand' is not a valid subcommand.\n"
printf "'%s' is not a valid subcommand.\n" "$subcommand"
exit 1
;;
esac
@ -293,190 +273,25 @@ function fetch_images ()
# Create image directory if it doesn't already exist
mkdir -p ${IMAGEDIR}
# Set variables based on $DISTRO
# Use the command "osinfo-query os" to get the list of the accepted OS variants.
case "$DISTRO" in
amazon2)
QCOW=amzn2-kvm-2.0.20190313-x86_64.xfs.gpt.qcow2
OS_TYPE="linux"
OS_VARIANT="auto"
IMAGE_URL=https://cdn.amazonlinux.com/os-images/2.0.20190313/kvm
DISK_FORMAT=qcow2
LOGIN_USER=ec2-user
;;
centos8)
QCOW=CentOS-8-GenericCloud-8.1.1911-20200113.3.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="centos8"
IMAGE_URL=https://cloud.centos.org/centos/8/x86_64/images
DISK_FORMAT=qcow2
LOGIN_USER=centos
;;
centos7)
QCOW=CentOS-7-x86_64-GenericCloud.qcow2
OS_TYPE="linux"
OS_VARIANT="centos7.0"
IMAGE_URL=https://cloud.centos.org/centos/7/images
DISK_FORMAT=qcow2
LOGIN_USER=centos
;;
centos7-atomic)
QCOW=CentOS-Atomic-Host-7-GenericCloud.qcow2
OS_TYPE="linux"
OS_VARIANT="centos7.0"
IMAGE_URL=http://cloud.centos.org/centos/7/atomic/images
DISK_FORMAT=qcow2
LOGIN_USER=centos
;;
centos6)
QCOW=CentOS-6-x86_64-GenericCloud.qcow2
OS_TYPE="linux"
OS_VARIANT="centos6.9"
IMAGE_URL=https://cloud.centos.org/centos/6/images
DISK_FORMAT=qcow2
LOGIN_USER=centos
;;
debian8)
# FIXME: Not yet working.
QCOW=debian-8-openstack-amd64.qcow2
OS_TYPE="linux"
OS_VARIANT="debian8"
IMAGE_URL=https://cdimage.debian.org/cdimage/openstack/current-8
DISK_FORMAT=qcow2
LOGIN_USER=debian
;;
debian9)
QCOW=debian-9-openstack-amd64.qcow2
OS_TYPE="linux"
OS_VARIANT="debian9"
IMAGE_URL=https://cdimage.debian.org/cdimage/openstack/current-9
DISK_FORMAT=qcow2
LOGIN_USER=debian
;;
debian10)
QCOW=debian-10-openstack-amd64.qcow2
OS_TYPE="linux"
OS_VARIANT="debian10"
IMAGE_URL=https://cdimage.debian.org/cdimage/openstack/current-10
DISK_FORMAT=qcow2
LOGIN_USER=debian
;;
fedora29)
QCOW=Fedora-Cloud-Base-29-1.2.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="fedora29"
IMAGE_URL=https://download.fedoraproject.org/pub/fedora/linux/releases/29/Cloud/x86_64/images
DISK_FORMAT=qcow2
LOGIN_USER=fedora
;;
fedora29-atomic)
QCOW=Fedora-AtomicHost-29-20190611.0.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="fedora29"
IMAGE_URL=https://download.fedoraproject.org/pub/alt/atomic/stable/Fedora-29-updates-20190611.0/AtomicHost/x86_64/images/
DISK_FORMAT=qcow2
LOGIN_USER=fedora
;;
fedora30)
QCOW=Fedora-Cloud-Base-30-1.2.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="fedora29"
IMAGE_URL=https://download.fedoraproject.org/pub/fedora/linux/releases/30/Cloud/x86_64/images
DISK_FORMAT=qcow2
LOGIN_USER=fedora
;;
fedora31)
QCOW=Fedora-Cloud-Base-31-1.9.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="fedora31"
IMAGE_URL=https://download.fedoraproject.org/pub/fedora/linux/releases/31/Cloud/x86_64/images
DISK_FORMAT=qcow2
LOGIN_USER=fedora
;;
fedora32)
QCOW=Fedora-Cloud-Base-32-1.6.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="fedora32"
IMAGE_URL=https://download.fedoraproject.org/pub/fedora/linux/releases/32/Cloud/x86_64/images
DISK_FORMAT=qcow2
LOGIN_USER=fedora
;;
fedora33)
QCOW=Fedora-Cloud-Base-33-1.2.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="fedora33"
IMAGE_URL=https://download.fedoraproject.org/pub/fedora/linux/releases/33/Cloud/x86_64/images
DISK_FORMAT=qcow2
LOGIN_USER=fedora
;;
fedora34)
QCOW=Fedora-Cloud-Base-34-1.2.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="fedora34"
IMAGE_URL=https://download.fedoraproject.org/pub/fedora/linux/releases/34/Cloud/x86_64/images
DISK_FORMAT=qcow2
LOGIN_USER=fedora
;;
ubuntu1604)
QCOW=ubuntu-16.04-server-cloudimg-amd64-disk1.img
OS_TYPE="linux"
OS_VARIANT="ubuntu16.04"
IMAGE_URL=https://cloud-images.ubuntu.com/releases/16.04/release
DISK_FORMAT=qcow2
LOGIN_USER=ubuntu
;;
ubuntu1804)
QCOW=ubuntu-18.04-server-cloudimg-amd64.img
OS_TYPE="linux"
OS_VARIANT="ubuntu18.04"
IMAGE_URL=https://cloud-images.ubuntu.com/releases/18.04/release
DISK_FORMAT=qcow2
LOGIN_USER=ubuntu
;;
ubuntu2004)
QCOW=ubuntu-20.04-server-cloudimg-amd64.img
OS_TYPE="linux"
OS_VARIANT="ubuntu20.04"
IMAGE_URL=https://cloud-images.ubuntu.com/releases/20.04/release
DISK_FORMAT=qcow2
LOGIN_USER=ubuntu
;;
ubuntu2204)
QCOW=ubuntu-22.04-server-cloudimg-amd64.img
OS_TYPE="linux"
OS_VARIANT="ubuntu22.04"
IMAGE_URL=https://cloud-images.ubuntu.com/releases/22.04/release
DISK_FORMAT=qcow2
LOGIN_USER=ubuntu
;;
ubuntu2404)
QCOW=ubuntu-24.04-server-cloudimg-amd64.img
OS_TYPE="linux"
OS_VARIANT="ubuntu24.04"
IMAGE_URL=https://cloud-images.ubuntu.com/releases/24.04/release
DISK_FORMAT=qcow2
LOGIN_USER=ubuntu
;;
opensuse15)
QCOW=openSUSE-Leap-15.2-OpenStack.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="opensuse15.0"
IMAGE_URL=https://download.opensuse.org/repositories/Cloud:/Images:/Leap_15.2/images
DISK_FORMAT=qcow2
LOGIN_USER=opensuse
;;
rocky85)
QCOW=Rocky-8-GenericCloud-8.5-20211114.2.x86_64.qcow2
OS_TYPE="linux"
OS_VARIANT="rocky8.5"
IMAGE_URL=https://dl.rockylinux.org/pub/rocky/8.5/images
DISK_FORMAT=qcow2
LOGIN_USER=rocky
;;
*)
die "${DISTRO} not a supported OS. Run 'kvm-install-vm create help'."
;;
esac
local found="false"
local vm_url=""
for vm in "${BUILTIN_VMS[@]}"; do
IFS=\| read -r vm_distro vm_desc vm_arch vm_url vm_login_user <<< "$vm"
if [[ "$vm_distro" == "$DISTRO" && "$vm_arch" == "$ARCH" ]]; then
QCOW="${vm_url##*/}" # Grab just the file from the URL to pass into virt-install
OS_INFO="$vm_distro" # Distro name should come from osinfo
IMAGE_URL="${vm_url%/*}" # Grab everything but the filename and the slash
DISK_FORMAT="qcow2"
LOGIN_USER="$vm_login_user"
found="true"
break
fi
done
if [ "$found" = "false" ]; then
die "No matching image found for ${DISTRO} (${ARCH})"
fi
IMAGE=${IMAGEDIR}/${QCOW}
@ -529,9 +344,9 @@ function check_ssh_key ()
function check_os_variant ()
{
if [[ ${OS_VARIANT} != auto ]]; then
osinfo-query os short-id=${OS_VARIANT} >/dev/null \
|| die "Unknown OS variant '${OS_VARIANT}'. Please update your osinfo-db. "\
if [[ ${OS_INFO} != auto ]]; then
osinfo-query os short-id=${OS_INFO} >/dev/null \
|| die "Unknown OS variant '${OS_INFO}'. Please update your osinfo-db. "\
"See https://libosinfo.org/download for more information."
fi
}
@ -553,7 +368,7 @@ function storpool_exists ()
function set_sudo_group ()
{
case "${DISTRO}" in
centos*|fedora*|rocky*|*-atomic|amazon*|opensuse* )
almalinux*|centos*|fedora*|rocky*|*-atomic|amazon*|opensuse* )
SUDOGROUP="wheel"
;;
ubuntu*|debian* )
@ -565,25 +380,9 @@ function set_sudo_group ()
esac
}
function set_cloud_init_remove ()
{
case "${DISTRO}" in
centos6 )
CLOUDINITDISABLE="chkconfig cloud-init off"
;;
centos8|centos7|amazon*|fedora*|rocky*|ubuntu*|debian*|opensuse* )
CLOUDINITDISABLE="systemctl disable cloud-init.service"
;;
*-atomic)
CLOUDINITDISABLE="/usr/bin/true"
;;
esac
}
function set_network_restart_cmd ()
{
case "${DISTRO}" in
centos6 ) NETRESTART="service network stop && service network start" ;;
ubuntu*|debian*) NETRESTART="systemctl stop networking && systemctl start networking" ;;
*) NETRESTART="systemctl stop network && systemctl start network" ;;
esac
@ -656,7 +455,6 @@ timezone: ${TIMEZONE}
# Remove cloud-init when finished with it
runcmd:
- ${NETRESTART}
- ${CLOUDINITDISABLE}
_EOF_
if [ ! -z "${SCRIPTNAME+x}" ]
@ -704,21 +502,6 @@ _EOF_
esac
fi
# Create CD-ROM ISO with cloud-init config
outputn "Generating ISO for cloud-init"
if command -v genisoimage &>/dev/null
then
genisoimage -output $CI_ISO \
-volid cidata \
-joliet -r $USER_DATA $META_DATA &>> ${VMNAME}.log \
&& ok \
|| die "Could not generate ISO."
else
mkisofs -o $CI_ISO -V cidata -J -r $USER_DATA $META_DATA &>> ${VMNAME}.log \
&& ok \
|| die "Could not generate ISO."
fi
# Create new storage pool for new VM
run "Creating storage pool" \
virsh pool-create-as \
@ -741,11 +524,6 @@ _EOF_
$(param bus ${DISK_BUS}) \
${DISK_EXTRA})"
# Assemble CI ISO disk parameters.
CI_ISO_PARAMS="$(join ',' \
${CI_ISO} \
${CI_ISO_EXTRA})"
# Omit the --graphics option to auto-detect.
if [ "${GRAPHICS}" = 'auto' ]
then
@ -761,8 +539,8 @@ _EOF_
# Assemble virt-install options.
NETWORK_OPTION="$(param --network ${NETWORK_PARAMS})"
DISK_OPTION="$(param --disk ${DISK_PARAMS})"
CI_ISO_OPTION="$(param --disk ${CI_ISO_PARAMS})"
GRAPHICS_OPTION="$(param --graphics ${GRAPHICS_PARAMS})"
CLOUD_INIT_OPTION="$(param --cloud-init user-data=${USER_DATA},meta-data=${META_DATA},disable=on)"
# Call virt-install to import the cloud image and create a new VM
run "Installing the domain" \
@ -772,10 +550,9 @@ _EOF_
--vcpus=${CPUS} \
--cpu=${FEATURE} \
${DISK_OPTION} \
${CI_ISO_OPTION} \
${CLOUD_INIT_OPTION} \
${NETWORK_OPTION} \
--os-type=${OS_TYPE} \
--os-variant=${OS_VARIANT} \
--osinfo=${OS_INFO} \
--noautoconsole \
${GRAPHICS_OPTION} \
${VIRT_INSTALL_EXTRA} \
@ -793,35 +570,39 @@ _EOF_
|| die "Could not enable autostart."
fi
# Eject cdrom
virsh detach-disk --domain ${VMNAME} ${VMDIR}/${VMNAME}/${CI_ISO} --config &>> ${VMNAME}.log
# Remove the unnecessary cloud init files
outputn "Cleaning up cloud-init files"
rm -f $USER_DATA $META_DATA $CI_ISO && ok
rm -f $USER_DATA $META_DATA && ok
MAC=$(virsh dumpxml ${VMNAME} | awk -F\' '/mac address/ {print $2}')
output "MAC address: ${MAC}"
if [ -f "/var/lib/libvirt/dnsmasq/${BRIDGE}.status" ]
then
outputn "Waiting for domain to get an IP address"
while true
do
IP=$(grep -B1 $MAC /var/lib/libvirt/dnsmasq/$BRIDGE.status | head \
-n 1 | awk '{print $2}' | sed -e s/\"//g -e s/,//)
if [ "$IP" = "" ]
then
sleep 1
else
status_file="/var/lib/libvirt/dnsmasq/${BRIDGE}.status"
IP=""
timeout=60 # seconds
if [[ -f "$status_file" ]]; then
outputn "Waiting for domain to get an IP address "
for (( i=0; i<timeout; i++ )); do
IP=$(
{ grep -B1 -m1 "\"mac-address\": \"$MAC\"" "$status_file" || true; } |
awk -F'"' '/ip-address/ {print $4; exit}'
)
if [[ -n "$IP" ]]; then
ok
break
fi
sleep 1
done
printf "\n"
[[ -n "$IP" ]] || die "Timed out waiting for DHCP lease"
printf '\n'
check_delete_known_host
else
outputn "Bridge looks like a layer 2 bridge, get the domain's IP address from your DHCP server"
outputn "Bridge looks like a layer‑2 bridge; get the domain’s IP from your DHCP server"
IP="<IP address>"
fi
@ -875,9 +656,10 @@ function set_defaults ()
{
# Defaults are set here. Override using command line arguments.
AUTOSTART=false # Automatically start VM at boot time
ARCH=x86_64 # Architecture (86_64|aarch64)
CPUS=1 # Number of virtual CPUs
FEATURE=host # Use host cpu features to the guest
MEMORY=1024 # Amount of RAM in MB
FEATURE=host-model # Use host cpu features to the guest
MEMORY=1536 # Amount of RAM in MB
DISK_SIZE="" # Disk Size in GB
DNSDOMAIN=example.local # DNS domain
GRAPHICS=spice # Graphics type or "auto"
@ -886,7 +668,7 @@ function set_defaults ()
VMDIR=${HOME}/virt/vms # Directory to store virtual machines
BRIDGE=virbr0 # Hypervisor bridge
PUBKEY="" # SSH public key
DISTRO=centos8 # Distribution
DISTRO=rocky9 # Distribution
MACADDRESS="" # MAC Address
PORT=-1 # Console port
TIMEZONE=US/Eastern # Timezone
@ -907,15 +689,70 @@ function set_defaults ()
GRAPHICS_LISTEN=localhost
GRAPHICS_EXTRA=""
VIRT_INSTALL_EXTRA=""
# Format: "name|description|architecture|image download url|login user"
# *Note*: The name should match what is in the osinfo list
DEFAULT_BUILTIN_VMS=(
"ubuntu24.04|Ubuntu 24.04 LTS (Noble Numbat)|x86_64|https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img|ubuntu"
"ubuntu24.04|Ubuntu 24.04 LTS (Noble Numbat)|aarch64|https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-arm64.img|ubuntu"
"ubuntu22.04|Ubuntu 22.04 LTS (Noble Numbat)|x86_64|https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img|ubuntu"
"ubuntu22.04|Ubuntu 22.04 LTS (Noble Numbat)|aarch64|https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-arm64.img|ubuntu"
"debian12|Debian 12 Stable (Bookworm)|x86_64|https://cdimage.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2|debian"
"debian12|Debian 12 Stable (Bookworm)|aarch64|https://cdimage.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-arm64.qcow2|debian"
"rocky8|Rocky Linux 8 (Green Obsidian)|x86_64|https://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud.latest.x86_64.qcow2|rocky"
"rocky8|Rocky Linux 8 (Green Obsidian)|aarch64|https://dl.rockylinux.org/pub/rocky/8/images/aarch64/Rocky-8-GenericCloud.latest.aarch64.qcow2|rocky"
"rocky9|Rocky Linux 9 (Blue Onyx)|x86_64|https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2|rocky"
"rocky9|Rocky Linux 9 (Blue Onyx)|aarch64|https://dl.rockylinux.org/pub/rocky/9/images/aarch64/Rocky-9-GenericCloud.latest.aarch64.qcow2|rocky"
)
BUILTIN_VMS=("${DEFAULT_BUILTIN_VMS[@]}")
}
function set_custom_defaults ()
{
# Source custom defaults, if set
if [ -f ~/.kivrc ];
then
source ${HOME}/.kivrc
# Source custom defaults: first local .kivrc, then fallback to ~/.kivrc
if [ -f "./.kivrc" ]; then
source "./.kivrc"
elif [ -f "${HOME}/.kivrc" ]; then
source "${HOME}/.kivrc"
fi
declare -gA BUILTIN_VM_DESCRIPTIONS=()
declare -gA BUILTIN_VM_SOURCES=()
declare -gA BUILTIN_VM_ARCHS=()
for entry in "${BUILTIN_VMS[@]}"; do
IFS=":" read -r name description arch url <<< "$entry"
key="${name}_${arch}"
BUILTIN_VM_DESCRIPTIONS["$key"]=$description
BUILTIN_VM_ARCHS["$key"]=$arch
BUILTIN_VM_SOURCES["$key"]=$url
done
}
function list_available_vms() {
for key in "${!BUILTIN_VM_DESCRIPTIONS[@]}"; do
local arch="${BUILTIN_VM_ARCHS[$key]}"
local description="${BUILTIN_VM_DESCRIPTIONS[$key]}"
# Extract the base name (before the architecture part)
# Since arch can be x86_64 or aarch64, we need to be more specific
local name
if [[ "$key" == *_x86_64 ]]; then
name="${key%_x86_64}"
elif [[ "$key" == *_aarch64 ]]; then
name="${key%_aarch64}"
else
name="$key"
fi
if [[ ${#arch} -eq 6 ]]; then
printf " %-13s (%s) - %s\n" "$name" "$arch" "$description"
else
printf " %-12s (%s) - %s\n" "$name" "$arch" "$description"
fi
done | sort
}
function create ()
@ -924,7 +761,8 @@ function create ()
while getopts ":b:c:d:D:f:g:i:k:l:L:m:M:p:s:t:T:u:ahynv" opt
do
case "$opt" in
a ) AUTOSTART=${OPTARG} ;;
a ) AUTOSTART="${OPTARG}" ;;
A ) ARCH="$(OPTARG)" ;;
b ) BRIDGE="${OPTARG}" ;;
c ) CPUS="${OPTARG}" ;;
d ) DISK_SIZE="${OPTARG}" ;;
@ -970,7 +808,7 @@ function create ()
if [ "$#" != 1 ]
then
printf "Please specify a single host to create.\n"
printf "Run 'kvm-install-vm help create' for usage.\n"
printf "Run 'kvm-install-vm create help' for usage.\n"
exit 1
else
VMNAME=$1
@ -979,7 +817,6 @@ function create ()
# Set cloud-init variables after VMNAME is assigned
USER_DATA=user-data
META_DATA=meta-data
CI_ISO=${VMNAME}-cidata.iso
# Check for ssh key
check_ssh_key
@ -987,7 +824,7 @@ function create ()
if [ ! -z "${IMAGE+x}" ]
then
output "Using custom QCOW2 image: ${IMAGE}."
OS_VARIANT="auto"
OS_INFO="auto"
LOGIN_USER="<use the default account in your custom image>"
else
fetch_images
@ -1021,9 +858,6 @@ function create ()
# Set network restart command
set_network_restart_cmd
# Set cloud init remove command
set_cloud_init_remove
# Set package manager
set_sudo_group
@ -1115,13 +949,14 @@ case "${subcommand}" in
exit 0
;;
create|remove|attach-disk|remove-disk)
set_defaults
set_custom_defaults
if [[ "${1:-none}" == "none" ]]; then
usage_subcommand "${subcommand}"
elif [[ "$1" =~ ^help$ ]]; then
usage_subcommand "${subcommand}"
else
set_defaults
set_custom_defaults
"${subcommand}" "$@"
exit $?
fi

Loading…
Cancel
Save