#!/bin/bash
if [[ $# -lt 5 ]];then
    echo -e "\033[32m Usage: ./create.sh IP/nm cpu memory disk OS uuid mac1 mac2 mac3 idc usage secusage\033[0m"
    exit 1
fi

logger(){
    echo [$1] $2
    echo `date +"%Y-%m-%d %H:%M:%S "` [$1] $2 >> /tmp/$hostname.log
    if [[ ($1 != 'debug') && ( -n $u_uuid ) ]];then
        curl http://vm-mgr.service.ucloud.cn/vm-mgr/v1/vm/receive -X POST -H 'Content-Type:application/json' -d "{\"Action\":\"create\",\"UID\":\"$u_uuid\",\"SubStatus\":\"$1\",\"Info\":\"$2\"}"
    fi
    if [[ $1 = 'success' ]];then
        exit 0
    elif [[ $1 = 'failed' ]];then
        exit 1
    fi
} 

# get all conf
u_uuid=$6
hostname=$u_uuid
ipcalc -c $1
if [[ $? -ne 0 ]]; then
    logger "failed" "Validate IP address $1 failed"
fi

ipaddr=`echo $1|cut -f1 -d'/'`
hostname=`echo $ipaddr|tr . -`
nm=`echo $1|cut -f2 -d'/'`
netmask=`ipcalc -m $ipaddr/$nm|awk -F '=' '{print $2}'`
ga1=`ipcalc -n $ipaddr/$nm|awk -F '=' '{print $2}'|awk -F '.' '{print $1"."$2"."$3}'`
ga2=`ipcalc -n $ipaddr/$nm|awk -F '=' '{print $2}'|awk -F '.' '{print $4}'`
if [[ -z $ga1 || -z $ga2 ]];then
    logger "failed" "Validate IP address $1 failed"
fi
ga3=$(($ga2 + 1))
gateway="$ga1.$ga3"
dns1=`grep ^nameserver /etc/resolv.conf |head -1|awk '{ print $2 }'`
dns2=`grep ^nameserver /etc/resolv.conf |head -2|tail -1|awk '{ print $2 }'`

cpucores=$2
msize=$(($3 * 1048576))
dsize=$4
os=$5
case $os in
   CentOS6.3) img='CentOS6.3.img' ;;
   CentOS7.4-kernel-4.1.0) img='CentOS7.4.img-4.1.0-30-1'  ;;
   CentOS7.4) img='CentOS7.4.img'  ;;
   Rocky9.4-Beta)  img='Rocky9.4.img' ;;
   Windows2012) img='Windows2012.img' ;;
   Windows2016) img='windows-2016-zh-20190118-b5850041228840d360710e2b25df1473.qcow2' ;;
   Windows2019) img='Windows2019.img' ;;
   Windows2022) img='windows-2022.zh-20221108-d61d6444417ba8e72d75052c550e0d55.qcow2' ;;
   *)
       echo "not support os $os!"
       exit 1 ;;
esac

echo `date +"%Y-%m-%d %H:%M:%S "` "start"  > /tmp/$hostname.log
_1macaddr=$7
_2macaddr=$8
_3macaddr=$9

# check ip
ping -n -c 1 -w 5 $ipaddr
if [[ $? -eq 0 ]]; then
    logger "failed" "ip is used"
fi

lscpu >/dev/null
if [[ $? -ne 0 ]]; then
    logger "failed" "lscpu can not run"
fi

lscpu|grep "Model name"|grep "AMD"
IS_AMD=$?

lscpu|grep "Model name"|grep "Intel"|grep "6126\|6146"
IS_Skylake=$?
# 不给v5机器了，没法往旧机型迁移,虚机不能开V5 cpu特性
IS_Skylake=1

# 根据CPU型号确定feature。不是最佳实践，需要参考主机的生成逻辑。暂时枚举。
cpu_model_name=`lscpu | grep 'Model name' | awk -F ':' '{print $2}' | sed 's/^ *//'`

#check /opt/data
mount |grep -q '/opt/data'
if [[ $? -ne 0 ]];then
    logger "failed" "'/opt/data/' not in mount!"
fi

