#!/usr/bin/env python
#-*- coding: utf-8 -*-
#update:2014-09-12 by liufeily@163.com

from django.core.urlresolvers import reverse
from django.http import HttpResponse,HttpResponseRedirect
from django.shortcuts import render_to_response,RequestContext
from django.contrib.auth.decorators import login_required
from mplatform.website.common.CommonPaginator import SelfPaginator
from django.db import connection,transaction
from mplatform.website.settings import ISO_ROOT
from django.core.files import uploadedfile
from mplatform.utils.db import dbbase
from django.views.decorators.csrf import csrf_exempt
from mplatform.PlatDeploy.views.managedeploy import SaveChunkFile,CombineChunks,RenameFile
from mplatform.utils.commondef import getSignCache,writeSignCache
import os
import logging
import commands
import string
import threading
import time
import datetime
import math
import json
import re
import shutil
logger = logging.getLogger(__name__)

@login_required
def ListTerminalIso(request):
     #获得部署网络
    db = dbbase.database()
    isolist = db.select_fetchall("select id, iso_name, iso_path, iso_size,iso_desc,update_time,deploy_result,deploy_time from platdeploy_terminal")

    kwvars = {
        'lPage':isolist,
        'request':request,
    }
    return render_to_response('PlatDeploy/terminaliso.list.html',kwvars,RequestContext(request))

@login_required
def ListTerminalDeploy(request):
     #获得部署网络
    db = dbbase.database()
    net = db.select_fetchone("select subnet, plattype, netmask, beginip,endip,nextserver,updatetime,constrainttime from platdhcp_terminal ")
    print net
    isolist = db.select_fetchall("select id, iso_name from platdeploy_terminal")

    leftminutes = GetDeployLeftMinutes()

    kwvars = {
        'isoList':isolist,
        'net':net,
        'leftminutes':leftminutes,
        'request':request,
    }
    return render_to_response('PlatDeploy/terminaldeploy.list.html',kwvars,RequestContext(request))

@login_required
def ListTerminalUpgrade(request):
     #获得部署网络
    db = dbbase.database()
    
    isoList = db.select_fetchall("select id, iso_name, iso_path, iso_size,iso_desc,update_time,deploy_result,deploy_time from platdeploy_terminal")
    newiso = db.select_fetchone("select iso_name,is_force from platdeploy_terminal where is_new=1")
    if newiso:
        newiso['is_force'] = '强制' if newiso['is_force'] == 1 else '非强制'
    index = 0
    statusDic = {'online':'在线',
                 'offline':'离线',
                 'upgrading':'正在升级',
                 'upgradesucc':'升级成功',
                 'upgradefail':'升级失败',
                 'reboot':'正在重启'}

    kwvars = {
        'isoList':isoList,
        'newiso':newiso,
        'request':request,
        'terminalList':getTerminalList()
    }
    return render_to_response('PlatDeploy/terminalupgrade.list.html',kwvars,RequestContext(request))

@login_required
def AjaxGetTerminalList(request):
    return HttpResponse( json.dumps(getTerminalList()))

def getTerminalList():
    sign_hosts = getSignCache()
        
    db = dbbase.database()
    
    terminalList = db.select_fetchall("select id,ip ,version ,status,mac from platdeploy_terminalstatus order by ip")

    statusDic = {'online':'在线',
                 'offline':'离线',
                 'upgrading':'正在升级',
                 'upgradesucc':'升级成功',
                 'upgradefail':'升级失败',
                 'reboot':'正在重启'}
    nowtime = datetime.datetime.now()
    for i in terminalList:
        i['status'] = 'offline'
        host = sign_hosts.get(i['mac'])
        if host:
            lastsigntimestr = host.get('lastsigntime')
            if lastsigntimestr:
                lastsigntime = datetime.datetime.strptime(lastsigntimestr, '%Y-%m-%d %H:%M:%S')
                if (nowtime - lastsigntime).seconds < 25:
                    i['status'] = host.get('status')
        
        status_name = statusDic.get(i.get('status'))
        if status_name:
            i['status'] = status_name

    return terminalList

