import os
import re 
import sys
import textwrap
import sunhpc.commands
from sunhpc.configs import Config
from sunhpc.paths import ipxe_path, scripts_path

class Command(sunhpc.commands.init.command):
    """
    这个命令是初始化系统Pxe引导配置服务.
    <arg type='string' name='ISOFile'>
    提供一个系统ISO挂载点、例如: /mnt/cdrom
    或者提供一个ISO文件路径、例如: /path/to/linux.iso
    或者提供一个ISO文件URL、例如: http://example.com/linux.iso
    </arg>
    <example cmd='init pxe /mnt/cdrom'>
    初始化Pxe引导配置服务
    </example>
    """
    def run(self, params, args):

        (args, mnt_src) = self.fillPostArgs(('mntPath', ))

        if not mnt_src:
            mnt_src = '/mnt/cdrom'

        if not os.path.exists(mnt_src):
            self.log.error(f"挂载点不存在: {mnt_src}")
            self.abort("请挂载一下受支持的Linux系统ISO文件.")

        # sunhpc
        base_nm = self.conf.osinfo.basename
        # /srv/repos/sunhpc
        mnt_dst = os.path.join('/srv/repos', base_nm)

        iface = self.conf.iface
        ipaddr = self.conf.ipaddr

        treeinfo = os.path.join(mnt_src, '.treeinfo')
        if not os.path.exists(treeinfo):
            self.log.error(f"不是一个有效或不受支持的Linux系统ISO挂载路径: {mnt_src}")
            self.abort("重新挂载一下受支持的Linux系统ISO文件.")

        info = {}
        with open(treeinfo, 'r') as f:
            for i in f.readlines():
                tmp = i.strip().split('=', 1)
                if len(tmp) == 2:
                    info[tmp[0].strip()] = tmp[1].strip()

        osname = info.get('family', 'unknown').split()[0].lower()
        if osname not in ['rocky', 'rhel', 'centos']:
            self.log.error(f"不支持的系统类型: {osname}")
            self.abort("请提供一个受支持的Linux系统ISO文件. 只支持Rocky, RHEL, CentOS系统.")

        kernel      = info.get('kernel', None)
        if kernel is None:
            self.log.error(f"没有找到内核文件: {kernel}")
            self.abort("请提供一个支持 Pxe 的 vmlinuz 文件位置.")

        initrd      = info.get('initrd', None)
        if initrd is None:
            self.log.error(f"没有找到初始化文件: {initrd}")
            self.abort("请提供一个支持 Pxe 的 initrd 文件位置.")

        osvers      = info.get('version', 'unknown')
        http_head   = self.conf.http.httpaddr
        http_root   = f"{http_head}/{base_nm}/{osname}/{osvers}"
        http_ksfile = f"{http_root}/{base_nm}/{self.conf.pxe.ksfile}"
        http_init   = f"{http_root}/{base_nm}/{self.conf.pxe.initfile}"
        lrepo_src   = os.path.join(mnt_dst, osname, osvers)
        if not os.path.exists(lrepo_src):
            os.makedirs(lrepo_src)

        # 复制 ISO 文件到目标目录
        if not mnt_src.endswith('/'):
            mnt_src = mnt_src + os.sep

        if not lrepo_src.endswith('/'):
            lrepo_src = lrepo_src + os.sep

        self.rsync_copy(mnt_src, lrepo_src)

        # 拷贝scripts目录到目标目录.
        scripts_dst      = mnt_dst + os.sep
        self.rsync_copy(scripts_path, scripts_dst)

        # 安装 httpd、dnsmasq 服务
        #result = self.sh.execute("dnf install -y httpd dnsmasq")

        wwwroot     = self.conf.http.wwwroot
        tftpboot    = self.conf.tftp.tftpboot
        vmlinuz     = os.path.join(lrepo_src, kernel)
        initrd      = os.path.join(lrepo_src, initrd)
        hostname    = self.sh.execute("hostname", quiet=True).output().strip()

        # 创建软连接
        self.sh.execute(f"ln -s {mnt_dst} {wwwroot}", quiet=True)

        # 创建tftpboot目录
        pxe_boot_src = ipxe_path + os.sep
        pxe_boot_dst = os.path.join(tftpboot, 'boot') + os.sep
        self.sh.execute(f"mkdir -p {pxe_boot_dst}", quiet=True)

        # 拷贝pxe引导文件到tftpboot目录
        self.rsync_copy(pxe_boot_src, pxe_boot_dst)

        # 配置 httpd 服务
        httpd_conf = self.conf.http.config
        self.create_httpd(hostname, base_nm, wwwroot, httpd_conf)

        # 配置 dnsmasq 服务
        start_ip        = self.conf.dnsmasq.start_ip
        end_ip          = self.conf.dnsmasq.end_ip
        addr_dns        = self.conf.dnsmasq.dns
        bios            = self.conf.pxe.bios
        ipxe            = self.conf.pxe.ipxe
        ipxe_sh         = self.conf.pxe.ipxeboot

        ipxe_http       = f"{http_head}/{base_nm}/{ipxe_sh}"
        dnsmasq_conf    = self.conf.dnsmasq.config

        self.create_dnsmasq(iface, 
            ipaddr, tftpboot, dnsmasq_conf,
            start_ip, end_ip, addr_dns, bios, ipxe, ipxe_http)

        # kickstart 
        ksfile_src = self.conf.pxe.ksfile
        ksfile_dst = os.path.join(scripts_dst, ksfile_src)
        self.create_ksfile(hostname, osvers, http_root, http_init, ksfile_dst)

        # 配置 firewalld 服务
        self.fw.load()
        self.fw.add_port('80', 'tcp')
        self.fw.add_port('443', 'tcp')
        self.fw.save()

    def create_ksfile(self, hostname, osvers, http_root, http_init, ksfile_dst):
        ksfile_cnf = f"""
        # Kickstart file for {hostname}
        # Created by sunhpc
        # Version: {osvers}

        graphical
        timezone Asia/Shanghai --utc
        keyboard --xlayouts="us"
        lang en_US.UTF-8
        selinux --disabled

        url --url='{http_root}'

        network  --bootproto=dhcp --device=link --ipv6=auto --activate
        # autopart --type=lvm
        # autopart --type=plain
        # autopart --nohome
        # autopart --noswap

        %include /tmp/diskinfo

        %packages
        @^minimal-environment
        @development
        @standard
        vim
        wget
        curl
        autofs
        nfs-utils
        nfs4-acl-tools
        sssd-nfs-idmap
        %end

        rootpw --plaintext "admin_b101"
        user --name=dell --plaintext --password="admin_b101" --gecos="dell"
        reboot

        %pre --interpreter=/bin/bash
        if [ -d /sys/firmware/efi ]; then
            cat > /tmp/diskinfo <<EOF
        clearpart --all --initlabel
        part /boot/efi --fstype=efi --size=600 --fsoptions="umask=0077,shortname=uefi"
        part /boot --fstype=xfs --size=1024
        part pv.01 --size=1 --grow
        volgroup vg_sys pv.01
        logvol /     --fstype=xfs  --name=root --vgname=vg_sys --size=51200
        logvol swap  --fstype=swap --name=swap --vgname=vg_sys --size=4096
        logvol /data --fstype=xfs  --name=data --vgname=vg_sys --size=1 --grow
        EOF
        else
            cat > /tmp/diskinfo <<EOF
        clearpart --all --initlabel
        part /boot --fstype=xfs --size=1024 --asprimary
        part pv.01 --size=1 --grow
        volgroup vg_sys pv.01
        logvol /     --fstype=xfs  --name=root --vgname=vg_sys --size=51200
        logvol swap  --fstype=swap --name=swap --vgname=vg_sys --size=4096
        logvol /data --fstype=xfs  --name=data --vgname=vg_sys --size=1 --grow
        EOF
        fi
        %end

        %post
        curl -s -o /tmp/init.sh {http_init}
        chmod +x /tmp/init.sh
        /tmp/init.sh
        %end

        %addon com_redhat_kdump --disable
        %end
        """
        with open(ksfile_dst, 'w') as f:
            f.write(textwrap.dedent(ksfile_cnf))

    def create_dnsmasq(self, 
            iface, ipaddr, tftpboot, dnsmasq_conf,
            start_ip, end_ip, addr_dns, bios, ipxe, ipxe_http):
        dnsmasq_tmpl = f"""
        interface={iface}
        bind-interfaces
        port=0

        enable-tftp
        tftp-root={tftpboot}

        # Gateway:3, DNS:6
        dhcp-range={start_ip},{end_ip},12h
        dhcp-option=3,{ipaddr}
        dhcp-option=6,{addr_dns}

        dhcp-match=set:ipxe,175
        dhcp-match=set:bios,option:client-arch,0
        dhcp-match=set:uefi,option:client-arch,7
        dhcp-match=set:uefi,option:client-arch,9
        dhcp-match=set:ipxe,option:user-class,ipxe

        dhcp-boot=tag:bios,tag:!ipxe,{bios}
        dhcp-boot=tag:uefi,tag:!ipxe,{ipxe}
        dhcp-boot=tag:ipxe,{ipxe_http}
        """
        with open(dnsmasq_conf, 'w') as f:
            f.write(textwrap.dedent(dnsmasq_tmpl))

    def create_httpd(self, hostname, base_nm, wwwroot, httpd_conf):
        httpd_tmpl = f"""
        Alias /{base_nm} {wwwroot}/{base_nm}

        UseCanonicalName Off
        ServerName {hostname}

        <Directory "{wwwroot}/{base_nm}">
            Options Indexes FollowSymLinks
            AllowOverride None
            Require all granted

            EnableSendfile on
        </Directory>
        """
        with open(httpd_conf, 'w') as f:
            f.write(textwrap.dedent(httpd_tmpl))




