setup libvirt VM by shell
Network setup
all code are here:
https://github.com/shaohef/kvm-script
Network Topology
we only need to change the valuse here. do not chagne other code.
REF: libvirt: Network XML format
# network_name(net): bridge_name(br),forward_mode(mode),cidr_startip(cidr) #mode can be nat/route/isolated NET_NAMES=( 'ansible_edge: asedgebr0' 'smartcity_edge: scedgebr0' 'smartcity_cloud: sccloudbr0' 'ansible_cloud: ascloudbr0') # [network_name]='host:interface_index host:interface_index' declare -A NET_MACS NET_MACS=( [ansible_edge]='EDGE1:1 EDGE2:1 EDGE3:1 HUB:1' [smartcity_edge]='EDGE1:2 EDGE2:2 EDGE3:2 HUB:2' [smartcity_cloud]='CLOUD:2 HUB:3' [ansible_cloud]='CLOUD:1') IP=192.168.124.2 MODE=route # route or nat #[host]="empty macs" declare -A MACS=([EDGE1]="" [EDGE2]="" [EDGE3]="" [HUB]="" [CLOUD]="")
parser network structure utils
# network_struct_parser 'ansible_edge: asedgebr0,nat ' 2 # network_struct_parser 'ansible_edge: asedgebr0' mode function network_struct_parser(){ # $1 struct string, $2 index(0,1,2,3) or key(net/br/mode/cidr) IFS=',: ' array=($1) ; unset IFS array[2]=${array[2]:-nat} declare -A MAP MAP=([net]=0 [br]=1 [mode]=2 [cidr]=3) # if [ -I "$2" ] ; [[ $2 =~ ^-?[0-9]+$ ]] && i=$2 || i=${MAP[$2]} echo ${array[$i]} } # network_struct_key 'ansible_edge: asedgebr0,nat ' function network_struct_key(){ # $1 struct string echo ${1%:*} } # get_network_struct_item NET_NAMES ansible_cloud function get_network_struct_item(){ # $1 NET_NAMES $2 key(network name) for i in $(eval "echo \${!$1[@]}"); do v=$(eval "echo \${$1[i]}") NM=${v%:*} BR=${v#*:} if [ "$NM" = "$2" ]; then echo $v break fi done } # get_network_struct_value NET_NAMES ansible_cloud function get_network_struct_value(){ # $1 NET_NAMES $2 key(network name) for i in $(eval "echo \${!$1[@]}"); do v=$(eval "echo \${$1[i]}") NM=${v%:*} VAL=${v#*:} if [ "$NM" = "$2" ]; then echo $VAL break fi done } # grep_ip 'ansible_edge: asedgebr0,nat,192.168.1.1' cidr function grep_ip(){ match=$(grep -o '[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}' <<< $1) if [ $? -eq 0 ]; then echo $match fi } # network_struct_get_ip 'ansible_edge: asedgebr0,nat,192.168.1.1' # network_struct_get_ip 'ansible_edge: asedgebr0,' # network_struct_get_ip 'ansible_edge: asedgebr0,192.168.1.1' function network_struct_get_ip(){ # echo $(network_struct_parser "$1" mode) possible=$(grep_ip $(network_struct_parser "$1" mode)) ip=${possible:-$(network_struct_parser "$1" cidr)} ip=$(grep_ip "$ip") echo $ip } # network_struct_get_mode 'ansible_edge: asedgebr0,nat,192.168.1.1' # network_struct_get_mode 'ansible_edge: asedgebr0,' # network_struct_get_mode 'ansible_edge: asedgebr0,192.168.1.1,nat' # network_struct_get_mode 'ansible_edge: asedgebr0,192.168.1.1' function network_struct_get_mode(){ mode=$(network_struct_parser "$1" mode) possible=$(grep_ip $mode) [[ ! -z "$possible" ]] && mode=$(network_struct_parser "$1" cidr) mode=${mode:-nat} echo $mode }
Generate a MAC address
REF:
# 33.9. Generating a new unique MAC address Red Hat Enterprise Linux 5 | Red Hat Customer Portal
function genmac(){ cat <<EOF | python3 import random # def randomMAC(): mac = [ 0x00, 0x16, 0x3e, random.randint(0x00, 0x7f), random.randint(0x00, 0xff), random.randint(0x00, 0xff) ] return ':'.join(map(lambda x: "%02x" % x, mac)) print(randomMAC()) EOF }
Generate MAC pool
# declare -A EDGE1_MACS EDGE2_MACS EDGE3_MACS HUB_MACS CLOUD_MACS # MACS=(EDGE1_MACS EDGE2_MACS EDGE3_MACS HUB_MACS CLOUD_MACS) # above 4.3 alpha version support nameref # declare -A MACS=([EDGE1]="" [EDGE2]="" [EDGE3]="" [HUB]="" [CLOUD]="") END=5 for i in "${!MACS[@]}"; do for j in $(seq 1 $END); do MACS[$i]=$(genmac)" "${MACS[$i]}; done echo "export ${i}_MACS=\"${MACS[$i]}\"" >> ~/.bashrc done
Get network Mac addess Array
# declare -p NET_MACS # get_net_macs NET_MACS ansible_edge function get_net_macs(){ # $1 net macs map NET_MACS, $2 net mames, $3 macs pool mac_idxs=$(eval "echo \${$1[$2]}") # IFS=', ' read -r -a array <<< "$string" # array=(${string//:/ }) macstr=($mac_idxs) # return value ret=() for v in "${macstr[@]}"; do host=${v%%:*} idx=${v##*:} macs=${v%%:*}_MACS string=$(eval "echo \${$macs}") # IFS=', ' array=($countries) array=($string) # echo "\${array[${!idx}]}" mac=$(eval "echo \${array[${idx}]}") ret+=($mac) done echo ${ret[@]} }
Get host name Array
# gen_host_array NET_MACS ansible_edge function gen_host_array(){ # $1 net macs map NET_MACS, $2 net mames, $3 base ip addr mac_idxs=$(eval "echo \${$1[$2]}") HOST=${mac_idxs//:/.} echo ${HOST,,} }
Get IP address Array
# inc_subnet 192.168.124.1 3 function inc_subnet(){ SUBN=${1#*.*.} SUBN=${SUBN%.*} SUFFIX=${1##*.} echo ${1%.*.*}.$((${SUBN} + ${2})).${SUFFIX} } # inc_ipaddr 192.168.124.1 3 function inc_ipaddr(){ echo ${1%.*}.$((${1##*.} + $2)) } # gen_ip_array NET_MACS smartcity_edge 192.168.127.1 function gen_ip_array(){ # $1 net macs map NET_MACS, $2 net mames, $3 base ip addr mac_idxs=$(eval "echo \${$1[$2]}") macstr=($mac_idxs) len=${#macstr[@]} ret=() for (( i=0; i<$len; i++ )); do ip=$(inc_ipaddr $3 $i); ret+=($ip) done echo ${ret[@]} }
Get DHCP IP address allocation
function get_dhcp_item(){ # $1 MAC, $2 HOST, $3 DOMAIN, $4 IP DOM=${3/_/.} # (IFS=$';'; echo " <host mac=\"$1\" name=\"${2,,}.${DOM,,}.com\" ip=\"$4\"/>") echo " <host mac=\"$1\" name=\"${2,,}.${DOM,,}.com\" ip=\"$4\"/>" } # gen_dhcp_items NET_MACS ansible_edge 192.168.124.192 function gen_dhcp_items(){ # $1 net macs map NET_MACS, $2 net mames, $3 base ip addr hosts=$(gen_host_array $1 $2) macs=$(get_net_macs $1 $2) ips=$(gen_ip_array $1 $2 $3) ha=($hosts) hm=($macs) hi=($ips) ret=() for i in ${!ha[@]}; do itm=$(get_dhcp_item ${hm[$i]} ${ha[$i]} $2 ${hi[$i]}) # declare -p itm ret+=("$itm") # echo ${ha[$i]} ${hm[$i]} ${hi[$i]} done # echo ${ret[@]} # declare -p ret ( IFS=$'\n'; echo "${ret[*]}" ) }
Generate network xml snippet files
# gen_networt_xml ansible_edge asedgebr0 192.168.124.1 $dhcp nat function gen_networt_xml(){ # $1 NET_NAME $2 BR NAME $3 IP $4 DHCP $5 MODE str="<network> <name>$1</name> <bridge name=\"$2\"/> <forward mode=\"${5}\"/> <ip address=\"${3%.*}.1\" netmask=\"255.255.255.0\"> <dhcp> <range start=\"${3%.*}.2\" end=\"${3%.*}.192\"/> $4 </dhcp> </ip> </network>" [[ ! -z ${5} && "isolated" =~ ${5,,} ]] && mode= || mode=" <forward mode=\"${5}\"/>" mkdir -p /tmp/vir_network cat | tee /tmp/vir_network/$1.xml << EOF <network> <name>$1</name> <bridge name="$2"/> $mode <ip address="${3%.*}.1" netmask="255.255.255.0"> <dhcp> <range start="${3%.*}.2" end="${3%.*}.192"/> $4 </dhcp> </ip> </network> EOF # declare -p str } # gen_networt_xmls NET_NAMES NET_MACS 192.168.124.1 nat # gen_networt_xmls NET_NAMES NET_MACS function gen_networt_xmls(){ # $1 NET_NAMES $2 NET_MACS $3 IP $4 MODE: nat or route IP=${3:-192.168.124.2} for i in $(eval "echo \${!$1[@]}"); do v=$(eval "echo \${$1[i]}") NM=${v%:*} BR=$(network_struct_parser "$v" br) ip=$(inc_subnet $IP $i) cidr_ip=$(network_struct_get_ip "$v") ip=${cidr_ip:-$ip} dhcp=$(gen_dhcp_items $2 $NM $ip) mode=$(network_struct_get_mode "$v") gen_networt_xml $NM $BR $ip "$dhcp" ${4:-$mode} done }
Network Operation
create
virsh net-create /tmp/vir_network.xml virsh net-list ip a
delete by
virsh net-destroy
VM Operation
download the expect images
Ubuntu Cloud Images - the official Ubuntu images for public clouds, Openstack, KVM and LXD
basic value
REF: libvirt: Domain XML format
VM_NAME=smartcity_cloud VM_MEMSIZE_G=10 VM_VCPUS=6 KVM=/usr/libexec/qemu-kvm IMG=/var/lib/libvirt/images/edge2.qcow2
Get host mac address and network infomatin.
REF: How to sort an array in Bash - Stack Overflow
# get_host_macs NET_MACS HUB function get_host_macs(){ # $1 net macs map NET_MACS, $2 hostname, $3 macs pool VAL=${2^^} ret=() for i in $(eval "echo \${!$1[@]}"); do v=$(eval "echo \${$1[$i]}") match=$(grep -o "$VAL:[[:digit:]]\{1,4\}" <<< $v) if [ $? -ne 0 ]; then continue fi idx=${match#*:} macs=${match%%:*}_MACS string=$(eval "echo \${$macs}") array=($string) # echo "\${array[${!idx}]}" mac=$(eval "echo \${array[${idx}]}") # 0 host, 1 index, 2 network, 3 mac ret+=("$VAL $idx $i $mac,") done # IFS=$'\n' sorted=($(sort <<<"${ret[*]}")); unset IFS # readarray -t sorted < <(for a in "${ret[@]}"; do echo "$a"; done | sort) sorted=($(printf '%s\n' "${ret[@]}"|sort)) echo ${sorted[@]} } # get_network_brige NET_NAMES ansible_cloud function get_network_brige(){ # $1 NET_NAMES $2 network name for i in $(eval "echo \${!$1[@]}"); do v=$(eval "echo \${$1[i]}") NM=${v%:*} BR=$(awk -F"[, :]" '{print $1}' <<< ${v#*: }) if [ "$NM" = "$2" ]; then echo $BR break fi done }
Generate network interface xml snippet files
# gen_interface_xml testnet 11.22.33.44.55.77 br0 function gen_interface_xml(){ IFMODEL=${IFMODEL:-rtl8139} #"virtio" # $1 network name in NET_MACS, $2 mac address, $3 Bridge name # <target dev='vnet1'/> # <alias name='net0'/> str=" <interface type='network'> <mac address='$2'/> <source network='$1' bridge='$3'/> <model type='$IFMODEL'/> </interface>" # declare -p str echo "$str" } # gen_interface_xmls NET_MACS HUB NET_NAMES function gen_interface_xmls(){ # $1 net macs map NET_MACS, $2 hostname, $3 network-bridge NET_NAMES ret=() macs=$(get_host_macs $1 $2) IFS=',' maca=($macs); unset IFS for i in ${!maca[@]}; do vs=${maca[$i]} va=($vs) # 0 host, 1 index, 2 network, 3 mac # echo ${va[1]} ${va[2]} BR=$(get_network_brige $3 ${va[2]}) xml=$(gen_interface_xml ${va[2]} ${va[3]} $BR) ret+=("$xml") done ( IFS=$'\n'; echo "${ret[*]}" ) # echo "${ret[@]}" }
Generate VM xml
# get_vm_xml NET_MACS cloud NET_NAMES function get_vm_xml(){ # $1 net macs map NET_MACS, $2 hostname, $3 network-bridge NET_NAMES
The whole code as follow:
V1.2
function null_exit(){ [[ -z "$1" ]] && exit 1; } # BASEIMG=/var/lib/libvirt/images/test.qcow2 # get_vm_xml NET_MACS cloud NET_NAMES function get_vm_xml(){ # https://stackoverflow.com/questions/9893667/is-there-a-way-to-write-a-bash-function-which-aborts-the-whole-execution-no-mat trap "exit 1" TERM export TOP_PID=$$ # kill -s TERM $TOP_PID echo "BASEIMG=$BASEIMG" null_exit $BASEIMG echo "VM_NAME=$VM_NAME" null_exit $VM_NAME VM_MEMSIZE_G=${VM_MEMSIZE_G:-10} VM_VCPUS=${VM_VCPUS:-4} echo "VM_MEMSIZE_G=$VM_MEMSIZE_G VM_VCPUS=$VM_VCPUS" IMG=${BASEIMG%/*}/$2.${BASEIMG#*.} cp $BASEIMG $IMG virt-edit -a $IMG /etc/hostname -e "s/^.*$/$2/" ifc=$(virt-ls -a $IMG /etc/sysconfig/network-scripts/ |grep ifcfg-ens* |head -n 1) virt-edit -a $IMG /etc/sysconfig/network-scripts/ifc -e 's/^BOOTPROTO=.*/BOOTPROTO=dhcp/' # $1 net macs map NET_MACS, $2 hostname, $3 network-bridge NET_NAMES mkdir -p /tmp/vir_domain INTREFCAE=$(gen_interface_xmls $1 $2 $3) cat | tee /tmp/vir_domain/${VM_NAME}.xml << EOF <domain type='kvm' id='2'> <name>$VM_NAME</name> <memory unit='GiB'>$VM_MEMSIZE_G</memory> <vcpu placement='static'>$VM_VCPUS</vcpu> <resource> <partition>/machine</partition> </resource> <os> <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type> <boot dev='hd'/> </os> <features> <acpi/> <apic/> </features> <cpu mode='custom' match='exact' check='full'> <model fallback='forbid'>Skylake-Server-IBRS</model> <feature policy='require' name='md-clear'/> <feature policy='require' name='spec-ctrl'/> <feature policy='require' name='ssbd'/> <feature policy='require' name='hypervisor'/> <feature policy='disable' name='arat'/> </cpu> <clock offset='utc'> <timer name='rtc' tickpolicy='catchup'/> <timer name='pit' tickpolicy='delay'/> <timer name='hpet' present='no'/> </clock> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <pm> <suspend-to-mem enabled='no'/> <suspend-to-disk enabled='no'/> </pm> <devices> <emulator>$KVM</emulator> <disk type='file' device='disk'> <driver name='qemu' type='qcow2'/> <source file='$IMG'/> <backingStore/> <target dev='vda' bus='virtio'/> <alias name='virtio-disk0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </disk> <disk type='file' device='cdrom'> <driver name='qemu'/> <target dev='hda' bus='ide'/> <readonly/> <alias name='ide0-0-0'/> <address type='drive' controller='0' bus='0' target='0' unit='0'/> </disk> <controller type='usb' index='0' model='ich9-ehci1'> <alias name='usb'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x7'/> </controller> <controller type='usb' index='0' model='ich9-uhci1'> <alias name='usb'/> <master startport='0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0' multifunction='on'/> </controller> <controller type='usb' index='0' model='ich9-uhci2'> <alias name='usb'/> <master startport='2'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x1'/> </controller> <controller type='usb' index='0' model='ich9-uhci3'> <alias name='usb'/> <master startport='4'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x2'/> </controller> <controller type='pci' index='0' model='pci-root'> <alias name='pci.0'/> </controller> <controller type='ide' index='0'> <alias name='ide'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> </controller> $INTREFCAE <serial type='pty'> <source path='/dev/pts/5'/> <target type='isa-serial' port='0'> <model name='isa-serial'/> </target> <alias name='serial0'/> </serial> <console type='pty' tty='/dev/pts/5'> <source path='/dev/pts/5'/> <target type='serial' port='0'/> <alias name='serial0'/> </console> <input type='mouse' bus='ps2'> <alias name='input0'/> </input> <input type='keyboard' bus='ps2'> <alias name='input1'/> </input> <video> <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> <alias name='video0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </video> <memballoon model='virtio'> <alias name='balloon0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> </devices> <seclabel type='dynamic' model='selinux' relabel='yes'> <label>system_u:system_r:svirt_t:s0:c263,c892</label> <imagelabel>system_u:object_r:svirt_image_t:s0:c263,c892</imagelabel> </seclabel> <seclabel type='dynamic' model='dac' relabel='yes'> <label>+107:+107</label> <imagelabel>+107:+107</imagelabel> </seclabel> </domain> EOF }
V1.1
1 # get_vm_xml NET_MACS cloud NET_NAMES 2 function get_vm_xml(){ 3 # $1 net macs map NET_MACS, $2 hostname, $3 network-bridge NET_NAMES 4 mkdir -p /tmp/vir_domain 5 INTREFCAE=$(gen_interface_xmls $1 $2 $3) 6 cat | tee /tmp/vir_domain/${VM_NAME}.xml << EOF 7 <domain type='kvm' id='2'> 8 <name>$VM_NAME</name> 9 <memory unit='GiB'>$VM_MEMSIZE_G</memory> 10 <vcpu placement='static'>$VM_VCPUS</vcpu> 11 <resource> 12 <partition>/machine</partition> 13 </resource> 14 <os> 15 <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type> 16 <boot dev='hd'/> 17 </os> 18 <features> 19 <acpi/> 20 <apic/> 21 </features> 22 <cpu mode='custom' match='exact' check='full'> 23 <model fallback='forbid'>Skylake-Server-IBRS</model> 24 <feature policy='require' name='md-clear'/> 25 <feature policy='require' name='spec-ctrl'/> 26 <feature policy='require' name='ssbd'/> 27 <feature policy='require' name='hypervisor'/> 28 <feature policy='disable' name='arat'/> 29 </cpu> 30 <clock offset='utc'> 31 <timer name='rtc' tickpolicy='catchup'/> 32 <timer name='pit' tickpolicy='delay'/> 33 <timer name='hpet' present='no'/> 34 </clock> 35 <on_poweroff>destroy</on_poweroff> 36 <on_reboot>restart</on_reboot> 37 <on_crash>destroy</on_crash> 38 <pm> 39 <suspend-to-mem enabled='no'/> 40 <suspend-to-disk enabled='no'/> 41 </pm> 42 <devices> 43 <emulator>$KVM</emulator> 44 <disk type='file' device='disk'> 45 <driver name='qemu' type='qcow2'/> 46 <source file='$IMG'/> 47 <backingStore/> 48 <target dev='vda' bus='virtio'/> 49 <alias name='virtio-disk0'/> 50 <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> 51 </disk> 52 <disk type='file' device='cdrom'> 53 <driver name='qemu'/> 54 <target dev='hda' bus='ide'/> 55 <readonly/> 56 <alias name='ide0-0-0'/> 57 <address type='drive' controller='0' bus='0' target='0' unit='0'/> 58 </disk> 59 <controller type='usb' index='0' model='ich9-ehci1'> 60 <alias name='usb'/> 61 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x7'/> 62 </controller> 63 <controller type='usb' index='0' model='ich9-uhci1'> 64 <alias name='usb'/> 65 <master startport='0'/> 66 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0' multifunction='on'/> 67 </controller> 68 <controller type='usb' index='0' model='ich9-uhci2'> 69 <alias name='usb'/> 70 <master startport='2'/> 71 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x1'/> 72 </controller> 73 <controller type='usb' index='0' model='ich9-uhci3'> 74 <alias name='usb'/> 75 <master startport='4'/> 76 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x2'/> 77 </controller> 78 <controller type='pci' index='0' model='pci-root'> 79 <alias name='pci.0'/> 80 </controller> 81 <controller type='ide' index='0'> 82 <alias name='ide'/> 83 <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> 84 </controller> 85 $INTREFCAE 86 <serial type='pty'> 87 <source path='/dev/pts/5'/> 88 <target type='isa-serial' port='0'> 89 <model name='isa-serial'/> 90 </target> 91 <alias name='serial0'/> 92 </serial> 93 <console type='pty' tty='/dev/pts/5'> 94 <source path='/dev/pts/5'/> 95 <target type='serial' port='0'/> 96 <alias name='serial0'/> 97 </console> 98 <input type='mouse' bus='ps2'> 99 <alias name='input0'/> 100 </input> 101 <input type='keyboard' bus='ps2'> 102 <alias name='input1'/> 103 </input> 104 <video> 105 <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> 106 <alias name='video0'/> 107 <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> 108 </video> 109 <memballoon model='virtio'> 110 <alias name='balloon0'/> 111 <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> 112 </memballoon> 113 </devices> 114 <seclabel type='dynamic' model='selinux' relabel='yes'> 115 <label>system_u:system_r:svirt_t:s0:c263,c892</label> 116 <imagelabel>system_u:object_r:svirt_image_t:s0:c263,c892</imagelabel> 117 </seclabel> 118 <seclabel type='dynamic' model='dac' relabel='yes'> 119 <label>+107:+107</label> 120 <imagelabel>+107:+107</imagelabel> 121 </seclabel> 122 </domain> 123 EOF 124 }
V1
1 # get_vm_xml NET_MACS cloud NET_NAMES 2 function get_vm_xml(){ 3 # $1 net macs map NET_MACS, $2 hostname, $3 network-bridge NET_NAMES 4 5 INTREFCAE=$(gen_interface_xmls $1 $2 $3) 6 cat | tee /tmp/vir_VM.xml << EOF 7 <domain type='kvm' id='2'> 8 <name>$VM_NAME</name> 9 <memory unit='GiB'>$VM_MEMSIZE_G</memory> 10 <vcpu placement='static'>$VM_VCPUS</vcpu> 11 <resource> 12 <partition>/machine</partition> 13 </resource> 14 <os> 15 <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type> 16 <boot dev='hd'/> 17 </os> 18 <features> 19 <acpi/> 20 <apic/> 21 </features> 22 <cpu mode='custom' match='exact' check='full'> 23 <model fallback='forbid'>Skylake-Server-IBRS</model> 24 <feature policy='require' name='md-clear'/> 25 <feature policy='require' name='spec-ctrl'/> 26 <feature policy='require' name='ssbd'/> 27 <feature policy='require' name='hypervisor'/> 28 <feature policy='disable' name='arat'/> 29 </cpu> 30 <clock offset='utc'> 31 <timer name='rtc' tickpolicy='catchup'/> 32 <timer name='pit' tickpolicy='delay'/> 33 <timer name='hpet' present='no'/> 34 </clock> 35 <on_poweroff>destroy</on_poweroff> 36 <on_reboot>restart</on_reboot> 37 <on_crash>destroy</on_crash> 38 <pm> 39 <suspend-to-mem enabled='no'/> 40 <suspend-to-disk enabled='no'/> 41 </pm> 42 <devices> 43 <emulator>$KVM</emulator> 44 <disk type='file' device='disk'> 45 <driver name='qemu' type='qcow2'/> 46 <source file='$IMG'/> 47 <backingStore/> 48 <target dev='vda' bus='virtio'/> 49 <alias name='virtio-disk0'/> 50 <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> 51 </disk> 52 <disk type='file' device='cdrom'> 53 <driver name='qemu'/> 54 <target dev='hda' bus='ide'/> 55 <readonly/> 56 <alias name='ide0-0-0'/> 57 <address type='drive' controller='0' bus='0' target='0' unit='0'/> 58 </disk> 59 <controller type='usb' index='0' model='ich9-ehci1'> 60 <alias name='usb'/> 61 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x7'/> 62 </controller> 63 <controller type='usb' index='0' model='ich9-uhci1'> 64 <alias name='usb'/> 65 <master startport='0'/> 66 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0' multifunction='on'/> 67 </controller> 68 <controller type='usb' index='0' model='ich9-uhci2'> 69 <alias name='usb'/> 70 <master startport='2'/> 71 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x1'/> 72 </controller> 73 <controller type='usb' index='0' model='ich9-uhci3'> 74 <alias name='usb'/> 75 <master startport='4'/> 76 <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x2'/> 77 </controller> 78 <controller type='pci' index='0' model='pci-root'> 79 <alias name='pci.0'/> 80 </controller> 81 <controller type='ide' index='0'> 82 <alias name='ide'/> 83 <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> 84 </controller> 85 $INTREFCAE 86 <serial type='pty'> 87 <source path='/dev/pts/5'/> 88 <target type='isa-serial' port='0'> 89 <model name='isa-serial'/> 90 </target> 91 <alias name='serial0'/> 92 </serial> 93 <console type='pty' tty='/dev/pts/5'> 94 <source path='/dev/pts/5'/> 95 <target type='serial' port='0'/> 96 <alias name='serial0'/> 97 </console> 98 <input type='mouse' bus='ps2'> 99 <alias name='input0'/> 100 </input> 101 <input type='keyboard' bus='ps2'> 102 <alias name='input1'/> 103 </input> 104 <video> 105 <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> 106 <alias name='video0'/> 107 <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> 108 </video> 109 <memballoon model='virtio'> 110 <alias name='balloon0'/> 111 <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> 112 </memballoon> 113 </devices> 114 <seclabel type='dynamic' model='selinux' relabel='yes'> 115 <label>system_u:system_r:svirt_t:s0:c263,c892</label> 116 <imagelabel>system_u:object_r:svirt_image_t:s0:c263,c892</imagelabel> 117 </seclabel> 118 <seclabel type='dynamic' model='dac' relabel='yes'> 119 <label>+107:+107</label> 120 <imagelabel>+107:+107</imagelabel> 121 </seclabel> 122 </domain> 123 EOF 124 }
Strat VM
HOST=cloud IMG=/var/lib/libvirt/images/$HOST.qcow2 VM_NAME=smartcity_$HOST VM_MEMSIZE_G=10 VM_VCPUS=6 get_vm_xml NET_MACS $HOST NET_NAMES virsh create /tmp/vir_domain/$VM_NAME.xml virsh list
XML tools to parser
REF:
xmllint - Native shell command set to extract node value from XML - Stack Overflow
xmllint displays value of second attribute if first one matches - Unix & Linux Stack Exchange
sed - How do I extract a single attribute from an XML file? - Ask Ubuntu
bash extract xml attribute value using xmllint - Stack Overflow
Pre-define expression
XML_IFC_EXP="//*[local-name()='interface']/address/@slot"
Parser XML
XML_IFC_EXP="//*[local-name()='interface']/address/@slot" # get_xml_attr_value $XML_IFC_EXP smartcity_cloud.xml function get_xml_attr_value(){ ret=() str=$(xmllint --xpath "$1" $2) entries=($(echo ${str})) for entry in "${entries[@]}"; do result=$(echo $entry | awk -F'[="]' '!/>/{print $(NF-1)}') ret+=("$result") done echo ${ret[@]} } function get_xml_elem_text(){ }
Inject interface script
NIC_PREFIX=ens virsh list --all # inject_ifc_script smartcity_edge3 function inject_ifc_script(){ # $1 domain name [[ "running" == "$(virsh domstate $1)" ]] && echo "The vm in running, exit" && return 1 mkdir -p /tmp/vir_domain virsh dumpxml $1 > /tmp/vir_domain/vm_tmp.xml NIC_PREFIX=${NIC_PREFIX:-ens} XML_IFC_EXP_DEF="//*[local-name()='interface']/address/@slot" XML_IFC_EXP=${XML_IFC_EXP:-$XML_IFC_EXP_DEF} dev=$(get_xml_attr_value $XML_IFC_EXP /tmp/vir_domain/vm_tmp.xml) build_list=($dev) for i in "${build_list[@]:1}"; do ifc="${NIC_PREFIX}${i#0x0*}" gen_ifcfg $ifc virt-copy-in -d $1 /tmp/vir_domain/ifcfg-$ifc /etc/sysconfig/network-scripts done } function gen_ifcfg(){ BOOTPROTO=${BOOTPROTO:-none} cat > /tmp/vir_domain/ifcfg-$1 << EOF TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=${BOOTPROTO} DEFROUTE=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no IPV6_ADDR_GEN_MODE=stable-privacy NAME=$1 # UUID=ccf2fab2-87aa-4279-b7dc-e8f3f2b87d12 DEVICE=$1 ONBOOT=yes # IPADDR=192.168.122.3 # NETMASK=255.255.255.0 # GATEWAY=192.168.122.1 EOF }
Only set one interface as the dhcp bootproto
virsh list --all
inject_ifc_script $dom
Set VM interface model
# set_interface_model domain index model function set_interface_model(){ # $1 domain $2 device index(can be "all") $3 model num=${2:-all} model=${3:-virtio} virt-xml $1 --edit $num --print-diff --network model=$model }
Set VM Host Name
function set_hostname() { # $1 domain name $2 host name [[ "running" == "$(virsh domstate $1)" ]] && echo "The vm in running, exit" && return 1 virt-edit -d $1 /etc/hostname -e "s/^.*$/$2/" }
Resize VM Disk(centos)
we can run this command and resize it in VM VMware虚拟机中CentOS7的硬盘空间扩容 - 华为云 (huaweicloud.com)
qemu-img resize /var/lib/libvirt/images/test20g.qcow2 +10G
a simple way(interactive):
# https://www.huaweicloud.com/articles/efd2b3302420a70e14adae31cf87f9b0.html # resize_vm_disk /var/lib/libvirt/images/tmp.qcow2 newname function resize_vm_disk () { # $1 old disk name $2 new disk $3 total size $4 partition $5 volume if [ -z "$1" ]; then ls /var/lib/libvirt/images/ echo "resize_vm_disk /var/lib/libvirt/images/\${olddisk}.qcow2 \${newdisk} 30G" return 1 fi new=${1%/*}/${2}.qcow2 size=${3:-20G} disk=${4:-/dev/sda2} lv_disk=${5:-/dev/centos/root} virt-filesystems --long -h --all -a $1 qemu-img create -f qcow2 -o preallocation=metadata $new $size # https://blog.csdn.net/tutucute0000/article/details/38414449 virt-resize --expand $disk --LV-expand $lv_disk $1 $new virt-filesystems --long -h --all -a $new echo "new qcow2 disk generated: $new" echo "NOTE: For xfs filesystem, please resize volume using CLI inside VM manfully " echo " virt-rescue -a $new -i" echo " chroot /sysroot" echo " vgdisplay" echo " lvextend -l +100%FREE /dev/mapper/centos-root" echo " xfs_growfs /dev/mapper/centos-root" echo " df -h" echo "after exit, please recheck: " echo " virt-filesystems --long -h --all -a $new" }
auto resize
v1.1
1 function gen_resize_lvm_script(){ 2 FILE=/tmp/vir_domain/resize_lvm.sh 3 cat > $FILE << EOF 4 # vgdisplay 5 lvextend -l +100%FREE ${2:-/dev/mapper/centos-root} >> /root/boot1.log 6 ${1:-xfs_growfs} ${2:-/dev/mapper/centos-root} >> /root/boot1.log 7 # df -h 8 EOF 9 echo "$FILE" 10 } 11 12 # get_dom_1st_disk domain_name 13 function get_dom_1st_disk(){ 14 # $1 domain name 15 FIRST_DISK_EXP='//disk[1][@device="disk"]/source/@file' 16 tmpxml=/tmp/vir_domain/tmp.xml 17 mkdir -p /tmp/vir_domain 18 virsh dumpxml $1 > $tmpxml 19 img=$(xmllint --xpath $FIRST_DISK_EXP $tmpxml | awk -F'[="]' '!/>/{print $(NF-1)}') 20 echo "$img" 21 } 22 23 24 function check_resize_dom_lvm_1st_arg(){ 25 if [ -z "$1" ]; then 26 virsh list --all 27 echo "usage:" 28 echo " resize_dom_lvm domain|file size_G disk volume script_file " 29 return 1 30 fi 31 32 if [[ ! -f "$1" ]] ; then 33 virsh dominfo $1 34 ret=$? 35 [[ $ret -ne 0 ]] && return $ret 36 fi 37 } 38 39 40 function check_resize_dom_lvm_2st_arg(){ 41 if [ -z "$2" ]; then 42 echo "Error: missing the size parameters(\$2): " 43 virt-filesystems --long -h --all -a $1 44 echo "Get the resize disk(\$3) and lvm(\$4) from above information" 45 echo "And generate resize script by this command:" 46 echo " gen_resize_lvm_script" 47 echo "Check the script is right" 48 return 1 49 fi 50 } 51 52 function parser_disk_info(){ 53 # $1 image 54 img=$1 55 # 0 last partition, 1 last pv 2. last vg 3. last vg parent 4. root lv, 5. file type 6. is lvm (check pv) 56 ret=() 57 fsys=$(virt-filesystems --long -h --all -a $img) 58 59 # ---------------------- 0 last partition ----------------------- 60 partn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9 ]*partition"|sort|tail -n 1) 61 # partndev=$(echo "$partn" | awk '{print $1}') 62 partndev=${partn%% *} 63 ret+=("$partndev") 64 # ---------------------- 1 last pv ----------------------- 65 pvn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9 ]*pv"|sort|tail -n 1) 66 pvndev=$(echo "$pvn" | awk '{print $1}') 67 # disk=${3:-/dev/sda2} 68 ret+=("$pvndev") 69 # pvndev=${3:-$pvndev} 70 71 # ---------------------- 2 last vg ----------------------- 72 vgn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9]*[[:space:]]*vg.*"|sort|tail -n 1) 73 vgdev=$(echo "$vgn" | awk '{print $1}') 74 ret+=("$vgdev") 75 76 # ---------------------- 3 last vg parent ----------------------- 77 vgnp=${vgn##* } 78 ret+=("$vgnp") 79 80 # ---------------------- 4 root lv ----------------------- 81 lv=$(echo "$fsys" |grep "${vgdev}/root[[:space:]]*.*${vgdev}"|sort|tail -n 1) 82 lvroot=$(echo "$lv" | awk '{print $1}') 83 # lvroot=${4:-$lvroot} 84 ret+=("$lvroot") 85 86 # ---------------------- 5 file type ----------------------- 87 fs=$(echo "$fsys" |grep "${lvroot}[[:space:]]*filesystem") 88 fstype=$(echo "$fs" | awk '{print $3}') 89 ret+=("$fstype") 90 91 # ---------------------- 6 is lvm ----------------------- 92 declare -p ret 93 # echo $pvn, $vgn, $fs, $vgdev 94 echo $pvndev, $lvroot, $fstype 95 } 96 97 98 99 function parser_disk_lv_info(){ 100 # $1 image 101 img=$1 102 # 0 last partition, 1 last pv 2. last vg 3. last vg parent 4. root vg, 5. file type 6. is lvm (check pv) 103 ret=() 104 fsys=$(virt-filesystems --long -h --all -a $img) 105 vgn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9]*[[:space:]]*vg[[:space:]]*.*/dev/[A-Za-z1-9]*"|sort|tail -n 1) 106 vgdev=${vgn%% *} 107 vgnp=${vgn##* } 108 lv=$(echo "$fsys" |grep -v "swap" |grep "${vgdev}/.*[[:space:]]*.*${vgdev}"|sort|tail -n 1) 109 fs=$(echo "$fsys" |grep -v "swap" |grep "${vgdev}/.*[[:space:]]*filesystem"|sort|tail -n 1) 110 fstype=$(echo "$fs" | awk '{print $3}') 111 112 IFS=',' array=($vgnp) ; unset IFS 113 len=${#array[@]} 114 pdevlast=${array[@]: -1} 115 pdev1st=${array[0]} 116 # a bug for virt-filesystems 117 if [[ "$pdevlast" == "$pdev1st" && $len -gt 0 ]] ; then 118 base=${pdev1st%%[[:digit:]]*} 119 idx=${pdev1st##${base}} 120 idx=$(($len -1 + $idx)) 121 # echo $pdev1st $base $idx 122 pdevlast=${base}${idx} 123 fi 124 # echo $vgdev: $vgnp: $lv: $fs: $fstype, $len, $pdevlast $pdev1st 125 echo "${lv%% *}, $fstype, $pdev1st, $pdevlast" 126 } 127 128 129 # resize_dom_lvm domain script_file size_G # only test on centos7.9 130 function resize_dom_lvm(){ 131 # $1 domain name $2 size $3 disk $4 volume # $5 resize script 132 check_resize_dom_lvm_1st_arg $1 133 ret=$? 134 [[ $ret -ne 0 ]] && return $ret 135 136 [[ ! -f "$1" && "running" == "$(virsh domstate $1)" ]] && echo "The vm in running, exit" && ret=1 137 [[ $ret -ne 0 ]] && return $ret 138 139 [[ -f "$1" ]] && img=$1 || img=$(get_dom_1st_disk $1) 140 141 check_resize_dom_lvm_2st_arg $img $2 142 ret=$? 143 [[ $ret -ne 0 ]] && return $ret 144 size=${2:-20G} 145 img_size=$(qemu-img info --output json $img | grep "virtual-size" | awk -F"[,:]" '{print $2}') 146 osize=$(($img_size/1024/1024/1024)) 147 nsize=${size%%[^0-9]*} 148 [[ "$(($osize + 1))" -gt "$nsize" ]] && echo "The original image size is ${osize}G. Please imput a bigger size." && return 1 149 150 lvinfo=$(parser_disk_lv_info $1) 151 IFS=', ' array=($lvinfo); unset IFS 152 lvroot=${4:-${array[0]}} 153 fstype=${array[1]} 154 pv_disk=${3:-${array[2]}} 155 [[ "xfs" == "$fstype" ]] && fs_cmd=xfs_growfs || fs_cmd=resize2fs 156 script=$(gen_resize_lvm_script $fs_cmd $lvroot) 157 # virt-sysprep can also works 158 # [[ -f "$1" ]] && virt-customize -a $1 --firstboot $script || virt-customize -d $1 --firstboot $script 159 160 tmp_img=${img%/*}/temporary.${img#*.} 161 echo "qemu-img create -f qcow2 -o preallocation=metadata $tmp_img $size" 162 echo "Generate a intermediate images: $tmp_img" 163 qemu-img create -f qcow2 -o preallocation=metadata $tmp_img $size 164 165 virt-filesystems --long -h --all -a $img 166 # https://blog.csdn.net/tutucute0000/article/details/38414449 167 echo "virt-resize --expand $pv_disk --LV-expand $lvroot $img $tmp_img" 168 virt-resize --expand $pv_disk --LV-expand $lvroot "$img" "$tmp_img" 169 echo "virt-customize -a $tmp_img --run $script" 170 virt-customize -a $tmp_img --run $script 171 virt-filesystems --long -h --all -a $tmp_img 172 if [[ $ret -eq 0 ]] ; then 173 echo "mv $tmp_img $img -f" 174 mv $tmp_img $img -f 175 else 176 echo "NOTE: Please double chech and run the follow command manually\!" 177 echo " mv $tmp_img $img -f" 178 fi 179 }
1 function gen_resize_lvm_script(){ 2 FILE=/tmp/vir_domain/resize_lvm.sh 3 cat > $FILE << EOF 4 # vgdisplay 5 lvextend -l +100%FREE ${2:-/dev/mapper/centos-root} >> /root/boot1.log 6 ${1:-xfs_growfs} ${2:-/dev/mapper/centos-root} >> /root/boot1.log 7 # df -h 8 EOF 9 echo "$FILE" 10 } 11 12 # get_dom_1st_disk domain_name 13 function get_dom_1st_disk(){ 14 # $1 domain name 15 FIRST_DISK_EXP='//disk[1][@device="disk"]/source/@file' 16 tmpxml=/tmp/vir_domain/tmp.xml 17 mkdir -p /tmp/vir_domain 18 virsh dumpxml $1 > $tmpxml 19 img=$(xmllint --xpath $FIRST_DISK_EXP $tmpxml | awk -F'[="]' '!/>/{print $(NF-1)}') 20 echo "$img" 21 } 22 23 24 function check_resize_dom_lvm_1st_arg(){ 25 if [ -z "$1" ]; then 26 virsh list --all 27 echo "usage:" 28 echo " resize_dom_lvm domain|file size_G disk volume script_file " 29 return 1 30 fi 31 32 if [[ ! -f "$1" ]] ; then 33 virsh dominfo $1 34 ret=$? 35 [[ $ret -ne 0 ]] && return $ret 36 fi 37 } 38 39 40 function check_resize_dom_lvm_2st_arg(){ 41 if [ -z "$2" ]; then 42 echo "Error: missing the size parameters(\$2): " 43 virt-filesystems --long -h --all -a $1 44 echo "Get the resize disk(\$3) and lvm(\$4) from above information" 45 echo "And generate resize script by this command:" 46 echo " gen_resize_lvm_script" 47 echo "Check the script is right" 48 return 1 49 fi 50 } 51 52 function parser_disk_info(){ 53 # $1 image 54 img=$1 55 # 0 last partition, 1 last pv 2. last vg 3. last vg parent 4. root lv, 5. file type 6. is lvm (check pv) 56 ret=() 57 fsys=$(virt-filesystems --long -h --all -a $img) 58 59 # ---------------------- 0 last partition ----------------------- 60 partn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9 ]*partition"|sort|tail -n 1) 61 # partndev=$(echo "$partn" | awk '{print $1}') 62 partndev=${partn%% *} 63 ret+=("$partndev") 64 # ---------------------- 1 last pv ----------------------- 65 pvn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9 ]*pv"|sort|tail -n 1) 66 pvndev=$(echo "$pvn" | awk '{print $1}') 67 # disk=${3:-/dev/sda2} 68 ret+=("$pvndev") 69 # pvndev=${3:-$pvndev} 70 71 # ---------------------- 2 last vg ----------------------- 72 vgn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9]*[[:space:]]*vg.*"|sort|tail -n 1) 73 vgdev=$(echo "$vgn" | awk '{print $1}') 74 ret+=("$vgdev") 75 76 # ---------------------- 3 last vg parent ----------------------- 77 vgnp=${vgn##* } 78 ret+=("$vgnp") 79 80 # ---------------------- 4 root lv ----------------------- 81 lv=$(echo "$fsys" |grep "${vgdev}/root[[:space:]]*.*${vgdev}"|sort|tail -n 1) 82 lvroot=$(echo "$lv" | awk '{print $1}') 83 # lvroot=${4:-$lvroot} 84 ret+=("$lvroot") 85 86 # ---------------------- 5 file type ----------------------- 87 fs=$(echo "$fsys" |grep "${lvroot}[[:space:]]*filesystem") 88 fstype=$(echo "$fs" | awk '{print $3}') 89 ret+=("$fstype") 90 91 # ---------------------- 6 is lvm ----------------------- 92 declare -p ret 93 # echo $pvn, $vgn, $fs, $vgdev 94 echo $pvndev, $lvroot, $fstype 95 } 96 97 98 99 function parser_disk_lv_info(){ 100 # $1 image 101 img=$1 102 # 0 last partition, 1 last pv 2. last vg 3. last vg parent 4. root vg, 5. file type 6. is lvm (check pv) 103 ret=() 104 fsys=$(virt-filesystems --long -h --all -a $img) 105 vgn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9]*[[:space:]]*vg[[:space:]]*.*/dev/[A-Za-z1-9]*"|sort|tail -n 1) 106 vgdev=${vgn%% *} 107 vgnp=${vgn##* } 108 lv=$(echo "$fsys" |grep -v "swap" |grep "${vgdev}/.*[[:space:]]*.*${vgdev}"|sort|tail -n 1) 109 fs=$(echo "$fsys" |grep -v "swap" |grep "${vgdev}/.*[[:space:]]*filesystem"|sort|tail -n 1) 110 fstype=$(echo "$fs" | awk '{print $3}') 111 112 IFS=',' array=($vgnp) ; unset IFS 113 len=${#array[@]} 114 pdevlast=${array[@]: -1} 115 pdev1st=${array[0]} 116 # a bug for virt-filesystems 117 if [[ "$pdevlast" == "$pdev1st" && $len -gt 0 ]] ; then 118 base=${pdev1st%%[[:digit:]]*} 119 idx=${pdev1st##${base}} 120 idx=$(($len -1 + $idx)) 121 # echo $pdev1st $base $idx 122 pdevlast=${base}${idx} 123 fi 124 # echo $vgdev: $vgnp: $lv: $fs: $fstype, $len, $pdevlast $pdev1st 125 echo "${lv%% *}, $fstype, $pdev1st, $pdevlast" 126 } 127 128 129 # resize_dom_lvm domain script_file size_G # only test on centos7.9 130 function resize_dom_lvm(){ 131 # $1 domain name $2 size $3 disk $4 volume # $5 resize script 132 check_resize_dom_lvm_1st_arg $1 133 ret=$? 134 [[ $ret -ne 0 ]] && return $ret 135 136 [[ ! -f "$1" && "running" == "$(virsh domstate $1)" ]] && echo "The vm in running, exit" && ret=1 137 [[ $ret -ne 0 ]] && return $ret 138 139 [[ -f "$1" ]] && img=$1 || img=$(get_dom_1st_disk $1) 140 141 check_resize_dom_lvm_2st_arg $img $2 142 ret=$? 143 [[ $ret -ne 0 ]] && return $ret 144 size=${2:-20G} 145 img_size=$(qemu-img info --output json $img | grep "virtual-size" | awk -F"[,:]" '{print $2}') 146 osize=$(($img_size/1024/1024/1024)) 147 nsize=${size%%[^0-9]*} 148 [[ "$(($osize + 1))" -gt "$nsize" ]] && echo "The original image size is ${osize}G. Please imput a bigger size." && return 1 149 150 lvinfo=$(parser_disk_lv_info $1) 151 IFS=', ' array=($lvinfo); unset IFS 152 lvroot=${4:-${array[0]}} 153 fstype=${array[1]} 154 pv_disk=${3:-${array[2]}} 155 [[ "xfs" == "$fstype" ]] && fs_cmd=xfs_growfs || fs_cmd=resize2fs 156 script=$(gen_resize_lvm_script $fs_cmd $lvroot) 157 # virt-sysprep can also works 158 # [[ -f "$1" ]] && virt-customize -a $1 --firstboot $script || virt-customize -d $1 --firstboot $script 159 160 tmp_img=${img%/*}/temporary.${img#*.} 161 echo "qemu-img create -f qcow2 -o preallocation=metadata $tmp_img $size" 162 echo "Generate a intermediate images: $tmp_img" 163 qemu-img create -f qcow2 -o preallocation=metadata $tmp_img $size 164 165 virt-filesystems --long -h --all -a $img 166 # https://blog.csdn.net/tutucute0000/article/details/38414449 167 echo "virt-resize --expand $pv_disk --LV-expand $lvroot $img $tmp_img" 168 virt-resize --expand $pv_disk --LV-expand $lvroot "$img" "$tmp_img" 169 echo "virt-customize -a $tmp_img --run $script" 170 virt-customize -a $tmp_img --run $script 171 virt-filesystems --long -h --all -a $tmp_img 172 if [[ $ret -eq 0 ]] ; then 173 echo "mv $tmp_img $img -f" 174 mv $tmp_img $img -f 175 else 176 echo "NOTE: Please double chech and run the follow command manually!" 177 echo " mv $tmp_img $img -f" 178 fi 179 }
v1.0
1 # resize_dom_lvm domain script_file size_G # only test on centos7.9 2 function resize_dom_lvm(){ 3 # $1 domain name $2 size $3 disk $4 volume # $5 resize script 4 if [ -z "$1" ]; then 5 virsh list --all 6 echo "usage:" 7 echo " resize_dom_disk domain|file size_G disk volume script_file " 8 return 1 9 fi 10 11 if [ -f "$1" ]; then 12 img=$1 13 else 14 [[ "running" == "$(virsh domstate $1)" ]] && echo "The vm in running, exit" && return 1 15 FIRST_DISK_EXP='//disk[1][@device="disk"]/source/@file' 16 tmpxml=/tmp/vir_domain/tmp.xml 17 mkdir -p /tmp/vir_domain 18 virsh dumpxml $1 > $tmpxml 19 img=$(xmllint --xpath $FIRST_DISK_EXP $tmpxml | awk -F'[="]' '!/>/{print $(NF-1)}') 20 fi 21 22 if [ -z "$2" ]; then 23 echo "Error: missing the size parameters(\$2): " 24 virt-filesystems --long -h --all -a $img 25 echo "generate resize script by this command:" 26 echo " gen_resize_lvm_script" 27 echo "and check the script by the above infromation" 28 return 1 29 fi 30 31 echo $img 32 fsys=$(virt-filesystems --long -h --all -a $img) 33 pvn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9 ]*pv"|sort|tail -n 1) 34 pvndev=$(echo "$pvn" | awk '{print $1}') 35 # disk=${3:-/dev/sda2} 36 pvndev=${3:-$pvndev} 37 38 vgn=$(echo "$fsys" |grep -o "/dev/[A-Za-z1-9]*[[:space:]]*vg"|sort|tail -n 1) 39 vgdev=$(echo "$vgn" | awk '{print $1}') 40 41 lv=$(echo "$fsys" |grep "${vgdev}/root[[:space:]]*.*${vgdev}"|sort|tail -n 1) 42 lvroot=$(echo "$lv" | awk '{print $1}') 43 lvroot=${4:-$lvroot} 44 45 fs=$(echo "$fsys" |grep "${lvroot}[[:space:]]*filesystem") 46 fstype=$(echo "$fs" | awk '{print $3}') 47 48 echo $pvn, $vgn, $fs, $vgdev 49 echo $pvndev, $lvroot, $fstype 50 51 52 # virt-sysprep can also works 53 [[ "xfs" == "$fstype" ]] && fs_cmd=xfs_growfs || fs_cmd=resize2fs 54 script=$(gen_resize_lvm_script $fs_cmd $lvroot) 55 # [[ -f "$1" ]] && virt-customize -a $1 --firstboot $script || virt-customize -d $1 --firstboot $script 56 57 58 tmp_img=${img%/*}/temporary.${img#*.} 59 rm "$tmp_img" -f 60 mv $img $tmp_img -f 61 rm "$img" -f 62 63 size=${2:-20G} 64 echo "qemu-img create -f qcow2 -o preallocation=metadata $img $size" 65 qemu-img create -f qcow2 -o preallocation=metadata $img $size 66 67 virt-filesystems --long -h --all -a $tmp_img 68 69 lv_disk=${lvroot:-/dev/centos/root} 70 # https://blog.csdn.net/tutucute0000/article/details/38414449 71 echo "virt-resize --expand $pvndev --LV-expand $lv_disk $tmp_img $img" 72 virt-resize --expand $pvndev --LV-expand $lv_disk "$tmp_img" "$img" 73 [[ -f "$1" ]] && virt-customize -a $1 --run $script || virt-customize -d $1 --run $script 74 virt-filesystems --long -h --all -a $img 75 }
Inject ssh key
function inject_ssh_key(){ # $1 domain, $2 USER $3 Key path USER=${2:-$USER} USER=${USER:-root} KEY=$(realpath ~/.ssh/id_rsa.pub) # echo $KEY FILENAME=${3:-$KEY} [[ "$USER" == "root" ]] && KEYPATH="/root/.ssh/" || KEYPATH="/home/$USER/.ssh/" # These 2 commands does not works # https://bugzilla.redhat.com/show_bug.cgi?id=1378311 virt-customize -d $1 --ssh-inject $USER:file:$FILENAME --selinux-relabel # virt-sysprep -d $1 --ssh-inject $USER:file:$FILENAME # virt-copy-in -d $1 $KEY $KEYPATH }