From 92dc351221e22bcc4e53600152569cc1bad8af46 Mon Sep 17 00:00:00 2001 From: Andrei Neshcheret Date: Mon, 31 Jul 2023 12:06:54 +0500 Subject: [PATCH 1/3] Compatibility with older version of virt-install * Ubuntu 20.04.6 LTS - compatibility * Using `cloud-localds` - as described in cloud-init documentation * `virsh` - auto remove all associated storage volumes --- README.md | 30 +++++++++++++++++++++++------- create-vm | 20 ++++++++++---------- delete-vm | 5 ++--- get-vm-ip | 3 +-- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 0528bcf..94866fa 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ to install the necessary virtualization packages: - python3-libvirt - virt-manager - virtinst + - cloud-image-utils ``` If you're not using Ansible just `apt-get install` the above packages. @@ -129,12 +130,12 @@ If you're not using Ansible just `apt-get install` the above packages. ## Permissions The `libvirtd` daemon runs under the `libvirt-qemu` user service account. The `libvirt-qemu` user -must be able to read the files in `${VM_IMAGE_DIR}`. If your ${HOME} directory has permissions set to +must be able to read the files in `${VM_IMAGE_DIR}`. If your `${HOME}` directory has permissions set to `0x750` then `libvirt-qemu` won't be able to read the `${VM_IMAGE_DIR}` directory. You could open up your home directory, e.g.: -``` +```sh chmod 755 ${HOME} ``` @@ -142,7 +143,7 @@ chmod 755 ${HOME} better approach is just to add `libvirt-qemu` to your home directory's group. For instance, on my host my home directory is `/home/earl` owned by user `earl` and group `earl`, permissions `0x750`: -``` +```sh $ chmod 750 /home/earl $ ls -al /home total 24 @@ -153,7 +154,7 @@ drwxr-x--- 142 earl earl 4096 Feb 16 09:27 earl To make sure that _only_ the `libvirt-qemu` user can read my files I can add the user to the `earl` group: -``` +```sh $ sudo usermod --append --groups earl libvirt-qemu $ sudo systemctl restart libvirtd $ grep libvirt-qemu /etc/group @@ -165,7 +166,7 @@ That shows that the group `earl`, group ID 1000, has a member `libvirt-qemu`. Si Note: The `libvirtd` daemon will chown some of the files in the directory, including the files in the `~/vms/images` directory, to be owned by `libvirt-qemu` group `kvm`. In order to delete these files without sudo, add yourself to the `kvm` group, e.g.: -``` +```sh $ sudo usermod --append --groups kvm earl ``` @@ -186,6 +187,9 @@ OPTIONS: -s Amount of storage to allocate in GB (defaults to 80) -b Bridge interface to use (defaults to virbr0) -m MAC address to use (default is to use a randomly-generated MAC) + -t The hypervisor to install on. Example choices are kvm, qemu, or xen. + Example choices are kvm, qemu, or xen. (defaults to kvm) + Available options are listed via 'virsh capabilities' in the tags. -v Verbose ``` @@ -197,14 +201,14 @@ This creates an Ubuntu 22.04 "Jammy Jellyfish" VM with a 40G hard drive. First download a copy of the Ubuntu 22.04 "Jammy Jellyfish" cloud image: -``` +```sh mkdir -p ~/vms/base cd ~/vms/base wget http://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img ``` Then create the VM: -``` +```sh create-vm -n node1 \ -i ~/vms/base/jammy-server-cloudimg-amd64.img \ -k ~/.ssh/id_rsa_ansible.pub \ @@ -321,3 +325,15 @@ which is why I wrote the `get-vm-ip` script. `virsh net-dhcp-leases $network` - Shows current DHCP leases when virsh is acting as the DHCP server. Leases may be shown for machines that no longer exist. + +### Other +In the case of using the network in the `bridge` mode, the arp table will not possibly contain any IP addresses, use this command instead. +```sh +sudo arp-scan --interface br0 --localnet | grep QEMU +``` +Sample output +``` +192.168.104.103 52:54:00:1d:4a:0c QEMU +192.168.104.118 52:54:00:35:2d:5f QEMU +``` + diff --git a/create-vm b/create-vm index df77c47..83adf68 100755 --- a/create-vm +++ b/create-vm @@ -27,6 +27,7 @@ STORAGE=80 BRIDGE=virbr0 MAC= VERBOSE= +VIRT_TYPE=$(command -v kvm-ok > /dev/null && echo kvm || echo qemu) usage() { @@ -45,6 +46,9 @@ OPTIONS: -s Amount of storage to allocate in GB (defaults to ${STORAGE}) -b Bridge interface to use (defaults to ${BRIDGE}) -m MAC address to use (default is to use a randomly-generated MAC) + -t The hypervisor to install on. Example choices are kvm, qemu, or xen. + Example choices are kvm, qemu, or xen. (defaults to ${VIRT_TYPE}) + Available options are listed via 'virsh capabilities' in the tags. -v Verbose EOF } @@ -64,6 +68,7 @@ while getopts "h:n:i:k:r:c:s:b:m:v" option; do s) STORAGE=${OPTARG};; b) BRIDGE=${OPTARG};; m) MAC=${OPTARG};; + t) VIRT_TYPE=${OPTARG};; v) VERBOSE=1;; *) usage @@ -130,14 +135,11 @@ while IFS= read -r key; do echo " - $key" >> "$VM_IMAGE_DIR/init/user-data" done < <(grep -v '^ *#' < "$AUTH_KEYS_FQN") -echo "Generating the cidata ISO file $VM_IMAGE_DIR/images/${HOSTNAME}-cidata.iso" +echo "Generating the cidata ISO file $VM_IMAGE_DIR/images/${HOSTNAME}-cidata.img" ( cd "$VM_IMAGE_DIR/init/" - genisoimage \ - -output "$VM_IMAGE_DIR/images/${HOSTNAME}-cidata.img" \ - -volid cidata \ - -rational-rock \ - -joliet \ + cloud-localds \ + "$VM_IMAGE_DIR/images/${HOSTNAME}-cidata.img" \ user-data meta-data ) @@ -148,6 +150,7 @@ fi virt-install \ --name="${HOSTNAME}" \ + --virt-type=${VIRT_TYPE} \ --network "bridge=${BRIDGE},model=virtio" $MACCMD \ --import \ --disk "path=${VM_IMAGE_DIR}/images/${HOSTNAME}.img,format=qcow2" \ @@ -155,11 +158,8 @@ virt-install \ --ram="${RAM}" \ --vcpus="${VCPUS}" \ --autostart \ - --hvm \ - --arch x86_64 \ - --accelerate \ + --cpu host \ --check-cpu \ - --osinfo detect=on,require=off \ --force \ --watchdog=default \ --graphics vnc,listen=0.0.0.0 \ diff --git a/delete-vm b/delete-vm index 717f3db..236dac8 100755 --- a/delete-vm +++ b/delete-vm @@ -39,9 +39,8 @@ fi if [[ -e $VM_IMAGE ]]; then # VM exists virsh destroy "$VM" - virsh undefine "$VM" - rm -fv "$VM_IMAGE" "$CI_IMAGE" + virsh undefine "$VM" --remove-all-storage else echo "Cannot find an VM image file named '$VM_IMAGE'. Attempting undefine..." - virsh undefine "$VM" + virsh undefine "$VM" --remove-all-storage fi diff --git a/get-vm-ip b/get-vm-ip index 155aca9..b33fe1a 100755 --- a/get-vm-ip +++ b/get-vm-ip @@ -33,5 +33,4 @@ if [[ -z $HOSTNAME ]]; then exit 1 fi -MAC=$(virsh domiflist $HOSTNAME | awk '{ print $5 }' | tail -2 | head -1) -arp -a | grep $MAC | awk '{ print $2 }' | sed 's/[()]//g' +virsh domifaddr --domain ${HOSTNAME} --source arp | tail -2 | head -1 | awk '{ print $4 }' | sed -E 's/\/[[:digit:]]+//' From 12c541164284748c7f867f13d1ee361e7e5cccdc Mon Sep 17 00:00:00 2001 From: Andrei Neshcheret Date: Mon, 6 May 2024 15:59:31 +0500 Subject: [PATCH 2/3] Using arp-scan as alternative method. --- get-vm-ip | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/get-vm-ip b/get-vm-ip index b9c6e71..5eec76a 100755 --- a/get-vm-ip +++ b/get-vm-ip @@ -19,13 +19,15 @@ usage() { cat << EOF -usage: $0 hostname +usage: $0 hostname [iface] -This script will take a virsh-managed VM hostname and return the IP address. +This script will take a virsh-managed VM hostname and return the IP address. In the case of using the network in the `bridge` mode, +the arp table will not possibly contain any IP addresses, optionally use alternative method `arp-scan` on specified `iface`. EOF } HOSTNAME=$1 +IFACE=$2 if [[ -z $HOSTNAME ]]; then echo "ERROR: Hostname is required" @@ -34,4 +36,9 @@ if [[ -z $HOSTNAME ]]; then fi MAC=$(virsh -q domiflist $HOSTNAME | awk '{ print $5 }') -arp -e | grep -i $MAC | awk '{ print $1 }' + +if [ -z ${IFACE} ]; then + arp -e | grep -i $MAC | awk '{ print $1 }' +else + arp-scan --interface ${IFACE} --localnet | grep -i $MAC | awk '{ print $1 }' +fi From a1cddc6162ad0a42f6f7c5dc07ab22d7e802080e Mon Sep 17 00:00:00 2001 From: Andrei Neshcheret Date: Mon, 6 May 2024 16:01:19 +0500 Subject: [PATCH 3/3] Use moder [[ ... ]] construct, more safe. --- get-vm-ip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/get-vm-ip b/get-vm-ip index 5eec76a..3974707 100755 --- a/get-vm-ip +++ b/get-vm-ip @@ -37,7 +37,7 @@ fi MAC=$(virsh -q domiflist $HOSTNAME | awk '{ print $5 }') -if [ -z ${IFACE} ]; then +if [[ -z ${IFACE} ]]; then arp -e | grep -i $MAC | awk '{ print $1 }' else arp-scan --interface ${IFACE} --localnet | grep -i $MAC | awk '{ print $1 }'