@login_required
def QueryDeployLeftMinutes(request):
    leftminutes = GetDeployLeftMinutes()
    if leftminutes:
        db = dbbase.database()
        res = db.select_fetchone("select iso_name from platdeploy_terminal where is_deploying='1'")
        deploying_iso = res.get('iso_name') if res else ''
        return HttpResponse(json.dumps({'leftminutes':leftminutes,'deploying_iso':deploying_iso}))
    else:
        return HttpResponse(json.dumps({}))

def GetDeployLeftMinutes():
    leftminutes = None
    db = dbbase.database()
    net = db.select_fetchone("select constrainttime from platdhcp_terminal ")
    last_deploy_time_str = db.select_fetchone("select max(deploy_time) as last_deploy_time from platdeploy_terminal where deploy_result='部署成功开启'")
    if last_deploy_time_str and last_deploy_time_str.get('last_deploy_time'):
        last_deploy_time_str = last_deploy_time_str['last_deploy_time'].replace(' ','-').replace(':','-')
        arr = last_deploy_time_str.split('-')
        constrainttime = int(net.get("constrainttime"))
        nowTime = datetime.datetime.now()
        last_deploy_time = datetime.datetime(int(arr[0]),int(arr[1]),int(arr[2]),int(arr[3]),int(arr[4]),int(arr[5]))
        passseconds = (nowTime - last_deploy_time).seconds
        passminutes = passseconds / 60.0
        leftminutes = int(math.ceil(constrainttime - passminutes))
        if leftminutes <= 0:
            leftminutes = None
    return leftminutes

#django.reqInMemoryUploadedFile
@login_required
@csrf_exempt
def AddTerminal(request):
    if request.method=='POST':
        chunks = request.POST.get("chunks")
        chunk_index = request.POST.get("chunk")

        if not os.path.exists(ISO_ROOT):
            os.makedirs(ISO_ROOT)
            
        # 清除之前的碎片文件
        if chunks and chunk_index and int(chunk_index) == 0 or not chunks:
            res_listdir = os.listdir(ISO_ROOT)
            for i in res_listdir:
                if os.path.isdir(ISO_ROOT + i) and re.match('^file_pieces_\w{32}$',i):
                    shutil.rmtree(ISO_ROOT + i)
                    
        # 保存切片文件
        if chunks: 
            th = threading.Thread(target=SaveChunkFile,args=(request.POST,request.FILES))
            th.start()
            
        file_UUID = request.POST.get("fileUUID")
        iso_name = request.POST.get("name")
        iso_path = ISO_ROOT + iso_name.encode('utf-8')
        iso_desc = request.POST.get("iso_desc")
        iso_size = request.POST.get("size")
        final_path = ISO_ROOT + file_UUID + '.iso'
#         final_name = iso_name
        
        # 检测到同名文件后，自动重命名
#         if not chunks or int(chunk_index) == int(chunks) - 1: 
#             rename = False
#             if os.path.exists(iso_path):
#                 rename = True
#                 final_name = RenameFile(iso_name.encode('utf-8'))
#                 final_path = ISO_ROOT + final_name
            
        # 小文件，直接保存
        if not chunks: 
            final_file = open(final_path, 'wb')
            final_file.write(request.FILES.get('file').read())
            final_file.close()
        
        # 大文件，到达最后一片时，将切片合并（该线程应该阻塞）
        if chunks and int(chunk_index) == int(chunks) - 1: 
            th2 = threading.Thread(target=CombineChunks,args=(request.POST,final_path))
            th2.start()
            th2.join()
        
        # 保存数据库
        if not chunks or int(chunk_index) == int(chunks) - 1: 
            cursor = connection.cursor()
            cursor.execute("select COALESCE(max(id),0)+1 as new_id from platdeploy_terminal")
            id = cursor.fetchone()[0]
            update_time = time.strftime("%Y-%m-%d %H:%M:%S")
            cursor.execute("INSERT INTO platdeploy_terminal(id, iso_name, iso_path, iso_size,iso_desc,update_time) values (%s, %s, %s,%s, %s, %s)", [id, iso_name, final_path,iso_size,iso_desc, update_time])
            connection.commit()
            
            # 自动重命名后，将新文件名告知前端
