#!/usr/bin/env -S python3 -u
import time
from proxmoxer import ProxmoxAPI
import paramiko
import io
import sys
import random

# needed in a venv:

#pip install proxmoxer
#pip install paramiko
#pip install requests

# VM template creation, done once on proxmox host

#pvesh get /cluster/nextid
#141
#wget https://cloud.debian.org/images/cloud/bookworm/20230802-1460/debian-12-genericcloud-amd64-20230802-1460.qcow2
#qm create 141 --memory 512 --net0 virtio,bridge=vmbr0 --name ttnn-debian12-template --serial0 socket --ide2 ceph1-ssd:cloudinit --ostype l26 --cores 1 --cpu EPYC-IBPB --ipconfig0 ip=dhcp
#qm importdisk 141 debian-12-genericcloud-amd64-20230802-1460.qcow2 ceph1-ssd
#qm set 141 --scsihw virtio-scsi-single --scsi0 ceph1-ssd:vm-141-disk-0,discard=on,ssd=1,iothread=1
#qm set 141 --boot c --bootdisk scsi0
#qm template 141

# you need to generate a proxmox token and change PROXMOX_USER, PROXMOX_TOKEN_NAME and PROXMOX_TOKEN_VALUE below accordingly

PROXMOX_USER="root@pam"
PROXMOX_TOKEN_NAME='lguerbyttnn'
PROXMOX_TOKEN_VALUE=open("/home/guerby/.proxmox-token-ttnn").read().split("\n")[0]
PROXMOX_API_HOST="g1.tetaneutral.net"

template_vmid="141" #ttnn-debian12-template
sftp_host=PROXMOX_API_HOST
proxmox_vm_node="g1"

# ttnn parameters

IPV6_PREFIXES = {
    '91.224.148' : 80,
    '91.224.149' : 81,
    '89.234.156' : 83,
    '89.234.157' : 84,
    '185.119.168': 85,
    '185.119.169': 86,
    '185.119.170': 87,
    '185.119.171': 88,
}

def ttnn_ip_generate(d):
    ip=d["TTNN_IPV4"]
    ip_l=ip.split(".")
    prefix = IPV6_PREFIXES[".".join(ip_l[:3])]
    low = int(ip_l[3])
    if d["TTNN_IPV6"] is None: d["TTNN_IPV6"]='2a03:7220:80%02d:%02x00::1' % (prefix, low)
    if d["TTNN_LL"] is None: d["TTNN_LL"]='fe80::%02d:%02x' % (prefix, low)

def do_sftp(hostname,path,data):
    ssh=paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        ssh.connect(hostname=hostname,port=22,username="root",timeout=5,banner_timeout=5,auth_timeout=5)
        ftp = ssh.open_sftp()
        file=ftp.file(path, "w")
        file.write(data)
        file.flush()
        ftp.close()
        ssh.close()
    except:
        raise
        pass

def get_mac(net0):
    for s in net0.split(","):
        if s.startswith("virtio=") or s.startswith("e1000="): return s.split("=")[1].lower()
    return "N/A"
    

# VM parameters

conf_d={
    "TTNN_HOSTNAME":"testlg1", 
    "TTNN_MAC":None,
    "TTNN_IPV4":"91.224.148.244",
    "TTNN_IPV6":None,
    "TTNN_LL":None,
    "TTNN_VMID":"323",
    "TTNN_VLANID":"1218",
    "TTNN_DISKSIZE":"8G",
}

ttnn_ip_generate(conf_d)

if conf_d["TTNN_MAC"] is None:
    mac=":".join([('0'+hex(random.randint(0,255))[2:])[-2:] for _ in range(6)])
    mac=mac[0]+["2","6","a","e"][random.randint(0,3)]+mac[2:] # lsb of first byte = 10 local unicast https://stackoverflow.com/questions/42660218/bash-generate-random-mac-address-unicast
    conf_d["TTNN_MAC"]=mac
else:
    mac=conf_d["TTNN_MAC"]

print("conf_d",conf_d)

new_vmid=conf_d["TTNN_VMID"]
HOSTNAME=conf_d["TTNN_HOSTNAME"]
disk_size=conf_d["TTNN_DISKSIZE"]
vlanid=conf_d["TTNN_VLANID"]

# cluster connection
proxmox = ProxmoxAPI(PROXMOX_API_HOST, user=PROXMOX_USER, token_name=PROXMOX_TOKEN_NAME, token_value=PROXMOX_TOKEN_VALUE, verify_ssl=False,timeout=3600)

