Skip to content

Instantly share code, notes, and snippets.

@hellt
Last active November 10, 2024 13:06
Show Gist options
  • Save hellt/3626a753a74e3e5a950c71e6b294543f to your computer and use it in GitHub Desktop.
Save hellt/3626a753a74e3e5a950c71e6b294543f to your computer and use it in GitHub Desktop.
Virsh interface move
#!/bin/bash
# usage ~/vifmove.sh <virsh_domain_name/id> <interface_name> <new_bridge_name>
tmpxml=$(mktemp /tmp/ifcfg.XXX)
macaddr="$(virsh domiflist $1 | awk "/$2\s/ {print \$NF}")"
cat > "$tmpxml" <<EOF
<interface type='bridge'>
<mac address='$macaddr'/>
<source bridge='$3'/>
<model type='virtio'/>
</interface>
EOF
virsh update-device "$1" "$tmpxml" --live --persistent
rm "$tmpxml"
@tonusoo
Copy link

tonusoo commented Nov 10, 2024

A version which finds the <virsh_domain_name/id> automatically:

#!/usr/bin/env bash

# usage ~/vifmove.sh <interface_name> <new_bridge_name>

# Script expects that VMs are installed under system libvirtd instance(qemu:///system URI) and not under
# session libvirtd instance(qemu:///session URI).

error_and_exit() {
    echo "ERROR: $1" >&2
    exit 1
}


(( $# != 2 )) && error_and_exit "Usage: sudo ${0##*/} <interface_name> <new_bridge_name>"
(( EUID != 0 )) && error_and_exit "Script needs to be executed as a root user."


# Check if the <new_bridge_name> exists.
[[ ! -d /sys/class/net/$2/bridge ]] && error_and_exit "Linux bridge $2 does not exist"


while read -r vm_id vm_name vm_state; do

    # VMs which are not running have the "-" on Id field.
    [[ "$vm_id" == - ]] || [[ "$vm_id" =~ ^[0-9]+$ ]] || continue

    while read -r int_name int_type int_source int_model int_mac_addr; do

        [[ "$int_type" != "bridge" ]] && continue
        [[ "$int_name" == "$1" ]] && break 2

    done < <(virsh domiflist "$vm_name")

done < <(virsh list --all)

[[ -z "$int_name" ]] && error_and_exit "None of the VMs have the 'bridge' type $1 interface associated"

if [[ "$2" == "$int_source" ]]; then
    echo "$1 is already connected to $2"
    exit
fi

tmp_xml=$(mktemp "/tmp/${0##*/}.XXXXXXXX")

cat << EOF > "$tmp_xml"
<interface type='bridge'>
  <mac address='$int_mac_addr'/>
  <source bridge='$2'/>
  <target dev='$1'/>
  <model type='$int_model'/>
</interface>
EOF


# Temporary XML file for "virsh update-device" is removed only if the
# "virsh update-device" succeeds. This is for troubleshooting purposes.
if [[ "$vm_state" == "running" ]] || [[ "$vm_state" == "paused" ]]; then

    if virsh update-device "$vm_name" "$tmp_xml" --config --live; then
        echo "Connected $int_name from bridge $int_source to bridge $2 and updated $vm_name XML"
        rm -f "$tmp_xml"
    fi

else

    if virsh update-device "$vm_name" "$tmp_xml" --config; then
        echo "Updated $vm_name XML with $int_name connected to $2 bridge"
        rm -f "$tmp_xml"
    fi

fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment