[工具] Shell 批量克隆 KVM 虚拟机 (中文版)

注意:

在克隆 KVM 虚拟机之前要先安装 KVM 、创建 KVM 虚拟网络和 KVM 模板机

正文:

介绍

基本信息

作者:朱明宇
名称:批量克隆 KVM 虚拟机(中文版)
作用:批量克隆 KVM 虚拟机(中文版)

使用方法

1. 在此脚本的分割线内写入相应的内容
2. 给此脚本添加执行权限
3. 执行此脚本

脚本分割线里的变量

1. templatedisk=”/test/kvm/images/rockylinux8.qcow2″ #模板机硬盘文件
2. templatexml=”/test/kvm/qemu/rockylinux8.xml” #模板机 xml 文件
3. templatename=”rockylinux8″ #模板机在 KVM 域中的名称
4. newdiskpath=”/test/kvm/images/” #新模版机硬盘文件目录
5. newxmlpath=”/test/kvm/qemu/” #新模版机硬盘文件目录

注意

1. 在执行此脚本之前要先安装 KVM
2. 在执行此脚本之前要先准备好模板机的硬盘文件和 xml 文件
3. 请以 root 的权限执行次脚本

脚本

#!/bin/bash
#作者:朱明宇
#名称:批量克隆 KVM 虚拟机
#作用:批量克隆 KVM 虚拟机
#使用方法:
#1.在此脚本的分割线内写入相应的内容
#2.给此脚本增加执行权限
#3.执行此脚本
#注意:
#1.在执行此脚本之前要先安装 KVM
#2.在执行此脚本之前要先准备好模板机的硬盘文件和 xml 文件
#3.请以 root 的权限执行次脚本

###此为分割线,分割线里的内容可让懂 Shell 用户自行修改,如果你不懂 Shell 请勿修改###

templatedisk="/test/kvm/images/rockylinux8.qcow2" #模板机硬盘文件
templatexml="/test/kvm/qemu/rockylinux8.xml" #模板机 xml 文件
templatename="rockylinux8" #模板机在 KVM 域中的名称
newdiskpath="/test/kvm/images/" #新模版机硬盘文件目录
newxmlpath="/test/kvm/qemu/" #新模版机硬盘文件目录

###此为分割线,分割线里的内容可让懂 Shell 用户自行修改,如果你不懂 Shell 请勿修改###

echo

mkdir $newdiskpath &> /dev/null

sudo systemctl start libvirtd &> /dev/null
if [ $? -ne 0 ];then
	echo
	echo -e "\033[31m你没有安装 KVM 或者你没有以 root 权限执行次脚本,脚本无法执行\033[0m"
	exit
fi

ls $templatedisk &> /dev/null
if [ $? -ne 0 ];then
        echo
        echo -e "\033[31m模版机硬盘文件不存在,脚本无法执行\033[0m"
        exit
fi

ls $templatexml &> /dev/null
if [ $? -ne 0 ];then
        echo
        echo -e "\033[31m模版机配置文件不存在,脚本无法执行\033[0m"
        exit
fi

sudo virsh destroy $templatename &> /dev/null
sudo virt-sysprep -d $templatename &> /dev/null
dnet=`sudo virsh net-list | sed -n 3p  | awk '{print $1}'`

read -p "将要克隆虚拟机,单独克隆一台请输入 1,批量克隆请输入任意其他字符 " cloneway
if [ ! $cloneway ];then
	echo
	echo -e "\033[31m你没有输入任何值,立刻退出\033[0m"
	exit
fi

