#!/bin/bash
if [[ $# -lt 5 ]];then
    echo -e "\033[32m Usage: ./create.sh IP/nm cpu memory disk OS uuid mac1 mac2 mac3 GW IDC Usage SecUsage\033[0m"
    echo -e "adaptation for Rocky9.4-Beta OpenEuler cloud-init"
    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:9902/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
_1macaddr=$7
_2macaddr=$8
_3macaddr=$9
GW=${10}
IDC=${11}
Usage=${12}
SecUsage=${13}

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}'`


gw_ip=`echo $10|cut -f1 -d'/'`
if [[ -n $gw_ip ]]; then
    ping -n -c 1 -w 5 $gw_ip 2>/dev/null
    if [[ $? -eq 0 ]]; then
        gateway="$gw_ip"
    else
        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"
    fi
else
    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"
fi




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
   CentOS7.4) img='CentOS7.4_cloud-init.img'  ;;
   Rocky9.4-Beta)  img='Rocky9.4_cloud-init.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' ;;
   OpenEuler) img='OpenEuler.img' ;;
   CentOS7.4-kernel-5.10.0) img='CentOS7.4.img-5.10'  ;;
   *)
       echo "not support os $os!"
       exit 1 ;;
esac

echo `date +"%Y-%m-%d %H:%M:%S "` "start"  > /tmp/$hostname.log


# 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/^ *//'`

# 检测ARM64架构
lscpu|grep "Architecture"|grep "aarch64"
IS_ARM64=$?

# 检测是否为Kunpeng处理器
lscpu|grep "Model name"|grep -i "kunpeng\|hi16"
IS_KUNPENG=$?

#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

if [[ $IS_ARM64 -eq 0 ]];then
    cp /usr/share/edk2/aarch64/vars-template-pflash.raw /var/lib/libvirt/qemu/nvram/$hostname_VARS.fd
fi


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

if [[ $IS_ARM64 -eq 0 ]]; then
    machine_type="<type arch='aarch64' machine='virt'>hvm</type>
    <loader readonly='yes' type='pflash'>/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw</loader>
    <nvram>/var/lib/libvirt/qemu/nvram/$hostname_VARS.fd</nvram>"
else
    #machine_type="<type arch='x86_64' machine='pc-i440fx-rhel7.5.0'>hvm</type>"
    machine_type="<type arch='x86_64' machine='pc'>hvm</type>"
fi

if [[ $IS_ARM64 -eq 0 ]]; then
    features="<features>
    <acpi/>
    </features>"
    # ARM64架构配置
    if [[ $IS_KUNPENG -eq 0 ]]; then
        # Kunpeng处理器配置
        cpu_mode="<cpu mode='host-passthrough' />"
    else
        # 通用ARM64配置
        cpu_mode="<cpu mode='custom' match='exact' check='full'>
        <model fallback='forbid'>cortex-a72</model>
        <feature policy='require' name='aarch64'/>
        <feature policy='require' name='pmu'/>
      </cpu>"
    fi
elif [[ $IS_AMD -eq 0 ]];then
    features="<features>
    <acpi/>
    <apic/>
    <pae/>
    <qemu_cpu>
      <legacy-cache state='off'/>
      <xlevel state='on' value='0x8000001e'/>
    </qemu_cpu>
    </features>"
    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>"
else
    features="<features>
    <acpi/>
    <apic/>
    <pae/>
    </features>"
    cpu_mode="<cpu mode='host-passthrough' />"
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 [[ OS == 'Windows2012' || OS == 'Windows2016' || OS == 'Windows2019' || OS == 'Windows2022' ]]; then
    cloud_init_cdrom=""
else
    cloud_init_cdrom="
<disk type='file' device='cdrom'>
    <driver name='qemu' type='raw'/>
    <source file='/opt/data/${hostname}img/cloud-init.iso'/>
    <target dev='hdc' bus='ide'/>
    <readonly/>
    <alias name='ide0-1-0'/>
</disk>"
fi


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

# 构建XML字符串
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
  $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>
    $cloud_init_cdrom
  </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

    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 函数