#create the img dir
dirname=$hostname'img'
if [ -d "/opt/data/$dirname" ]; then
    logger "failed" "this host already existed"
fi
mkdir -p /opt/data/$dirname

create_xml() {
if [[ $u_uuid != '' ]];then
    uuid="<uuid>$u_uuid</uuid>"
fi

#machine_type="<type arch='x86_64' machine='pc-i440fx-rhel7.5.0'>hvm</type>"
machine_type="<type arch='x86_64' machine='pc'>hvm</type>"

if [[ $IS_AMD -eq 0 ]];then
    features="<qemu_cpu>
      <legacy-cache state='off'/>
      <xlevel state='on' value='0x8000001e'/>
    </qemu_cpu>"
    cpu_mode="<cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>EPYC</model>
    <topology sockets='1' cores='$(($cpucores/2))' threads='2'/>
    <feature policy='require' name='topoext'/>
    <feature policy='require' name='hypervisor'/>
    <feature policy='require' name='x2apic'/>
    <feature policy='disable' name='svm'/>
    <feature policy='disable' name='monitor'/>
  </cpu>"
elif [[ $os == "Rocky9.4-Beta" ]];then
    if [[ "$cpu_model_name" =~ "Intel(R) Xeon(R) CPU E5-2650 v4" ]];then
        cpu_mode="<cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>Broadwell-noTSX</model>
    <feature policy='require' name='vme'/>
    <feature policy='require' name='f16c'/>
    <feature policy='require' name='rdrand'/>
    <feature policy='require' name='hypervisor'/>
    <feature policy='require' name='arat'/>
    <feature policy='require' name='xsaveopt'/>
    <feature policy='require' name='kvm-asyncpf'/>
    <feature policy='require' name='kvm-pv-eoi'/>
    <feature policy='require' name='kvm-pv-unhalt'/>
    <feature policy='require' name='abm'/>
  </cpu>"
    fi
fi

# 仅用于test05 rocy9虚拟机测试，不能用于生产环境
idc=`echo $HOSTNAME | awk -F '-' '{print $1}'`
if [[ $idc == "test05" ]];then
	cpu_mode="<cpu mode='host-passthrough' check='partial'/>"
fi


disk_vdb="
<disk type='file' device='disk'>
    <driver name='qemu' type='qcow2' cache='writethrough'/>
    <source file='/opt/data/${hostname}img/$hostname.disk'/>
    <target dev='vdb' bus='virtio'/>
    <serial>UCLOUD-LOCAL-SDB</serial>
    <alias name='virtio-disk1'/>
</disk>
"

if [[ $_1macaddr != '' ]];then
    mac1="<mac address='${_1macaddr}'/>"
fi
if [[ $_2macaddr != '' ]];then
    mac2="<mac address='${_2macaddr}'/>"
fi
if [[ $_3macaddr != '' ]];then
    mac3="<mac address='${_3macaddr}'/>"
fi

vm_xml="<domain type='kvm'>
  <name>$hostname</name>
  $uuid
  <memory unit='KiB'>$msize</memory>
  <currentMemory unit='KiB'>$msize</currentMemory>
  <vcpu placement='static'>$cpucores</vcpu>
  <os>
  $machine_type
    <boot dev='hd'/>
    <boot dev='cdrom'/>
    <boot dev='network'/>
    <bootmenu enable='no'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
    $features
  </features>
  $cpu_mode
  <clock offset='utc'/>
  <on_poweroff>preserve</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='writethrough'/>
      <source file='/opt/data/${hostname}img/${hostname}.img'/>
      <target dev='vda' bus='virtio'/>
      <serial>UCLOUD-LOCAL-SDA</serial>
      <alias name='virtio-disk0'/>
    </disk>
    $disk_vdb
    <controller type='usb' index='0'>
      <alias name='usb0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <interface type='bridge'>
      $mac1
      <source bridge='manbr'/>
      <virtualport type='openvswitch'/>
      <model type='virtio'/>
      <driver name='vhost' queues='4'/>
    </interface>
    <interface type='bridge'>
      $mac2
      <source bridge='wanbr'/>
      <virtualport type='openvswitch'/>
      <model type='virtio'/>
      <driver name='vhost' queues='4'/>
    </interface>
    <interface type='bridge'>
      $mac3
      <source bridge='br0'/>
      <virtualport type='openvswitch'/>
      <model type='virtio'/>
      <driver name='vhost' queues='4'/>
    </interface>
    <serial type='pty'>
      <target type='isa-serial' port='0'>
        <model name='isa-serial'/>
      </target>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
    <input type='tablet' bus='usb'>
      <address type='usb' bus='0' port='1'/>
    </input>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='-1' autoport='yes' />
    <video>
      <model type='vga' vram='65536' heads='1'/>
      <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='none'/>
</domain>"

echo "$vm_xml" > /opt/data/$dirname/$hostname.xml

}