if [ $cloneway == 1 ];then
	read -p "要克隆产生的主机名称,没有默认值必须输入一个 " onename

	echo $onename | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m要克隆产生的主机名 '$onename' 不能有空格,停止克隆\033[0m"
                exit
        fi

        if [ ! $onename ];then
		echo
                echo -e "\033[31m你没有输入要克隆产生的主机名,停止克隆\033[0m"
                exit
        fi

	sudo virsh list --all | egrep -w $onename &> /dev/null
        if [ $? -eq 0 ];then
		echo
                echo -e "\033[31m要克隆产生的主机名 '$onename' 已经存在了,停止克隆\033[0m"
                exit
        fi

        read -p "要克隆的主机所属的虚拟网络,直接回车则是选择已创建的网络中排名最靠前的 $dnet " net

        echo $net | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m网络名 '$net' 不能有空格,停止克隆\033[0m"
                exit
        fi

	read -p "要克隆产生的主机 CPU 核心数,请只输入数字,最小为 1,单位个,直接回车则是使用默认值 1 " cpu

	echo $cpu | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m CPU 核心数 '$cpu' 不能有空格,停止克隆\033[0m"
                exit
        fi

	read -p "要克隆产生的主机内存大小,请只输入数字,单位 K,直接回车则是使用默认值 1048576 " mem

        echo $mem | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m内存大小 '$mem' 不能有空格,停止克隆\033[0m"
                exit
        fi

	read -p "要克隆产生的主机硬盘大小,请只输入数字,单位 G,直接回车则是使用默认值 10 " disk

        echo $disk | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m硬盘大小 '$disk' 不能有空格,停止克隆\033[0m"
                exit
        fi

	echo
	echo "名称:"
	echo "使用主机名 '$onename'"

else
	read -p "要批量克隆产生的主机名称的前缀名称,没有默认值必须输入一个 " name

	echo $name | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m要批量克隆产生的主机名称前缀 '$name' 不能有空格,停止克隆\033[0m"
                exit
        fi


        if [ ! $name ];then
		echo
                echo -e "\033[31m你没有输入要批量克隆产生的主机名称前缀,停止克隆\033[0m"
                exit
        fi

	read -p "要批量克隆产生的主机名后缀起始编号,没有默认值必须输入一个,请只输入数字 " snum

        if [ ! $snum ];then
		echo
                echo -e "\033[31m你没有输入要批量克隆产生的主机名后缀起始编号,停止克隆\033[0m"
                exit
        fi

        echo $snum | grep '\-' &> /dev/null
        if [ $? -eq 0 ];then
		snum=${snum##*-}
                echo -e "\033[33m你输入的要批量克隆产生的主机名后缀起始编号可能是一个负数,将只使用整数部分 $snum\033[0m"
        fi

        echo $snum | grep '\.' &> /dev/null
        if [ $? -eq 0 ];then
                snum=${snum%%.*}
                echo -e "\033[33m你输入的要批量克隆产生的主机名后缀起始编号可能是一个小数,将只使用数字部分 $snum\033[0m"
        fi

        let snum+0 &> /dev/null
        if [ $? -ne 0 ];then
                echo
                echo -e "\033[31m你输入的要批量克隆产生的主机名后缀起始编号 $snum 不是数字,无法克隆\033[0m"
        exit
        fi

	read -p "要批量克隆产生的主机名后缀结束编号,没有默认值必须输入一个,请只输入数字 " enum

        if [ ! $enum ];then
                echo -e "\033[31m你没有输入要批量克隆产生的主机名后缀结束编号,停止克隆\033[0m"
        fi

	echo $enum | grep '\-' &> /dev/null
        if [ $? -eq 0 ];then
                enum=${enum##*-}
                echo -e "\033[33m你输入的要批量克隆产生的主机名后缀结束编号可能是一个负数,将只使用数字部分 $enum\033[0m"
        fi

        echo $enum | grep '\.' &> /dev/null
        if [ $? -eq 0 ];then
                enum=${enum%%.*}
                echo -e "\033[33m你输入的要批量克隆产生的主机名后缀结束编号可能是一个小数,将只使用整数部分 $enum\033[0m"
        fi

        let enum+0 &> /dev/null
        if [ $? -ne 0 ];then
                echo -e "\033[31m你输入的要批量克隆产生的主机名后缀结束编号 $enum 不是数字,无法克隆\033[0m"
                exit
        fi

        read -p "要批量克隆的主机所属的虚拟网络,直接回车则是选择已创建的网络中排名最靠前的 $dnet " net

        echo $net | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m网络名 '$net' 不能有空格,停止克隆\033[0m"
                exit
        fi

	read -p "要批量克隆产生的主机 CPU 核心数,请只输入数字,最小为 1,单位个,直接回车则是使用默认值 1 " cpu

        echo $cpu | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m CPU 核心数 '$cpu' 不能有空格,停止克隆\033[0m"
                exit
        fi

	read -p "要批量克隆产生的主机内存大小,请只输入数字,单位 K,直接回车则是使用默认值 1048576 " mem

        echo $mem | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m内存大小 '$mem' 不能有空格,停止克隆\033[0m"
                exit
        fi

	read -p "要批量克隆产生的主机硬盘大小,请只输入数字,单位 G,直接回车则是使用默认值 10 " disk

        echo $disk | grep '\ ' &> /dev/null
        if [ $? -eq 0 ];then
                echo
                echo -e "\033[31m硬盘大小 '$disk' 不能有空格,停止克隆\033[0m"
                exit
        fi

	echo
	echo "名称:"
	for i in `seq $snum $enum`
	do
	sudo virsh list --all | egrep -w $name$i &> /dev/null
	if [ $? -eq 0 ];then
		echo -e "\033[33m使用主机名 '$name$i' ,已经存在了,将跳过不克隆它\033[0m"
	else
		echo "使用主机名 '$name$i' "
	fi
        done
fi

echo

echo "网络:"

sudo virsh net-list | grep $net &> /dev/null
if [ $? -eq 0 ];then
        echo "使用网络 $net"
fi

if [ ! $net ];then
        net=`sudo virsh net-list | sed -n 3p  | awk '{print $1}'`
	echo -e "\033[33m你没有输入网络,将使用默认网络 $net\033[0m"
	echo "使用网络 $net"
fi

sudo virsh net-list | grep $net &> /dev/null
if [ $? -ne 0 ];then
        net=`sudo virsh net-list | sed -n 3p  | awk '{print $1}'`
        echo -e "\033[33m你输入的要克隆主机的所属的网络不存在,将使用默认网络 $net\033[0m"
	echo "使用网络 $net"
fi

echo

echo "CPU:"

if [ ! $cpu ];then
	cpu=1
	echo -e "\033[33m你没有输入 CPU 核心数,将使用默认 CPU 核心数 1\033[0m"
else

        echo $cpu | grep '\-' &> /dev/null
        if [ $? -eq 0 ];then
                cpu=${cpu##*-}
                echo -e "\033[33m你输入的 CPU 核心数可能是一个负数,将只使用数字部分 $cpu\033[0m"
        fi

        echo $cpu | grep '\.' &> /dev/null
        if [ $? -eq 0 ];then
                cpu=${cpu%%.*}
                echo -e "\033[33m你输入的 CPU 核心数可能是一个小数,将只使用整数部分 $cpu\033[0m"
        fi

	let cpu=cpu+0 &> /dev/null
	if [ $? -ne 0 ];then
		echo -e "\033[33m你输入的 CPU 核心数不是数字,将使用默认值 1\033[0m"
                cpu=1
	fi

	if [ $cpu -lt 1 ];then
                echo -e "\033[33m你输入的 CPU 核心数小于 1,将使用默认值 1\033[0m"
		cpu=1
	fi
fi

echo "CPU 核心数 $cpu"

echo

echo "内存:"

if [ ! $mem ];then
	mem=1048576
        echo -e "\033[33m你没有输入内存大小,将使用默认内存大小 1048576 K\033[0m"

else

        echo $mem | grep '\-' &> /dev/null
        if [ $? -eq 0 ];then
                mem=${mem##*-}
                echo -e "\033[33m你输入的内存大小可能是一个负数,将只使用数字部分 $mem\033[0m"
        fi

        echo $mem | grep '\.' &> /dev/null
        if [ $? -eq 0 ];then
                mem=${mem%%.*}
                echo -e "\033[33m你输入的内存大小可能是一个小数,将只使用整数部分 $mem\033[0m"
        fi

	let mem=mem+0 &> /dev/null
	if [ $? -ne 0 ];then
		echo -e "\033[33m你输入的内存大小不是数字,将使用默认值 1048576\033[0m"
                mem=1048576
	fi

	if [ $mem -lt 1048576 ];then
                echo -e "\033[33m你输入的内存大小小于 1048576,将使用默认值 1048576\033[0m"
		mem=1048576
	fi
fi

echo "内存大小 $mem K"

echo

echo "硬盘:"

if [ ! $disk ];then
	disk=10
        echo -e "\033[33m你没有输入硬盘大小,将使用默认硬盘大小 10 G\033[0m"

else

        echo $disk | grep '\-' &> /dev/null
        if [ $? -eq 0 ];then
                disk=${disk##*-}
                echo -e "\033[33m你输入的硬盘大小可能是一个负数,将只使用数字部分 $disk\033[0m"
        fi

        echo $disk | grep '\.' &> /dev/null
        if [ $? -eq 0 ];then
                disk=${disk%%.*}
                echo -e "\033[33m你输入的硬盘大小可能是一个小数,将只使用整数部分 $disk\033[0m"
        fi

	let disk=disk+0 &> /dev/null
	if [ $? -ne 0 ];then
		echo -e "\033[33m你输入的硬盘大小不是数字,将使用默认值 10\033[0m"
	fi

	if [ $disk -lt 10 ];then
		echo -e "\033[33m你输入的硬盘大小小于 10,将使用默认值 10\033[0m"
		disk=10
	fi
fi

echo "硬盘大小 $disk G"

echo

echo "备注(可能没有任何信息):"

if [ $cloneway -eq 1 ];then
	sudo qemu-img create -f qcow2 -F qcow2 -b $templatedisk $newdiskpath$onename.qcow2 ${disk}G &> /dev/null
	sudo cp $templatexml $newxmlpath$onename.xml
	sudo sed -i "/uuid/d" $newxmlpath$onename.xml
	sudo sed -i "/mac address/d" $newxmlpath$onename.xml
	sudo sed -i "s:<name>.*</name>:<name>$onename</name>:" $newxmlpath$onename.xml
	sudo sed -i "s:<source file=.*/>:<source file=\'$newdiskpath$onename.qcow2\'/>:" $newxmlpath$onename.xml
	sudo sed -i "s:<vcpu placement='static'>.*</vcpu>:<vcpu placement='static'>$cpu</vcpu>:" $newxmlpath$onename.xml
	sudo sed -i "s:.*</memory>:<memory unit='KB'>$mem</memory>:" $newxmlpath$onename.xml
	sudo sed -i "s:.*</currentMemory>:<currentMemory unit='KB'>$mem</currentMemory>:" $newxmlpath$onename.xml
        sudo sed -i "s:<source network=.*:<source network=\'$net\'/>:" $newxmlpath$onename.xml
	sudo virsh define $newxmlpath$onename.xml &> /dev/null
        sudo virsh start $onename &> /dev/null
	echo
	sudo virsh list --all
else
	for i in `seq $snum $enum`
	do
                sudo virsh list --all | egrep -w $name$i &> /dev/null
                if [ $? -eq 0 ];then
		      echo -e "\033[33m$name$i 没有被克隆\033[0m"
	       	      continue
                fi
		sudo qemu-img create -f qcow2 -F qcow2 -b $templatedisk $newdiskpath$name$i.qcow2 $[disk]G &> /dev/null
		sudo cp $templatexml $newxmlpath$name$i.xml
		sudo sed -i "/uuid/d" $newxmlpath$name$i.xml
		sudo sed -i "/mac address/d" $newxmlpath$name$i.xml
		sudo sed -i "s:<name>.*</name>:<name>$name$i</name>:" $newxmlpath$name$i.xml
		sudo sed -i "s:<source file=.*/>:<source file=\'$newdiskpath$name$i.qcow2\'/>:" $newxmlpath$name$i.xml
		sudo sed -i "s:<vcpu placement='static'>.*</vcpu>:<vcpu placement='static'>$cpu</vcpu>:" $newxmlpath$name$i.xml
		sudo sed -i "s:.*</memory>:<memory unit='KB'>$mem</memory>:" $newxmlpath$name$i.xml
		sudo sed -i "s:.*</currentMemory>:<currentMemory unit='KB'>$mem</currentMemory>:" $newxmlpath$name$i.xml
                sudo sed -i "s:<source network=.*:<source network=\'$net\'/>:" $newxmlpath$name$i.xml
	        sudo virsh define $newxmlpath$name$i.xml &> /dev/null
                sudo virsh start $name$i &> /dev/null
      done
      echo
      sudo virsh list --all
fi