cloud_init_rocky9() {
    logger "debug" "使用Cloud-Init配置Rocky Linux 9虚拟机"
    
    # 创建Cloud-Init配置目录
    local cloud_dir="/opt/data/${dirname}/cloud-init"
    mkdir -p "$cloud_dir"
    
    # 生成meta-data文件
    cat > "${cloud_dir}/meta-data" << EOF
instance-id: ${hostname}
local-hostname: ${hostname}
EOF

# 公共信息初始化
IPV6_HEX=$(echo "${ipaddr}" | awk -F '.' '{printf "%02x%02x:%02x%02x",$1,$2,$3,$4}')
IPV6="2002:${IPV6_HEX}::1"
RESOLV_CONTENT=$(cat /etc/resolv.conf 2>/dev/null || echo -e "nameserver 8.8.8.8\nnameserver 8.8.4.4")
    # 生成user-data文件 - 使用双引号heredoc，让变量展开
    cat > "${cloud_dir}/user-data" << USERDATA_EOF
#cloud-config
hostname: ${hostname}
fqdn: ${hostname}.local

users:
  - name: root
    ssh_authorized_keys:
      - ssh-rsa [payload removed: 544 characters] isl_sod@ucloud.cn_UcloudServers-v2-2022-10-17
      - ssh-rsa [payload removed: 372 characters] root@10-81-96-153
    lock_passwd: false
    shell: /bin/bash

ssh_pwauth: true
disable_root: false





# 写入网络配置文件 - 直接使用变量
write_files:
  - path: /etc/ssh/sshd_config
    content: |
      ListenAddress ${ipaddr}
      Protocol 2
      SyslogFacility AUTHPRIV
      PasswordAuthentication no
      ChallengeResponseAuthentication no
      GSSAPIAuthentication no
      GSSAPICleanupCredentials yes
      UsePAM yes
      AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
      AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
      AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
      AcceptEnv XMODIFIERS
      X11Forwarding yes
      UseDNS no
      Subsystem sftp /usr/libexec/openssh/sftp-server
      MaxStartups 100
      LogLevel VERBOSE
      PermitEmptyPasswords no
    permissions: '0600'
  - path: /etc/sysconfig/network-scripts/ifcfg-eth0
    content: |
      DEVICE=eth0
      TYPE=Ethernet
      ONBOOT=yes
      BOOTPROTO=static
      IPADDR=${ipaddr}
      NETMASK=${netmask}
      GATEWAY=${gateway}
    permissions: '0644'
  - path: /etc/hostname
    content: |
      ${hostname}
    permissions: '0644'
  - path: /etc/sysconfig/network-scripts/route6-sit6to4
    content: |
      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
    permissions: '0644'
  - path: /etc/sysconfig/network-scripts/ifcfg-sit6to4
    content: |
      DEVICE=sit6to4
      TYPE=sit
      ONBOOT=yes
      NM_CONTROLLED=no
      BOOTPROTO=static
      IPV6INIT=yes
      IPV6TUNNELIPV4=any
      IPV6TUNNELIPV4LOCAL=${ipaddr}
      IPV6ADDR=${IPV6}/128
    permissions: '0644'
  - path: /etc/resolv.conf
    content: |
$(echo "$RESOLV_CONTENT" | sed 's/^/      /')
    permissions: '0644'

runcmd:
  - modprobe sit
  - echo "sit" > /etc/modules-load.d/sit.conf
  - sed -i --follow-symlinks "/net\.ipv6\.conf\.all\.disable_ipv6.*/d" /etc/sysctl.conf
  - hostnamectl set-hostname ${hostname}
  - systemctl stop NetworkManager
  - systemctl disable NetworkManager
  - systemctl mask NetworkManager
  - systemctl enable network
  - systemctl restart network
  - systemctl restart sshd
  - |
    if [ -b /dev/vdb ] && ! blkid /dev/vdb; then
        mkfs.ext4 -F /dev/vdb
        mkdir -p /data
        echo '/dev/vdb /data ext4 defaults,noatime 0 0' >> /etc/fstab
        mount /data
    fi
  - curl -o /tmp/init.sh  http://softlib.service.ucloud.cn/downloads/uvmp/init.sh
  - chmod +x /tmp/init.sh
  - /tmp/init.sh ${IDC} ${Usage} ${SecUsage}


final_message: "Cloud-Init配置完成"
# power_state:
#   mode: reboot
#   timeout: 0
#   condition: true
USERDATA_EOF

    # 验证生成的user-data文件
    logger "debug" "验证生成的user-data文件格式"
    
    # 创建Cloud-Init ISO
    logger "debug" "创建Cloud-Init ISO镜像"
    if command -v genisoimage >/dev/null 2>&1; then
        genisoimage -output "/opt/data/${dirname}/cloud-init.iso" -volid cidata -joliet -rock \
            "${cloud_dir}/user-data" "${cloud_dir}/meta-data" 2>/dev/null
    elif command -v mkisofs >/dev/null 2>&1; then
        mkisofs -output "/opt/data/${dirname}/cloud-init.iso" -volid cidata -joliet -rock \
            "${cloud_dir}/user-data" "${cloud_dir}/meta-data" 2>/dev/null
    else
        logger "failed" "未找到genisoimage或mkisofs命令"
        return 1
    fi
    
    if [ -f "/opt/data/${dirname}/cloud-init.iso" ]; then
        logger "debug" "Cloud-Init ISO创建成功"
    else
        logger "failed" "Cloud-Init ISO创建失败"
        return 1
    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 使用cloud-init
if [[ "$os" =~ Windows ]]; then
    guestmount_modify_conf

else
    cloud_init_rocky9
 
fi
define_start_vm
