create-host 基于 libvirt、qcow2 模板一键生成虚拟机脚本

#!/bin/bash

# qcow2 模板文件路径和md5
#qcow2TemplatePath=/var/lib/libvirt/images/wangrui/CentOS-7.0.2009-template-none-50G.qcow2
#qcow2TemplateMD5=4941c69a7e0c3b09ec6768a9cd408af7
qcow2TemplatePath=/var/lib/libvirt/images/jiahong/kylin_server_10.2-esxi-100g.qcow2
qcow2TemplateMD5=247606d55a7804fffb90faa9cc2f29fa

# qcow2 模板密码
password=123@abc.com
# qcow2 模板磁盘大小,单位GB
diskSize=100
# qcow2 模板网卡文件名
ETH_FILE_NAME=ifcfg-eth0

# kvm虚拟机存放路径
BASE_PATH=/var/lib/libvirt/images/wangrui
# kvm虚拟机名称前缀
VIRSH_HOSTNAME_PREFIX=wangrui

# IP 前缀,如:172.16.20,只要两个点
IP_PREFIX=172.16.20
# 网关
GATEWAY=172.16.20.254
# 子网掩码
NETMASK=255.255.255.0
# DNS
DNS=172.16.20.150

# CPU 核数
cpuNumber=2
# 内存大小,单位GB
memorySize=4

# kvm虚拟机创建完后ping的次数
PING_COUNT=20

# 打印正常日志
printInfo() {
  echo "INFO: $1"
}

# 打印错误日志
printError() {
  echo "ERROR: $1"
  echo
  exit 1
}

printWelcome() {
  echo -e "\n-------------------- kvm 虚拟机创建程序 (by 王睿) start --------------------\n"
}

# 检测文件MD5
checkMD5sum() {
  echo -e "虚拟机模板文件: ${qcow2TemplatePath}\n"
  if [ -a $2 ]; then
    echo -e "qcow2文件md5检测\n"
    if [ "$1" != "$(md5sum $2|cut -d ' ' -f1)" ]; then
      printError "md5不一致,程序退出"
    fi
  else
    printError "文件: $2 不存在"
  fi
}

# 输入机器配置
inputHostConfig() {
  echo
  echo -n "请输入CPU核数(默认值 $cpuNumber): "
  read _cpuNumber
  echo
  echo -n "请输入内存大小(单位GB, 默认值 $memorySize): "
  read _memorySize
  if [ "" != "$_cpuNumber" ]; then cpuNumber="$_cpuNumber"; fi
  if [ "" != "$_memorySize" ]; then memorySize="$_memorySize"; fi
}

# 主机检测
hostCheck() {
  echo -e "\n主机IP可用性检测"
  for I in $(seq 120 253)
  do
    IP="${IP_PREFIX}.$I"
    HOSTNAME="host-${IP//./-}"
    result=$(echo $(virsh list --all) | grep "${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME}")
    if [ "$result" != "" ]; then continue; fi
    if [ -d "${BASE_PATH}/${HOSTNAME}" ]; then continue; fi
    if [ -f "${BASE_PATH}/${HOSTNAME}" ]; then continue; fi
    ping -c 1 $IP &> /dev/null
    if [ $? -ne 0 ]; then break; fi
  done
  echo -e "\n分配IP为: ${IP}"
}

# 创建主机
createHost() {
  hostQcow2File=${BASE_PATH}/${HOSTNAME}/${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME}.qcow2
  mkdir -p ${BASE_PATH}/${HOSTNAME}
  cp ${qcow2TemplatePath} $hostQcow2File
  chmod 644 ${BASE_PATH}/${HOSTNAME}/${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME}.qcow2
  echo -e "\n当前主机使用qcow2: ${hostQcow2File}"
  virt-install \
  --virt-type kvm \
  --name ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME} \
  --memory $((memorySize * 1024)) \
  --vcpus ${cpuNumber} \
  --import \
  --hvm \
  --disk ${BASE_PATH}/${HOSTNAME}/${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME}.qcow2 \
  --noreboot \
  --bridge=br1 \
  --graphics vnc,listen=0.0.0.0 \
  --video vga \
  --noautoconsole \
  --os-type=generic
}

