#coding:utf-8

import os
import sys
import shutil
import sunhpc
import subprocess
class RollHandler(object):

    def __init__(self, cmd, mnt, clean):

        self.cmd        = cmd
        self.clean      = clean
        self.mntdir     = mnt
        self.repodirs   = ''
        self.rinfo      = None
        self.isoname    = 'unknown'
        self.foreign    = False

    def is_mounted(self):
        cmd = 'mount |grep %s' % self.mntdir
        if subprocess.call(cmd, shell=True):
            return 0
        return 1

    def mount_iso(self, iso):
        subprocess.run('mount -r %s %s' % (iso, self.mntdir), shell=True, check=True)
        self.isoname = iso

    def umount_iso(self):
        subprocess.run('umount %s' % self.mntdir, shell=True)

    def read_iso(self):
        cmd = r'find %s -type f -name roll-\*.xml' % self.mntdir
        ret = self.cmd.shcmd(cmd, code=True)
        try:
            roll = sunhpc.core.files.RollInfoFile(ret['o'].strip())
            self.rinfo = roll
        except FileNotFoundError:
            pass

    def foreign_roll(self):
        self.cmd.msg('The "%s" was not produced by sunhpc created.' % self.isoname, 'w')
        # check iso .discinfo file
        discinfo = os.path.join(self.mntdir, '.discinfo')
        if not os.path.exists(discinfo):
            self.cmd.msg('The %s is not exists.' % discinfo, 'a')

        info = []
        with open(discinfo, 'r') as fn:
            info = fn.readlines()

        try:
            self.foreign        = True
            self.rinfo          = sunhpc.core.utils.Struct()
            self.rinfo.name     = info[1].split()[0].strip()
            self.rinfo.version  = info[1].split()[-1].strip()
            self.rinfo.arch     = info[2].strip()
        except IndexError:
            self.foreign = False


    def copy_iso(self):
        self.read_iso()
        if not self.rinfo:
            self.foreign_roll()

        self.copy_roll()

    def copy_roll(self):
        # self.rinfo是经过file.RollInfoFile处理过的,返回相应的类对象.
        if self.foreign:
            roll_name = self.rinfo.name
            roll_vers = self.rinfo.version
            roll_arch = self.rinfo.arch
            roll_os   = self.cmd.os
            roll_boot = None
            roll_path = self.mntdir
        else:
            roll_name = self.rinfo.getRollName()
            roll_vers = self.rinfo.getRollVersion()
            roll_arch = self.rinfo.getRollArch()
            roll_os   = self.rinfo.getRollOS()
            roll_boot = self.rinfo.isBootable()
            roll_path = os.path.join(self.mntdir, roll_name)

        # 获取rolls存放位置
        cmd = '/opt/sunhpc/bin/sunhpc report distro'
        for line in os.popen(cmd).readlines():
            distro = line[:-1]

        # /export/sunhpc/install/rolls
        if self.foreign:
            rolls_dir = '%s/repos' % (distro)
        else:
            rolls_dir = '%s/rolls' % (distro)

        # /export/sunhpc/install/rolls/kernel......
        if self.foreign:
            roll_dir = os.path.join(rolls_dir, roll_name, roll_vers, roll_arch)
        else:
            roll_dir = os.path.join(rolls_dir, roll_name)

        if self.clean:
            # /export/sunhpc/install/rolls/kernel/version/x86_64
            specific_roll_dir = os.path.join(roll_dir, roll_vers, roll_arch)
            if os.path.exists(specific_roll_dir):
                txt = '[+] Cleaning %s version %s for %s from the Rolls directory.' % \
                            (roll_name, roll_vers, roll_arch)
                self.cmd.msg(txt)
                self.clean_dir(specific_roll_dir)
            os.makedirs(specific_roll_dir)

        cwd = os.getcwd()
        os.chdir(roll_path)

        # 计算一下大小
        cmd = 'du -sh %s' % self.mntdir
        ret = self.cmd.shcmd(cmd, code=True)
        size = 'unkown'
        if ret['c'] == 0:
            size = ret['o'].split()[0]

        # 开始拷贝文件
        self.cmd.msg('Copying %s(%s) to %s, Please waiting....\r' % (roll_name, size, roll_dir))

        # find . ! -name TRANS.TBL ! -path './kernel*' -print 排除目录和对应文件
        # cpio -d自动创建目录, -u自动覆盖旧文件 -p目录拷贝模式 -m保留文件原始mtime
        # subprocess.run('find . ! -name TRANS.TBL -print|cpio -mpud %s' % roll_dir, shell=True)

        rpmlist = self.cmd.shcmd('find . ! -name TRANS.TBL -print')['o'].split('\n')
        self.cmd.copyfiles(rpmlist, roll_dir)

        # 拷贝iso根目录下其他引导所需要的文件.
        if roll_boot:
            os.chdir(self.mntdir)
            boot_dir = os.path.join(rolls_dir, 'boot')
            bootlist = self.cmd.shcmd('find . ! -name TRANS.TBL ! -path "./%s*" -print' % roll_name)['o'].split('\n')
            self.cmd.copyfiles(bootlist, boot_dir)

            os.chdir(os.path.join(self.mntdir, roll_name))

        # 修改所有目录权限,确保所有人能够访问,例如Apache等.
        self.cmd.shcmd(r"find %s -type d -exec chmod a+rx {} \;" % roll_dir, code=True)

        # 插入roll信息到数据库,如果存在则放弃插入.
        rows = self.cmd.db.search('select * from rolls where'  \
                    ' name="%s" and version="%s" and arch="%s" and os="%s"' \
                    % (roll_name, roll_vers, roll_arch, roll_os))

        if not rows:
            db_cmd = 'insert into rolls (name, version, arch, enabled, os)'\
                        ' values("%s", "%s", "%s", "%s", "%s")'   \
                    % (roll_name, roll_vers, roll_arch, 'yes', roll_os)

            self.cmd.db.execute(db_cmd)

        os.chdir(cwd)
        # 如果是引导roll,需要使用软件Kylins create distro重新部署.
        # 重新创建images,stage2,和相关连接相关任务.
        self.cmd.msg('Copy the %s finished.' % roll_name)
        self.repodirs = roll_dir

    def clean_dirs(self, dirs):
        for root, dirs, files in os.walk(dirs, topdown=False):
            for name in files:
                os.remove(os.path.join(root, name))
            for name in dirs:
                os.rmdir(os.path.join(root, name))
        os.removedirs(dirs)