#             if iso_name != final_name: 
#                 return HttpResponse(final_name)
            
        return HttpResponse('')
    else:
        pass

    kwvars = {
        'request':request,
    }

    return render_to_response('PlatDeploy/terminal.add.html',kwvars,RequestContext(request))




@login_required
def StartUpgrade(request):
    isoid = request.POST.get('isoid')
    isforce = request.POST.get('isforce')
    sql1 = "update platdeploy_terminal set is_new=0,is_force=0"
    sql2 = "update platdeploy_terminal set is_new=1,is_force=%s where id=%s" % (isforce,isoid)
    sql3 = "update platdeploy_terminalstatus set upgraded='0'"
    try:
        dbcursor = connection.cursor()
        dbcursor.execute(sql1)
        dbcursor.execute(sql2)
        dbcursor.execute(sql3)
        connection.commit()
    except Exception as e:
        logger.error('Error in StartUpgrade:%s' % str(e))
        
    cacheinfo = getSignCache()
    for h in cacheinfo:
        if cacheinfo[h].get('host_type') == 'client':
            cacheinfo[h]['upgraded'] = '0'
    writeSignCache(cacheinfo)
        
    return HttpResponse('success')

@login_required
def StopUpgrade(request):
    sql = "update platdeploy_terminal set is_new=0,is_force=0"
    try:
        dbcursor = connection.cursor()
        dbcursor.execute(sql)
        connection.commit()
    except Exception as e:
        logger.error('Error in StopUpgrade:%s' % str(e))
    return HttpResponse('success')

@login_required
def DeleteTerminalhost(request,id):
    if id:
        cursor = connection.cursor()
        sql = "select mac from platdeploy_terminalstatus where id='%s'" % id
        cursor.execute(sql)
        mac = cursor.fetchone()[0]
        
        sql = "delete from platdeploy_terminalstatus where id='%s'" % id
        cursor.execute(sql)
        connection.commit()
        
        sign_hosts = getSignCache()
        if mac and sign_hosts.get(mac):
            del sign_hosts[mac]
            writeSignCache(sign_hosts)
                
    return HttpResponseRedirect(reverse('listplatterminalupgradeurl'))

@login_required
def DeleteIso(request,id):
        db = dbbase.database()
        
        select_sql = "select id, iso_name, iso_path, iso_size,iso_desc,update_time from platdeploy_terminal where id = %s" % id
        isolist = db.select_fetchall(select_sql)
        
        for iso in isolist:
            cmd_delete = 'rm -f "%s"' % iso['iso_path']
            os.system(cmd_delete)
        delete_sql = "delete from platdeploy_terminal where id = %s" % id
        db.execute(delete_sql)
        return HttpResponseRedirect(reverse('listplatterminalisourl'))


@login_required
def EditTerminalNet(request):
    if request.method=='POST':
        subnet = request.POST["subnet"]
        netmask = request.POST["netmask"]
        beginip = request.POST["beginip"]
        endip = request.POST["endip"]
        nextserver = request.POST["nextserver"]
        constrainttime = request.POST["constrainttime"]
        update_time = time.strftime("%Y-%m-%d %H:%M:%S")
        cursor = connection.cursor()
        cursor.execute("select plattype from platdhcp_terminal ;")
        row = cursor.fetchone()
        if row:
            print 'update+++++++++++++++++++++++++++++++++++++++++'
            cursor.execute("update platdhcp_terminal set subnet=%s, plattype=%s, netmask=%s, beginip=%s,endip=%s,nextserver=%s,updatetime=%s ,constrainttime=%s", [subnet, 'service',netmask, beginip,endip,nextserver, update_time,constrainttime])
        else:
            cursor.execute("INSERT INTO platdhcp_terminal(subnet, plattype, netmask, beginip,endip,nextserver,updatetime,constrainttime) values (%s, %s, %s,%s, %s, %s, %s,%s)", [subnet, 'service',netmask, beginip,endip,nextserver, update_time,constrainttime])
        transaction.commit()#commit_unless_managed()
        connection.commit()
        return HttpResponseRedirect(reverse('listplatterminaldeployurl'))
    else:
        db = dbbase.database()
        net = db.select_fetchone("select subnet, plattype, netmask, beginip,endip,nextserver,updatetime,constrainttime from platdhcp_terminal ")
        if net == None:
           net = {'constrainttime':'30'}

    kwvars = {
        'net':net,
        'request':request,
    }
    return render_to_response('PlatDeploy/terminalnet.edit.html',kwvars,RequestContext(request))