# 修改配置
updateHostConfig() {
  mkdir ${BASE_PATH}/${HOSTNAME}/etc
  virt-copy-out -d ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME} /etc/hostname /etc/sysconfig/network-scripts/${ETH_FILE_NAME} ${BASE_PATH}/${HOSTNAME}/etc
    
   echo "${HOSTNAME}" > ${BASE_PATH}/${HOSTNAME}/etc/hostname
   echo "TYPE=Ethernet" > ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
   echo "BOOTPROTO=static" >> ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
   echo "ONBOOT=yes" >> ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
   echo "DEVICE=eth0" >> ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
   echo "PREFIX=24" >> ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
  echo "IPADDR=${IP}" >> ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
  echo "GATEWAY=${GATEWAY}" >> ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
  echo "NETMASK=${NETMASK}" >> ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
  echo "DNS1=${DNS}" >> ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
#  sed -i 's/ONBOOT=no/ONBOOT=yes/g' ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
#  sed -i 's/BOOTPROTO=dhcp/BOOTPROTO=static/g' ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME}
  
  virt-copy-in -d ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME} ${BASE_PATH}/${HOSTNAME}/etc/hostname /etc
  virt-copy-in -d ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME} ${BASE_PATH}/${HOSTNAME}/etc/${ETH_FILE_NAME} /etc/sysconfig/network-scripts
  # updateShadowFile
  rm -rf ${BASE_PATH}/${HOSTNAME}/etc
}

# 更新影子文件(TODO 异常,拷贝进去没用)
updateShadowFile() {
  shadowTempFile="${BASE_PATH}/${HOSTNAME}/shadow-temp"
  > ${shadowTempFile}
  cat "${BASE_PATH}/${HOSTNAME}/shadow" | while read line
  do
  if [[ "${line}" =~ ^'root:'.* ]]; then
      suffix=${line#*:}
      suffix=${suffix#*:}
      line="root:$(openssl ${password} -6 123@abc.com):${suffix}"
  fi
  echo ${line} >> ${shadowTempFile}
  done
  rm ${BASE_PATH}/${HOSTNAME}/shadow
  mv ${BASE_PATH}/${HOSTNAME}/shadow-temp ${BASE_PATH}/${HOSTNAME}/shadow
  virt-copy-in -d ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME} ${BASE_PATH}/${HOSTNAME}/shadow /etc
}

# 启动虚拟机
startupHost() {
  virsh start ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME}
}

# 打印成功信息
printSuccessInfo() {
  echo -e "虚拟机 ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME} 创建并启动成功, 详细配置如下:\n"
  echo -e "主机名: \t${HOSTNAME}"
  echo -e "IP: \t\t${IP}"
  echo -e "root密码: \t${password}"
  echo -e "CPU: \t\t${cpuNumber}核"
  echo -e "内存: \t\t${memorySize}GB"
  echo -e "磁盘: \t\t${diskSize}GB"
  echo
  
  echo -e "重命名域请执行如下命令(重命名后记得 virsh start 启动域):"
  echo -e "  virsh destroy ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME}"
  echo -e "  virsh domrename ${VIRSH_HOSTNAME_PREFIX}-${HOSTNAME} <new-name>"
  
  echo -e "\nTODO: 磁盘扩容待完善"
  echo -e "\n-------------------- kvm 虚拟机创建程序 (by 王睿)  end --------------------\n"
}

# 主机ping检测
hostPingCheck() {
  i=0
  while true
  do
    ((i++))
    ping -c 1 $IP &> /dev/null
    if [ $? -eq 0 ]
      then break
    else
      echo "第$i次 ping $IP 失败"
      if [ $i -eq "${PING_COUNT}" ]; then echo; printError "ping ${PING_COUNT}次 均失败, 不再尝试"; break; fi
    fi
  done
  echo -e "\n主机已ping通,请使用ssh终端连接: $IP\n"
}

printWelcome
checkMD5sum $qcow2TemplateMD5 $qcow2TemplatePath
echo -e "qcow2文件md5符合预期, 开始kvm虚拟机创建流程"
inputHostConfig
hostCheck
if [ $? -ne 0 ]; then printError "hostCheck 函数异常退出,程序中止"; fi

createHost
if [ $? -ne 0 ]; then printError "createHost 函数异常退出,程序中止"; fi

updateHostConfig
if [ $? -ne 0 ]; then printError "updateHostConfig 函数异常退出,程序中止"; fi

startupHost
if [ $? -ne 0 ]; then printError "startupHost 函数异常退出,程序中止"; fi

printSuccessInfo
if [ $? -ne 0 ]; then printError "printSuccessInfo 函数异常退出,程序中止"; fi

hostPingCheck

 

posted @ 2022-08-25 14:58  Nihaorz  阅读(152)  评论(0)    收藏  举报