class command(sunhpc.commands.pxelinux.command):
    pass

class Command(command):
    """
    build pxe install in the cluster
    <arg type='File' name='iso'>
    supply an sunhpc iso images file.
    </arg>

    <param type='File' name='iso'>
    supply an sunhpc iso images file.
    </param>

    <param type='Path' name='mnt'>
    Specify a temporary iso images mount directory.default:/mnt/cdrom
    </param>

    <param type='Bool' name='pxesrv'>
    Pxelinux services are also installed , httpd, dhcpd, tftp. autofs,default:yes
    </param>

    <param type='bool' name='clean'>
    If set, then remove all files from any existing rolls of the same name.
    </param>

    <example cmd='pxelinux build CentOS-7.9.2009-0.x86_64.disk.iso'>
    Added the sunhpc iso to the local Roll directory.
    </example>

    <related>sunhpc create roll roll-CentOS.xml boot=/mnt/cdrom</related>

    """

    def run(self, params, args):

        (clean, mnt, pxe, quiet) = self.fillParams([
            ('clean', 'n'), ('mnt', '/mnt/cdrom'),
            ('pxesrv', 'yes'),
            ('quiet', 'no')])

        if os.path.exists(self.db.getDBFile):
            shutil.chown(self.db.getDBFile, 'root', 'apache')

        cwd     = os.getcwd()
        q       = self.str2bool(quiet)
        pxesrv  = self.str2bool(pxe)
        clean   = self.str2bool(clean)
        if len(args) == 0:
            self.abort('must supply linux iso images file.')

        if not os.path.exists(mnt):
            os.makedirs(mnt)

        iso_list = []
        for i in args:
            i = os.path.join(os.getcwd(),i)
            if os.path.exists(i) and i.endswith('.iso'):
                iso_list.append(i)
            else:
                self.msg("Cannot find %s or %s is not and ISO image" % (i, i), 'a')

        roll_handler = RollHandler(self, mnt, clean)
        if roll_handler.is_mounted():
            self.msg("The %s has been mounted,umount is firsrt." % mnt, 'a')

        for i in iso_list:
            roll_handler.mount_iso(i)
            roll_handler.copy_iso()
            roll_handler.umount_iso()

        if roll_handler.foreign:
            sys.exit(0)

        if pxesrv:
            self.configSRV(q)
        else:
            self.msg('Rebuild the sunhpc distribution -> /export/sunhpc/install')
            self.msg('Use the command: sunhpc create distro')

        # modify the database file owner root.apache

        os.chdir(cwd)

    def configSRV(self, q):

        distbase = self.command('report.distro',[]).strip()
        os.chdir(distbase)
        # /export/sunhpc/install
        self.command('create.distro')

        srvlist = ['httpd', 'tftpd', 'dhcpd', 'autofs']
        for s in srvlist:
            self.msg('Building the pxe services - %s' % s, q=q)
            self.command('pxelinux.build.%s' % s, ['quiet=%s' % q])
            
RollName = "base"