copy_create_img() {
logger "debug" "copy the img file"

bash <(curl -s http://softlib.service.ucloud.cn/usa/vmzone/Templateimg/checkfile.sh) /opt/data/Templateimg/${img}

if [[ $? -ne 0 ]];then
    logger "failed" "check img failed!"
fi

cp /opt/data/Templateimg/${img} /opt/data/$dirname/$hostname.img
if [[ $? -eq 0 ]];then
    logger "debug" "copy img done!"
else
    logger "failed" "copy img failed!"
fi

qemu-img create -f qcow2 -o preallocation=metadata /opt/data/$dirname/$hostname.disk ${dsize}G
disk_result=$?

if [[ $disk_result -eq 0 ]];then
    logger "debug" "create data disk done!"
else
    logger "failed" "create data disk failed!"
fi
}

guestmount_modify_conf() {
    logger "debug" "guestmount to config"

    mountdir="/opt/op/$hostname"
    mkdir -p /opt/op/$hostname
    #mount img and modify hostname,ipaddr
    logger "debug" "start guestmount"
#    modprobe nbd
#    for i in {0..15}
#    do
#        nbd_dev="/dev/nbd$i"
#        if [[ -b $nbd_dev ]];then
#            lsof $nbd_dev
#            if [[ $? -ne 0 ]];then
#                break
#            fi
#        fi
#        nbd_dev=''
#    done
#    if [[ -n $nbd_dev ]];then
#        qemu-nbd -c $nbd_dev /opt/data/$dirname/$hostname.img
#    else
#        logger "debug" "nbd device not find"
#    fi
#    sleep 10
#    if [[ -b ${nbd_dev}p2 ]];then
#        mount ${nbd_dev}p2 $mountdir
#        mount_result=$?
#    else
#        mount ${nbd_dev}p1 $mountdir
#        mount_result=$?
#    fi
    mount_result=1
    if [[ $mount_result -ne 0 ]]; then
#        qemu-nbd -d $nbd_dev
#        logger "debug" "$nbd_dev mount failed"
        guestmount -a /opt/data/$dirname/$hostname.img -i $mountdir
        if [[ $? -ne 0 ]];then
            logger "failed" "guestmount failed"
        fi
    fi
    tmpHost="$mountdir/etc/sysconfig/network" 
    tmpIp="$mountdir/etc/sysconfig/network-scripts/ifcfg-eth0"

    if [[ $os = "Windows2016" || $os = 'Windows2019' ]];then
        tmpBat="$mountdir/bootstrap.bat"
    
        cat > $tmpBat <<EOF
netsh interface ip set address name="以太网 3" source=static address=$ipaddr mask=$netmask gateway=$gateway
netsh interface ip set dns name="以太网 3" source=static address="$dns1"
netsh interface ip add dns name="以太网 3" address="$dns2"

netsh advfirewall set allprofiles state off

net user Administrator ucloud12#$

del %0 | move *.* d:\

EOF
        iconv -f utf8 -t gbk -o ${tmpBat}.tmp $tmpBat
        mv ${tmpBat}.tmp $tmpBat
        unix2dos $tmpBat

    elif [[ $os = 'Windows2022' ]];then
        tmpBat="$mountdir/bootstrap.bat"

        cat > $tmpBat <<EOF
netsh interface ip set address name="以太网 2" source=static address=$ipaddr mask=$netmask gateway=$gateway
netsh interface ip set dns name="以太网 2" source=static address="$dns1"
netsh interface ip add dns name="以太网 2" address="$dns2"

netsh advfirewall set allprofiles state off

net user Administrator ucloud12#$

del %0 | move *.* d:\

EOF
        iconv -f utf8 -t gbk -o ${tmpBat}.tmp $tmpBat
        mv ${tmpBat}.tmp $tmpBat
        unix2dos $tmpBat

    elif [[ $os = "Windows2012" ]];then
        tmpBat="$mountdir/Windows/setip.bat"
    
        cat > $tmpBat <<EOF
@echo off
cmd /c netsh interface ip set address name="eth0" source=static addr=$ipaddr mask=$netmask gateway=$gateway
cmd /c netsh interface ip set dns name="eth0" source=static addr="$dns1"
cmd /c netsh interface ip add dns name="eth0" addr="$dns2"

ipconfig /all

net user Administrator ucloud12#$

del %0 | move *.* d:\

EOF

    elif [[ $os =~ "CentOS" ]];then
        if [ $os = "CentOS6.3" ];then
            sed -i "s/HOSTNAME=.*/HOSTNAME=$hostname/g" $tmpHost
        else
            echo "$hostname" > $mountdir/etc/hostname
        fi

        cat > $tmpIp <<EOF
DEVICE="eth0"
BOOTPROTO="static"
TYPE="Ethernet"
ONBOOT="yes"
IPADDR=$ipaddr
NETMASK=$netmask
GATEWAY=$gateway
EOF

############ ipv6 set ##############

ifcfgv6=$mountdir'/etc/sysconfig/network-scripts/ifcfg-sit6to4'
routev6=$mountdir'/etc/sysconfig/network-scripts/route6-sit6to4'
SYSCTL=$mountdir'/etc/sysctl.conf'

IPV4=$ipaddr

IPV6=2002:`echo "${IPV4}" |awk -F '.' '{printf "%02x%02x:%02x%02x\n",$1,$2,$3,$4}'`::1

sed -i --follow-symlinks "/net\.ipv6\.conf\.all\.disable_ipv6.*/d" $SYSCTL

cat > $ifcfgv6 <<EOF
DEVICE=sit6to4
TYPE=sit
ONBOOT=yes
NM_CONTROLLED=no
BOOTPROTO=static
IPV6INIT=yes
IPV6TUNNELIPV4=any
IPV6TUNNELIPV4LOCAL=$IPV4
IPV6ADDR=$IPV6/128
EOF

cat > $routev6 <<EOF
2002:c0a8::/32 dev sit6to4 src $IPV6 metric 8
2002:ac10::/28 dev sit6to4 src $IPV6 metric 8
2002:a00::/24 dev sit6to4 src $IPV6 metric 8
2002:6460::/27 dev sit6to4 src $IPV6 metric 8
EOF


        #add key
        mkdir $mountdir/root/.ssh 2>/dev/null
        #echo "ssh-rsa [payload removed: 372 characters] root@UCloud-Servers" >> $mountdir/root/.ssh/authorized_keys
     echo "ssh-rsa [payload removed: 544 characters] isl_sod@ucloud.cn_UcloudServers-v2-2022-10-17" > $mountdir/root/.ssh/authorized_keys
     echo "ssh-rsa [payload removed: 372 characters] root@10-81-96-153"  >> $mountdir/root/.ssh/authorized_keys
        # auto mount vdb

        cat > $mountdir/tmp/add_disk.sh <<EOF
#!/bin/bash

vdb_exist=\`lsblk|grep -i vdb\`
vdb_ext4_exist=\`blkid|grep -i vdb\`

if [ -n "\$vdb_exist" ] && [ -z "\$vdb_ext4_exist" ];then
    mkfs.ext4 -O extent -b 4096 -E stride=128,stripe-width=128 /dev/vdb
    mkdir /data
    mount /dev/vdb /data/
    echo '/dev/vdb                /data                   ext4    defaults,noatime  0 0' >> /etc/fstab
fi
sed -i.bak -c '/add_disk.sh/d' /etc/rc.d/rc.local
EOF

        echo '/bin/bash -x /tmp/add_disk.sh' >> $mountdir/etc/rc.d/rc.local
        chmod +x $mountdir/etc/rc.d/rc.local

        #复制宿主的dns配置
        cp -f /etc/resolv.conf $mountdir/etc/resolv.conf

        ## 清理模板中的历史操作
        echo ''> $mountdir/etc/udev/rules.d/70-persistent-net.rules
        echo ''> $mountdir/root/.bash_history
        echo ''> $mountdir/var/log/wtmp
        echo ''> $mountdir/var/log/btmp
        sed -i "/vdb/d" $mountdir/etc/fstab
``
    fi

    sync
    umount $mountdir
    sleep 10

    if [[ -n $nbd_dev ]];then
        qemu-nbd -d $nbd_dev
        if [ $? -ne 0 ];then
            logger "failed" "failed to disconnect $nbd_dev"
        fi
    fi

    rmdir $mountdir

    if [ $? -ne 0 ];then
        logger "failed" "failed to clean up mount point"
    fi
}

rocky9_first_init() {

    bash <(curl -s http://softlib.service.ucloud.cn/usa/vmzone/Templateimg/checkfile.sh) /opt/data/Templateimg/vmlinuz-6.6.1-1.el9.ucloud.x86_64

    bash <(curl -s http://softlib.service.ucloud.cn/usa/vmzone/Templateimg/checkfile.sh) /opt/data/Templateimg/initramfs-6.6.1-1.el9.ucloud.x86_64.img

   # /usr/bin/qemu-system-x86_64  -enable-kvm -cpu host -m 2048  \
   #     -kernel /opt/data/Templateimg/vmlinuz-6.6.1-1.el9.ucloud.x86_64 \
   #     -initrd /opt/data/Templateimg/initramfs-6.6.1-1.el9.ucloud.x86_64.img \
   #     -append "root=/dev/sda1 ip=$ipaddr netmask=$netmask gateway=$gateway namnameserver=$dns1" \
   #     -hda /opt/data/${hostname}img/${hostname}.img -nographic -boot menu=off,strict=on -net none
   # 仅用于test05 rocy9虚拟机测试，不能用于生产环境
    idc=`echo $HOSTNAME | awk -F '-' '{print $1}'`
    if [[ $idc == "test05" ]];then
         echo $idc
         /usr/bin/qemu-system-x86_64 -enable-kvm -cpu host -m 2048 \
                -kernel /opt/data/Templateimg/vmlinuz-6.6.1-1.el9.ucloud.x86_64 \
                -initrd /opt/data/Templateimg/initramfs-6.6.1-1.el9.ucloud.x86_64.img \
                -append "noxsave noavx noavx2 noavx512f root=/dev/sda1 ip=$ipaddr netmask=$netmask gateway=$gateway nameserver=$dns1 " \
                -hda /opt/data/${hostname}img/${hostname}.img \
                -nographic
                -cpu Westmere,-avx512f,-avx512dq  \
                -boot menu=off,strict=on \
                -net none 
   else
	/usr/bin/qemu-system-x86_64  -enable-kvm -cpu host -m 2048  \
		-kernel /opt/data/Templateimg/vmlinuz-6.6.1-1.el9.ucloud.x86_64 \
		-initrd /opt/data/Templateimg/initramfs-6.6.1-1.el9.ucloud.x86_64.img \
		-append "root=/dev/sda1 ip=$ipaddr netmask=$netmask gateway=$gateway namnameserver=$dns1" \
		-hda /opt/data/${hostname}img/${hostname}.img -nographic -boot menu=off,strict=on -net none
    fi
}

define_start_vm() {
    virsh define /opt/data/$dirname/$hostname.xml
    if [ $? -ne 0 ];then
        logger "failed" "define vm failed"
    fi
    virsh dumpxml --migratable $hostname > /opt/data/$dirname/$hostname.xml
    virsh start $hostname
    if [ $? -ne 0 ];then 
        logger "failed" "start vm failed"
    fi
    logger "success" "create_success"
}

create_xml
copy_create_img

# rocky9 无法使用guestmount或nbd 挂载
if [[ $os == "Rocky9.4-Beta" ]];then
    rocky9_first_init
else
    guestmount_modify_conf
fi

define_start_vm