@login_required
def StartDeploy(request):
    try:
        db = dbbase.database()
        id = request.POST.get('isoid')
#         product_name = request.POST.get('product_name')
        
        # 检测运行平台是否正在部署
        busydhcp = db.select_fetchone("select id from platdeploy_service where deploy_result = '部署成功开启'")
        if busydhcp:
            return HttpResponse('DHCPBUSY')
        #一：
        #iso文件放入/data/isos/
        #在/data/tmp/中运行livecd-iso-to-pxeboot /data/isos/xxx.iso
        #rm -rf /data/tftpboot/*
        #cp -rf /data/tmp/tftpboot/* /data/tftpboot/
        #rm -R /data/tmp/tftpboot
        print '========================================================'
        print id
        int_id = string.atoi(id)
        
        select_sql = "select iso_name,iso_path from platdeploy_terminal where id=%d;" % int_id
        iso = db.select_fetchone(select_sql)
        cmd_pxeboot = 'cd /data/tmp/; livecd-iso-to-pxeboot "%s";' % (iso['iso_path'])
    
        os.system(cmd_pxeboot)
        os.system('rm -rf /var/lib/tftpboot/*')
        #os.system('cp -rf /data/tmp/tftpboot/* /data/tftpboot/')
        os.system('cp -rf /data/tmp/tftpboot/* /var/lib/tftpboot/')#需要tftp服务的支持
        os.system('rm -R /data/tmp/tftpboot')
    
        #二：
        #修改配置文件：pxelinux.cfg/default：
        #DEFAULT pxeboot
        #TIMEOUT 20
        #PROMPT 0
        #LABEL pxeboot
        #        KERNEL vmlinuz0
        #        APPEND rootflags=loop initrd=initrd0.img root=live:/mcos-tp-server-2.0.0_alpha-201504161628.iso rootfstype=auto ro rd.live.image crashkernel=256M rd_NO_MULTIPATH rootflags=ro elevator=deadline install quiet max_loop=256 rhgb rd.luks=0 rd.md=0 rd.dm=0
        #ONERROR LOCALBOOT 0
        #改为：
        #DEFAULT pxeboot
        #TIMEOUT 20
        #PROMPT 0
        #LABEL pxeboot
        #        KERNEL vmlinuz0
        #        APPEND rootflags=loop initrd=initrd0.img root=live:/mcos-tp-server-2.0.0_alpha-201504161628.iso rootfstype=auto ro rd.live.image crashkernel=256M rd_NO_MULTIPATH rootflags=ro elevator=deadline install quiet max_loop=256 rhgb rd.luks=0 rd.md=0 rd.dm=0 autoinstall reinstall adminpw=roorroor rootpw=toottoot massclouds_init=/dev/sda manager=192.168.7.181
        #ONERROR LOCALBOOT 0
        #其中
        #autoinstall 表示下载后自动安装iso
        #reinstall（如果以前安装过要加上这个参数，以前没安装过可加可不加）
        #adminpw=xxxx 表示设置amdin的默认密码
        #rootpw=xxxx 表示设置root的默认密码
        #massclouds_init=/dev/xxx 表示自动安装到哪个盘
        #manager=xxx.xxx.xxx.xxx 表示manager的ip
    
        net = db.select_fetchone("select subnet, plattype, netmask, beginip,endip,nextserver,updatetime,constrainttime from platdhcp_terminal where plattype='service';")
    #    pxe_config = '''DEFAULT pxeboot
    #TIMEOUT 20
    #PROMPT 0
    #LABEL pxeboot
    #        KERNEL vmlinuz0
    #        APPEND rootflags=loop initrd=initrd0.img root=live:%s rootfstype=auto ro rd.live.image crashkernel=256M rd_NO_MULTIPATH rootflags=ro elevator=deadline install quiet max_loop=256 rhgb rd.luks=0 rd.md=0 rd.dm=0 autoinstall reinstall adminpw=rootroot rootpw=rootroot massclouds_init=/dev/sda manager=%s
    #ONERROR LOCALBOOT 0''' % (iso['iso_name'],net['nextserver'])
    #    cmd_pxeconfig = "echo '%s' > /var/lib/tftpboot/pxelinux.cfg/default" % pxe_config
        handletype = 'reinstall'
        str_pxeconfig = " autoinstall %s adminpw=rootroot rootpw=rootroot massclouds_init=/dev/sda manager=%s" % (handletype, net['nextserver'])
        file = open( "/var/lib/tftpboot/pxelinux.cfg/default", "r" )
        content = file.read()
        content = content.replace(' quiet ',' ') # 去掉quiet参数
        file.close()
        key_word = "rd.md=0 rd.dm=0"
        pos = content.find(key_word)+len(key_word)
        if pos != -1:
                content = content[:pos] + str_pxeconfig + content[pos:]
                file = open( "/var/lib/tftpboot/pxelinux.cfg/default", "w" )
                file.write( content )
                file.close()
    
        #os.system(cmd_pxeconfig)
    
        #三：
        #修改dhcp配置文件，例如：
        #subnet 192.168.7.0 netmask 255.255.255.0{
        #  range 192.168.7.10 192.168.7.90;
        #  next-server 192.168.7.222;
        #  filename "pxelinux.0";
        #}
        dhcp_conf = '''
        # If this DHCP server is the official DHCP server for the local
        # network, the authoritative directive should be uncommented.
         authoritative;
         subnet %s netmask %s{
         range %s %s;
         next-server %s;
         filename "pxelinux.0";
         }''' %(net['subnet'],net['netmask'],net['beginip'],net['endip'],net['nextserver'])
        cmd_dhcp = "echo '%s' > /etc/dhcp/dhcpd.conf" % dhcp_conf
        os.system(cmd_dhcp)
    
        #四：
        #systemctl start dhcpd
        (status,output) = commands.getstatusoutput('systemctl start dhcpd')
        if status != 0:
            logger.error('Error to start dhcpd:%s' % output)
            return HttpResponse('error')
        deploy_time = time.strftime("%Y-%m-%d %H:%M:%S")
        update_sql = "update platdeploy_terminal set deploy_time='%s', deploy_result ='%s',is_deploying='1' where id=%d" % (deploy_time, '部署成功开启',int_id)
        db.execute(update_sql)
    
        #五：开始定时处理
        logger.debug("开始定时处理")
        int_constrainttime=int(net['constrainttime'])
        t = threading.Timer(int_constrainttime*60,StopDhcp,(int_id,))
        t.start()
    except Exception as e:
        logger.error('Error in StartDeploy:%s' % str(e))
        return HttpResponse('error')
    return HttpResponse('success')

# @login_required
# def UpgradeTerminal(request,id):
#     return StartDeploy(request, id, True)


def StopDhcp(id):
    logger.debug("进入函数StopDhcp id=%s",id)
    db = dbbase.database()
    os.system('systemctl stop dhcpd')
    update_sql = "update platdeploy_terminal set deploy_result ='%s',is_deploying='0' where id=%d" % ('部署网络自动关闭',id)
    db.execute(update_sql)
    logger.debug("退出函数StopDhcp")

@login_required
def StopDeploy(request):
    db = dbbase.database()
#     int_id = string.atoi(id)
    os.system('systemctl stop dhcpd')
    update_sql = "update platdeploy_terminal set deploy_result ='%s',is_deploying='0'" % ('部署成功关闭',)
    db.execute(update_sql)
    return HttpResponseRedirect(reverse('listplatterminaldeployurl'))