# cloud-init
ci_yaml="""#cloud-config
hostname: TTNN_HOSTNAME
timezone: Europe/Paris
manage_etc_hosts: true
user: root
disable_root: false
ssh_authorized_keys:
  - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDE+stci1LeZ3wjD6hCuMjtwzcJU7sO7I5928W/RH0L0Q/7xHPKPt8feLVE5w5QYUyCiSudzEVf1T2EVqGKQOSyFA+DqOS/aLi4sFq9Y/BeKnGMpf798Zn5Z17GlItVs1Y1ce7M8pjIrSuIYjFkl0zUvnqmyONZDph/uzwnyk9TWhlJSsmwehnPrlt81kT0v8P+n5OJs4U+qT5FLXZFKaDBz71bwMJyYK1AujlKwIoH6SUmJYykxd3C1gE4Zebsy6GugzkBb5UaEdM+lKGKUV84L5y4XUL5bm0wAIa9twrFARvgXklhNOYzIs8UQ+6Q/4mmRaIzNoYi88p7lab9rxHt root@g1
chpasswd:
  expire: false
users:
  - name: root
package_upgrade: true
packages:
  - qemu-guest-agent
  - screen
  - parted
  - emacs-nox
  - vim
  - tmux
  - tcpdump
  - tshark
  - iftop
  - iotop
  - sysstat
  - molly-guard
  - console-data
  - console-setup
  - kbd
  - iproute2
  - eject
  - gdisk
  - fdisk
  - python-is-python3
write_files:
  - content: |
      #!/bin/bash
      sleep 15
      date > /root/ttnn-date.txt
      echo TTNN_VMID > /root/ttnn-vmid.txt
      echo TTNN_VLANID > /root/ttnn-vlanid.txt

      apt-get remove -y --purge cloud-guest-utils cloud-image-utils cloud-init cloud-initramfs-growroot cloud-utils netplan.io 
      apt-get autoremove -y --purge
      rm -rf /etc/cloud
      rm -rf /etc/netplan
      rm -rf /usr/share/netplan
      echo fr_FR.UTF-8 UTF-8 >> /etc/locale.gen
      echo en_US.UTF-8 UTF-8 >> /etc/locale.gen
      echo LANG=fr_FR.UTF-8 > /etc/default/locale
      locale-gen
      gzip -dc /usr/share/keymaps/i386/azerty/fr.kmap.gz > /usr/share/keymaps/fr.map
      localectl set-keymap fr
      sed -i 's/GRUB_CMDLINE_LINUX=\"/GRUB_CMDLINE_LINUX=\"net.ifnames=0 /g' /etc/default/grub
      update-grub
      sed -i 's/rw,discard/rw,noatime/g' /etc/fstab
      echo LLMNR=no >> /etc/systemd/resolved.conf
      cat > /etc/systemd/network/50-ttnn-eth0.network << EOF
      [Match]
      PermanentMACAddress=TTNN_MAC
      Name=eth0
      
      [Network]
      LinkLocalAddressing=ipv6
      Address=TTNN_IPV4/32
      Address=TTNN_IPV6/56
      Address=TTNN_LL/64
      IPv6AcceptRA=no
      DNS=91.224.148.10
      DNS=91.224.149.254
      DNS=2a03:7220:8080:0a00::1
      DNS=2a03:7220:8080:fe00::1
      Domains=tetaneutral.net
      
      [Route]
      Destination=0.0.0.0/0
      Gateway=91.224.148.0
      GatewayOnLink=true
      
      [Route]
      Destination=::/0
      Gateway=fe80::31
      EOF
      sleep 5
      poweroff
    path: /root/ttnn-cloudinit.sh
    permissions: '0755'
runcmd:
  - date > /root/ttnn-boot-date.txt
  - screen -dmS ci-ttnn -L -Logfile /root/ttnn-cloudinit.log /root/ttnn-cloudinit.sh
"""


for k,v in conf_d.items():
    ci_yaml=ci_yaml.replace(k,v)

snippet_name="userconfig-script-%s.yaml"%HOSTNAME

print("sftp",snippet_name)
do_sftp(sftp_host,"/var/lib/vz/snippets/"+snippet_name,ci_yaml)
print("clone",template_vmid,new_vmid,HOSTNAME)
px=proxmox.nodes(proxmox_vm_node)
px.qemu(template_vmid).clone().post(newid=new_vmid,name=HOSTNAME,full="1")
time.sleep(5)
print("resize")
px.qemu(new_vmid).resize().put(disk="scsi0",size=disk_size)
print("cicustom")
px.qemu(new_vmid).config().post(cicustom="user=local:snippets/"+snippet_name)


# first boot with DHCP 
net_s="virtio="+mac+",bridge=vmbr1"
print("net0",net_s)
px.qemu(new_vmid).config().post(net0=net_s)

time.sleep(2)
x=px.qemu(new_vmid).config().get()
net0=x.get("net0","N/A")
print(net0)
print(get_mac(net0))
print("start")
px.qemu(new_vmid).status().start().post()
print("done")
time.sleep(10)

while True:
    x=px.qemu(new_vmid).status().current().get()["status"]
    print(x)
    if x=="stopped": break
    time.sleep(10)

# then set real VLAN
new_net_s=net0.replace(",bridge=vmbr1",",bridge=vmbr0,tag="+vlanid)
print(new_net_s)
px.qemu(new_vmid).config().post(net0=new_net_s)
    
print("del ide2")
px.qemu(new_vmid).config().post(delete="ide2")
print("del cicustom")
px.qemu(new_vmid).config().post(delete="cicustom")
print("del ipconfig0")
px.qemu(new_vmid).config().post(delete="ipconfig0")

time.sleep(5)

print("restart")
px.qemu(new_vmid).status().start().post()
print("all done")

