HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux WebLive 5.15.0-79-generic #86-Ubuntu SMP Mon Jul 10 16:07:21 UTC 2023 x86_64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //usr/local/qcloud/monitor/barad/plugin/collector/utils/host_proxy.py
#!/usr/bin/env python
# 0. head
import sys, os
import socket
import time
import select
import threading
import SocketServer
import zipfile
import re

sys.path.append(os.getcwd()+"/../lib/")
#import psutil

# 1. macro define and global variable
# BUFFER_SIZE = 256
LOG_PATH = '../log/host_proxy.log'
VER_FILE = '/var/run/Tx-proxy.lock'
conf_file = '../etc/host_proxy.conf'
proxy_name = 'Tx-proxy'
os_name = 'Unknown OS'
os_list = 'Tencent tlinux CentOS Linux SLES Ubuntu'
MAX_LOG_SIZE = 1024 * 1024 * 1024

def quote_str(cmd):
    badchars = "\n&;|'\"$()`>"
    for char in badchars:
        cmd = cmd.replace(char, "_")
    return cmd

# write log to logfile
def write_log(str, timestamp = True):
    with open(LOG_PATH,'a+') as f:
        if timestamp:
            f.write("[%s] %s" % (time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())), str) )
        else:
            f.write(str)

# write version to /var/run/Tx-proxy.lock
def write_version():
    if not os.path.exists(conf_file):
        write_log("host_proxy.conf does not exist!\n")
        sys.exit(1)
    with open(conf_file, 'r') as f1:
        ver = f1.read().strip()
    write_log("Set process version to %s..." % ver)
    with open(VER_FILE,'w') as f2:
        f2.write(ver)
    write_log("Done\n", False)

def change_proc_name(new_name=proxy_name):
    write_log("Set process name to %s..." % new_name)
    try:
        import setproctitle
        setproctitle.setproctitle(new_name)
        # checking whether set process name succ or not
        if not setproctitle.getproctitle().startswith(new_name):
            write_log("set process name to %s failed \n" % new_name)
            sys.exit(1)
            
    except Exception, e:
        import traceback
        write_log(traceback.format_exc())
        sys.exit(1)

    write_log("Done\n", False)

# daemon
def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
    write_log("Daemonize...")
    try:
        pid = os.fork()
        if pid > 0: 
            sys.exit(0)
    except OSError, e:
        write_log("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror) )
        sys.exit(1)

    #os.chdir("/")
    os.umask(0)
    os.setsid()

    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)
    except OSError, e:
        write_log("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror) )
        sys.exit(1)

    for f in sys.stdout, sys.stderr: f.flush()
    si = open(stdin, 'r')
    so = open(stdout, 'a+')
    se = open(stderr, 'a+', 0)
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

    write_log("Done\n", False)

def get_proc_num(proc_name):
    proc_name = quote_str(proc_name)
    cmd = 'ps aux | grep -w ' + proc_name + ' | grep -v grep | wc -l';
    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error :%s\n" % e)
        sys.exit(1)
    #for p in psutil.process_iter():
    #    try:
    #        if p.name() == proc_name:
    #            proc_num += 1
    #    except Exception, e:
    #        pass
    proc_num=int(out[0].strip())
    return proc_num

# a. check whether the port is occupied, exit if true
def check_proc(procname = proxy_name):
    write_log("Check whether the port is occupied...")

    cnt = get_proc_num(procname)

    if cnt > 1:
        # host_agent has been running
        write_log('%s has been running, so exit\n' %(procname) )
        sys.exit(1)

    write_log("Done\n", False)
    return True

# log rotate
def log_rotate():
    try:
        fsize = os.path.getsize(LOG_PATH)
    except OSError,e:
        write_log('get host_proxy size failed.')
        return False

    if fsize > MAX_LOG_SIZE:
        try:
            status = os.system('cd ../log/;rm -f host_proxy.log.tar.gz;tar -czvf host_proxy.log.tar.gz host_proxy.log;cd ../bin')
        except OSError,e:
            write_log('compress host_proxy.log failed.')
            return False

        try:
            with open(LOG_PATH, "w"):
                pass
        except OSError,e:
            write_log('open host_proxy.log failed.')
            return False


        write_log('logrotate success')
        return True

# check os
def check_os():
    write_log('Check os name...')
    global os_name
    with open('/etc/os-release','r') as f:
        for l in f:
            key = l.split("=")[0]
            if "NAME" in key:
                os_name = (l.split("=")[1]).split('"')[1]
                break

    if os_name not in os_list:
        write_log('Error: Unknown OS\n')
        sys.exit(1)

    write_log('Done, os_name:%s\n' %(os_name), False)

# check whether iscsid is running
def check_iscsid(procname):
    cnt = get_proc_num(procname)
    if cnt < 1:
        # open-iscsi is not running
        return False
    return True

# b. check whether iscsi is OK, and if not, start it
def check_iscsi(procname = 'iscsid'):
    write_log("Check whether iscsid is running...")
    global os_name
    if not check_iscsid(procname):
        if os_name == 'Tencent tlinux' or os_name == 'CentOS Linux':
            cmd = 'systemctl stop iscsid.socket && sleep 1 && systemctl start iscsid.socket'
            write_log('os is %s, and %s is not running, try to handle: %s\n' %(os_name, procname, cmd) )
            try:
                out = os.popen(cmd, 'r').readlines()
            except OSError, e:
                write_log("Error :%s\n" % e)
                sys.exit(1)
        cmd = 'systemctl start iscsi && systemctl start iscsid'
        write_log('%s is not running, try to handle: %s\n' %(procname, cmd) )

        try:
            out = os.popen(cmd, 'r').readlines()
        except OSError, e:
            write_log("Error :%s\n" % e)
            sys.exit(1)

        if not check_iscsid(procname):
            # open-iscsi is still not running
            write_log('Failed to start iscsi by handling: %s, so exit\n' %(cmd) )
            sys.exit(1)

    write_log("Done\n", False)
    return True


def check_iscsi_config():
    write_log("Check the iscsi config in /etc/iscsi/iscsid.conf...")
    iscsi_conf='/etc/iscsi/iscsid.conf'
    restart = False
    if os.path.exists(iscsi_conf):
        with open(iscsi_conf, 'r') as f:
            lines = f.readlines()
        with open(iscsi_conf, 'w') as f_w:
            for line in lines:
                if 'node.startup' in line and '#' not in line:
                    if "manual" in line:
                        restart = True
                        line = line.replace("manual", "automatic")
                f_w.write(line)
    else:
        write_log("iscsi config file does not exist!")
        sys.exit(1)
    if restart:
        cmd = quote_str('systemctl restart iscsid')
        write_log('iscsi config file is changed, try to restart by: %s...' %(cmd) )
        try:
            out = os.popen(cmd, 'r').readlines()
        except OSError, e:
            write_log("Error :%s\n" % e)
            sys.exit(1)

    write_log("Done\n", False)

#c. check the ethernet, exit if 'Broadcom Limited Device d802' not in it or the eth driver is not bnxt_en
def check_Ethernet(vendor = "14e4", device_id = "d802", driver = "bnxt_en"):
    write_log("Check whether the ethernet is 'Broadcom' with vendor 14e4 and device id d802...")
    vendor=quote_str(vendor)
    device_id=quote_str(device_id)
    cmd = 'lspci -nn -vv | grep Ethernet | grep Broadcom | grep \'' + vendor + ':' + device_id + '\''
    
    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error :%s\n" % e)
        return False

    if len(out) < 1:
        write_log('Ethernet is not Broadcom with vendor 14e4 and device id d802, so exit\n')
        sys.exit(1)

    write_log("Done\n", False)
    write_log("Check whether the eth driver is 'bnxt_en'...")
    cmd = 'ethtool -i eth1 | grep -w ' + driver
    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error :%s\n" % e)
        return False

    if len(out) < 1:
        write_log('Ethernet driver is not %s, so exit\n' %(driver) )
        sys.exit(1)

    write_log("Done\n", False)
    return True

# check whether eth1 is up now
def is_eth_up(ethernet = "eth1", ip = "169.254.68.1"):
    ethernet = quote_str(ethernet)
    cmd = 'ifconfig -a | grep -w ' + ethernet
    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error: %s, exit\n" % e)
        sys.exit(1)

    if len(out) < 1:
        write_log('Error\n%s is not exist, so exit\n' %(ethernet))
        sys.exit(1)

    for line in out:
        if 'UP' not in line:
            return False
        if 'RUNNING' not in line:
            return False
    ip = quote_str(ip)
    cmd = 'ifconfig -a | grep -A 5 -w ' + ethernet + ' | grep -w ' + ip
    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error: %s, exit\n" % e)
        sys.exit(1)

    if len(out) >= 1:
        return True
    return False

def check_eth_status():
    global os_name
    if os_name == 'Ubuntu':
        check_eth_status_ubuntu()
    else:
        check_eth_status_centos()


def check_eth_status_ubuntu(ethernet = "eth1", ip = "169.254.68.1", netmask = "255.255.255.252"):
    write_log("Check whether the eth1 is set to up permanently...\n")
    global os_name
    need_format = True
    ifcfg_file = "/etc/network/interfaces"
    tmp = ip.split('.')
    base = ''
    for i in range(len(tmp)-1):
        base += tmp[i] + '.'
    network = base + '0'
    bc = str(255 - int(netmask.split('.')[-1]))
    broadcast = base + bc

    cmd = 'grep eth1 /etc/network/interfaces'

    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error: %s, exit\n" % e)
        sys.exit(1)

    if out == '':
        need_format = False
    else:
        need_format = True

    if need_format == True:
        with open(ifcfg_file, 'w') as f:
            conf = "auto " + ethernet
            conf += "\niface " + ethernet + " inet static"
            conf += "\naddress " + ip
            conf += "\nnetwork " + network
            conf += "\nnetmask " + netmask
            conf += "\nbroadcast " + broadcast
            # conf += "\ngateway " + gateway
            f.write(conf)
        if not is_eth_up(ethernet, ip):
            ethernet = quote_str(ethernet)
            cmd = 'ifdown ' + ethernet + ' && ifup ' + ethernet
            try:
                out = os.popen(cmd, 'r').readlines()
            except OSError, e:
                write_log("Error: %s, exit\n" % e)
                sys.exit(1)

            if not is_eth_up(ethernet, ip):
                write_log('Error:%s is down, and try to up it failed\n' %(ethernet))
                sys.exit(1)

        write_log("Done\n", False)
        return True



#c. up eth1 with ip "169.254.68.1/30" if it is down
def check_eth_status_centos(ethernet = "eth1", ip = "169.254.68.1", netmask = "255.255.255.252"):
    write_log("Check whether the eth1 is set to up permanently...")
    global os_name
    ifcfg_path = "/etc/sysconfig/network-scripts"
    if os_name == 'SLES':
        ifcfg_path = "/etc/sysconfig/network"

    tmp = ip.split('.')
    base = ''
    for i in range(len(tmp)-1):
        base += tmp[i] + '.'
    network = base + '0'
    bc = str(255 - int(netmask.split('.')[-1]))
    broadcast = base + bc
    ethernet = quote_str(ethernet) 

    if os.path.exists(ifcfg_path):
        conf_file_name = 'ifcfg-' + ethernet
        eth_ifcfg_path = os.path.join(ifcfg_path,conf_file_name)
        with open(eth_ifcfg_path,'w') as f:
            conf = "NAME=" + ethernet
            conf += "\nDEVICE=" + ethernet
            conf += "\nBOOTPROTO=static"
            conf += "\nTYPE=Ethernet"
            conf += "\nBROADCAST=" + broadcast
            conf += "\nIPADDR=" + ip
            conf += "\nIPV6INIT=yes"
            conf += "\nIPV6_AUTOCONF=yes"
            conf += "\nNETMASK=" + netmask
            conf += "\nNETWORK=" + network
            conf += "\nONBOOT=yes\n"
            if os_name == 'SLES':
                conf += "STARTMODE=auto\n"
            f.write(conf)
        if not is_eth_up(ethernet, ip):
            cmd = 'ifdown ' + ethernet + ' && ifup ' + ethernet
            try:
                out = os.popen(cmd, 'r').readlines()
            except OSError, e:
                write_log("Error: %s, exit\n" % e)
                sys.exit(1)

            if not is_eth_up(ethernet, ip):
                write_log('Error:%s is down, and try to up it failed\n' %(ethernet))
                sys.exit(1)

        write_log("Done\n", False)
        return True
    else:
        write_log('Warning: open ifcfg file failed, can not persist the ethernet config!\n')
        if not is_eth_up(ethernet, ip):
            write_log('Now try to up %s just for once.\n' %(ethernet))
            ethernet = quote_str(ethernet)
            ip = quote_str(ip)
            netmask = quote_str(netmask)
            broadcast = quote_str(broadcast)
            cmd = 'ifconfig ' + ethernet + ' down && ifconfig ' + ethernet + ' ' + ip + 'netmask ' + netmask + ' broadcast ' + broadcast + ' up'
            try:
                out = os.popen(cmd, 'r').readlines()
            except OSError, e:
                write_log("Error: %s, exit\n" % e)
                sys.exit(1)
            if not is_eth_up(ethernet, ip):
                write_log('Error:%s is down, and try to up it failed\n' %(ethernet))
                sys.exit(1)
        return False
    


# get diskid from /sys/block/sd*/device/model
def get_diskid(device):
    diskid_info_path = os.path.join('/sys/block/', device,'device/model')

    # legal char in the file(/sys/block//device/model) except number and letter
    diskid_legal_char = '-_.!?'
    #write_log('try to get disk-info from path: %s\n' %(diskid_info_path) )
    
    try:
        f = open(diskid_info_path,'r').read()
    except IOError, e:
        write_log("can't open diskid_info_path:%s, with error %s\n" % (diskid_info_path,e))
        return (2,e)

    if len(f) < 1:
        write_log("No info about the diskid of %s\n" % x)
        return (3,'')

    #remove the illegal char in device/model
    disk_id = ''.join(list(filter(lambda ch: ch.isalnum() or ch in diskid_legal_char,f)))

    if('disk-' not in disk_id):
        #write_log("the format of %s is illegal\n" % disk_id)
        return (1,disk_id)

    return (0,disk_id)

# set the timeout in /sys/block/sd*/device/timeout
def set_timeout(device,timeout=8640):
    timeout_path = os.path.join('/sys/block/',os.path.basename(device),'device/timeout')
    try:
        f = open(timeout_path,'w+')
    except IOError, e:
        write_log("set timeout error: %s\n" % e)
        return 1

    try:
        original=f.read().strip()
    except IOError, e:
        original=''
        write_log("read timeout error: %s\n" % e)

    write_log("Original timeout of %s is %s \n" % (device, original))

    if  original != '8640':
        write_log("Now Change timeout from %s to %d \n" % (original, timeout))
        try:
            f.write("%d"%timeout)
        except IOError, e:
            write_log("write timeout error: %s\n" % e)
    else:
        write_log("No need to change timeout!\n")

    f.close()

# set the max_sectors_kb in /sys/block/sd*/queue/max_sectors_kb
def set_max_sectors_kb(device,max_sectors_kb=512):
    dest_path = os.path.join('/sys/block/',os.path.basename(device),'queue/max_sectors_kb')
    try:
        f = open(dest_path,'w+')
    except IOError, e:
        write_log("set max_sectors_kb error: %s\n" % e)
        return 1

    try:
        original=f.read().strip()
    except IOError, e:
        original=''
        write_log("read max_sectors_kb error: %s\n" % e)

    write_log("Original max_sectors_kb of %s is %s \n" % (device, original))

    if  original == '' or int(original) > 512:
        write_log("Now Change max_sectors_kb from %s to %d \n" % (original, max_sectors_kb))
        try:
            f.write("%d"%max_sectors_kb)
        except IOError, e:
            write_log("write max_sectors_kb error: %s\n" % e)
    else:
        write_log("No need to change max_sectors_kb!\n")
    
    f.close()

def set_softlink(sl_path,real_path):
    if os.path.exists(sl_path):
        #now check the softlink
        if os.path.islink(sl_path) and os.readlink(sl_path) == real_path:
            return 0
        else:
            write_log("The softlink %s incorrect,try to remove it\n" % (sl_path))
            if not os.path.isdir(sl_path): 
                try:
                    os.remove(sl_path)
                except OSError,e:
                    write_log("Remove %s failed, with error: %s\n" % (sl_path,e))
                    return 1
            else:
                try:
                    os.rmdir(sl_path)
                except OSError,e:
                    write_log("Remove directory %s failed, with error: %s\n" % (sl_path,e))
                    return 1

    write_log("Now set softlink from %s to %s\n" % (sl_path, real_path))
    os.symlink(real_path, sl_path)

    # set timeout for new session
    set_timeout(os.path.basename(real_path))
    set_max_sectors_kb(os.path.basename(real_path))

    return 0

# d. if the iscsi has login but there's no softlink, try to creat softlink for them
def check_softlink():
    sd_info_path = '/sys/block/'
    real_path_prefix = '/dev/'
    device_keyword = 'sd'
    
    for x in os.listdir(sd_info_path):
        #write_log('test device: %s\n' % x)

        if device_keyword in x:
            #write_log('check the device type and diskid for %s\n' %(x) )
            # There should be a correspond device in /dev
            real_path = os.path.join(real_path_prefix, x)
            if not os.path.exists(real_path):
                write_log('device %s is not exist in /dev!\n' %(x) )
                continue
            
            (status,disk_id) = get_diskid(x)
            if status > 0:
                continue

            sl_path = os.path.join('/dev/disk/by-id/',disk_id)
            set_softlink(sl_path,real_path)

            sl_path = os.path.join('/dev/disk/by-id/','virtio-' + disk_id)
            set_softlink(sl_path,real_path)
                         
# check softlink every 5 mins
def do_check_softlink(): 
    while(True):
        check_softlink()
        time.sleep(5)

# run do_check_softlink by thread
def creat_softlink_checker():
    write_log("Creat a thread for softlink_checker...")
    t = threading.Thread(target=do_check_softlink, name='SoftlinkCheckerThread')
    t.start()
    write_log("Done\n", False)

# check whether the session has been established
def check_session(target = ''):
    cmd = "iscsiadm -m session"
    no_session = "iscsiadm: No active sessions."

    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error :%s\n" % e)
        return 1

    if len(out) < 1:
        write_log("Check Session: no Result\n")
        return 2

    for line in out:
        write_log("Session : %s\n" % line)
        if target in line:
            if no_session in line:
                write_log("Check Session: No active sessions\n")
                return 3
            else:
                return 0

    write_log("Check Session: Do not find session %s\n" %(target)) 
    return 4

# just for login and logout
def exec_cmd(cmd = ''):
    write_log('%s, handle cmd: %s\n' %(time.ctime(), cmd) )
    cmd = quote_str(cmd)
    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error :%s\n" % e)
        return (1, 'Exec Cmd Error')

    if len(out) < 1:
        write_log('%s Error :No results\n' %(cmd) )
        return (2, 'No Results Error')

    res = False
    for line in out:
        write_log('%s' %(line) )
        if 'successful' in line:
            res = True
            write_log('Exec successful\n')
            break

    if not res:
        write_log('%s Error: Exec Failed\n' %(cmd) )
        return (3, 'Exec Failed')

    return (0, 'OK')

# after a target is logined, there will be a disk id in /dev/disk/by-path/
def find_diskid(target = ''):
    # check disk by-path
    id_path = '/dev/disk/by-path/'
    for x in os.listdir(id_path):
        write_log('pase: %s\n' % x)

        if target in x:
            write_log('target: %s, disk by-path: %s\n' %(target, x) )

            uuid_path = os.path.join(id_path, x)
            if not os.path.islink(uuid_path):
                write_log('uuid_path %s is not link\n' %(uuid_path) )
                #return (1, 'INVALID UUID PATH')
                continue

            real_path = os.readlink(uuid_path)
            if real_path[-1] in '0123456789' and 'part' in x:
                write_log('real_path: %s is a partition,check next\n' %(real_path) )
                continue
            write_log('real_path: %s\n' %(real_path) )
            path = os.path.abspath(os.path.join(id_path, real_path))
            write_log('path: %s\n' %(path) )
            

            if not os.path.exists(path):
                write_log('path: %s is not exist\n' %(path) )
                return (1, 'INVALID DISK ID')

            return (0, path)

    return (1, 'INVALID DISK ID')


# check whether disk is mount
def check_mount(diskid = ''):
    mounted = False
    device = []

    with open('/proc/mounts','r') as f:
        for l in f:
            dev = l.split( )[0]
            if diskid in dev:
                if os.path.dirname(diskid) != os.path.dirname(dev):
                    continue
                write_log('/proc/mounts: %s' %(l) )
                write_log('device %s is mounted\n' %(dev) ) 
                mounted = True
                device.append(dev)

    return (mounted,device)

def discovery_targets(ipport = '169.254.68.2:3260'):
    ret = []
    cmd = quote_str('iscsiadm -m discovery -t st -p ' + ipport)
    
    write_log('%s, handle: %s\n' %(time.ctime(), cmd) )
    
    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error :%s\n" % e)
        return (1, ret)

    if len(out) < 1:
        write_log("No results\n")
        return (0, ret)

    for line in out:
        write_log('%s' %(line) )
        
        # FIXME. if discovery failed, perhaps no open-iscsi running or iscsi.ko

        target = line.split( )[1]
        write_log('get target: %s\n' %(target) )
        ret.append(target)

    return (0, ret)

#delete the record in iscsi-tgt after logout
def delete_record(target = ''):
    cmd = quote_str('iscsiadm -m node -o delete -T ' + target)
    write_log('%s, handle: %s\n' %(time.ctime(), cmd) )

    try: # response of delete has no 'successful', CAN NOT use exec_cmd
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error :%s\n" % e)

    return 0

def find_softlink(diskid = ''):
    sl_path = '/dev/disk/by-id/'
    for x in os.listdir(sl_path):
        if 'disk-' not in x:
            continue
        path = os.path.join(sl_path, x)
        if os.path.islink(path):
            real_path = os.readlink(path)
            write_log('sl_path: %s, real_path: %s\n' %(path, real_path) )

            if real_path == diskid:
                write_log('find softlink\n')                
                return (0, path)

    return (1, 'NULL')

def target_match(target = ''):
    pattern = r'^iqn\..+spdk:([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$'
    match = re.match(pattern, target)
    return bool(match)

#########################

def process_attach(target = '', volume = '', client_address = ''):
    if target != '1' or volume != '2':
        if client_address != "169.254.68.2":
            return (1, 'IP NOT ALLOW, ATTACH FAILED')
        if not target_match(target):
            write_log("Error target:%s\n" % target)
            return (1, 'ATTACH FAILED')
    # 1. discovery
    (status, targets) = discovery_targets()
    if status > 0:
        write_log("Error: discovery failed\n")
        return (1, 'DISCOVERY FAILED')

    if target not in targets:
        write_log("not discovery target %s\n" % target)
        return (1, 'NOT DISCOVERY TARGET')

    # 2. login
    already_login = False
    cmd = 'iscsiadm -m node -l -T ' + target
    (status, resp) = exec_cmd(cmd)
    #check whether the session has been established
    session = check_session(target)
    if session > 0:
        if status > 0:
            return (1, 'LOGIN FAILED')
        else:
            write_log("Error: Login successful but there's no active session\n")
            return (1,'LOGIN FAILED')
    # if the output of login cmd is none, the session has already been established
    elif status == 2:
        already_login = True

    # 3. check by-id
    # timeout: 10ms*300 = 3s
    timeout=300
    count=0
    write_log("Waitlink......\n")
    (status, diskid) = find_diskid(target)
    while (status > 0 and count < timeout):
        time.sleep(0.01)
        (status, diskid) = find_diskid(target)
        count = count + 1
    
    if status > 0:
        cmd = 'iscsiadm -m node -u -T ' + target
        (status, resp) = exec_cmd(cmd)
        if status > 0:
            return (1, 'DEVICE NOT FIND AND LOGOUT FAILED')
        delete_record(target)
        return (1, 'DEVICE NOT FIND')

    # 4. check the format of volume
    (device_path,device_name) = os.path.split(diskid)
    (status,disk_id) = get_diskid(device_name)
    if(status > 0 or disk_id != volume):
        if(status > 0):
            write_log("can not get legal disk_id from /sys/block/%s/device/model\n" % (device_name) )
        else:
            write_log("disk_id is %s, and volume is %s, input error\n" % (disk_id,volume) )

        # if login just now, we should logout, delete record and return failed
        if not already_login:
            session = check_session(target)
            if session == 0:
                #if session exist, logout first 
                cmd = 'iscsiadm -m node -u -T ' + target
                (status, resp) = exec_cmd(cmd)
                if status > 0:
                    return (1, 'DISKID INCORRECT AND LOGOUT FAILED')

            # delete record
            delete_record(target)

        return (1, 'DISKID INCORRECT')

    # 5. set soft link and timeout and max_sector_size
    dst = '/dev/disk/by-id/' + volume
    set_softlink(dst,diskid)

    dst = '/dev/disk/by-id/virtio-' + volume
    set_softlink(dst,diskid)

    if already_login:
        return (0, 'ALREADY_LOGIN')
    else:
        return (0, 'SUCCESS')


def process_detach(target = '', forceflag = '--noforce', client_address = ''):
    if client_address != "169.254.68.2":
        return (1, 'IP NOT ALLOW, DETACH FAILED')
    if not target_match(target):
        write_log("Error target:%s\n" % target)
        return (1, 'DETACH FAILED')
    # 0. force or not
    force = False

    diskid_exist = True
    softlink_exist = True

    if forceflag == '--force':
        force = True

    # 1. find disk-id and softlink
    (status, diskid) = find_diskid(target)
    if status > 0:
        diskid_exist = False
        write_log("process_detach : Not find diskid\n")

    (status, softlink) = find_softlink(diskid)
    if status > 0:
        softlink_exist = False
        write_log("process_detach : Not find softlink\n") 

    # 2. check mounted
    mounted = False
    if(diskid_exist):
        (mounted,device) = check_mount(diskid)

    # 3. if mounted and force, try to umount; and not force, exit.
    if mounted:
        if force:
            for dev in device:
                cmd = quote_str('umount ' + dev)
                write_log('%s, handle: %s\n' %(time.ctime(), cmd) )

                try:
                    out = os.popen(cmd, 'r').readlines()
                except OSError, e:
                    write_log("Error :%s\n" % e)

        else: # not force
            write_log("%s is mounted, and not force to logout, just exit\n" % diskid)            
            return (0, 'MOUNTED AND NOT LOGOUT')

    # 4. delete softlink
    delete_softlink_flag = softlink_exist
    while delete_softlink_flag:
        if os.path.exists(softlink):
            os.remove(softlink)
        (status, softlink) = find_softlink(diskid)
        if status > 0:
            delete_softlink_flag = False

    #5.check session
    session = check_session(target)
    if session > 0:
        #if session not exist, just delete record
        delete_record(target)
        return (2,'NOTHING_TO_DO')
    else:
        #if session exist, logout and delete record
        cmd = 'iscsiadm -m node -u -T ' + target
        (status, resp) = exec_cmd(cmd)
        if status > 0:
            return (3, 'LOGOUT FAILED')
        delete_record(target)
        if not (diskid_exist and softlink_exist):
            return (1, 'LOGOUT')  

    return (0, 'SUCCESS')

def process_rescan(target = '', client_address = ''):
    if client_address != "169.254.68.2":
        return (1, 'IP NOT ALLOW, RESCAN FAILED')
    if not target_match(target):
        write_log("Error target:%s\n" % target)
        return (1, 'RESCAN FAILED')

    cmd = quote_str('iscsiadm -m node -R -T ' + target)
    write_log('%s, handle: %s\n' %(time.ctime(), cmd) )  

    try:
        out = os.popen(cmd, 'r').readlines()
    except OSError, e:
        write_log("Error :%s\n" % e)      

    rescan = False
    for line in out:
        write_log('%s' %(line) )
        
        if 'Rescanning' in line:
            rescan = True
            write_log('rescan successful\n')

    if not rescan:
        write_log('rescan Failed\n')
        return (1, 'RESCAN FAILED')

    return (0, 'SUCCESS')

def process_request(request, client_addres = ''):
    args = request.split( )
    if len(args) < 3:
        write_log("Error: invalid arguments, %s\n" % request) 
        return (1, 'INVAID ARGUMENTS')

    if args[0] == 'attach':
        (ret, msg) = process_attach(args[1], args[2], client_addres)
    elif args[0] == 'detach':
        (ret, msg) = process_detach(args[1], args[2], client_addres)
    elif args[0] == 'rescan':
        (ret, msg) = process_rescan(args[1], client_addres)
    else:
        write_log("Error: invalid arguments, %s\n" % request)
        return (1, 'INVAID ARGUMENTS')

    return (ret, msg)

class ProxyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        conn = self.request
        self.data = conn.recv(256).strip()
        write_log('from [%s] recv request: %s\n' %(self.client_address, self.data) )
        client_addres_str = self.client_address[0]
        (eno, rsp) = process_request(self.data, client_addres_str)
        write_log('(%d) response: %s\n' %(eno, rsp))

        self.data = '%d+' % eno
        self.data += rsp
        conn.sendall(self.data.upper())

def socket_server(localip = '169.254.68.1', port = 9966):
    # socket
    SocketServer.TCPServer.allow_reuse_address = True
    server = SocketServer.TCPServer((localip, port), ProxyTCPHandler)
    write_version()
    write_log("SocketServer starting...\n")
    server.serve_forever()


###########################################################

# main
def main():
    log_rotate()
    check_os()
    check_iscsi()
    check_iscsi_config()
    change_proc_name(proxy_name)
    check_proc()
    check_Ethernet()
    check_eth_status()
    daemonize()
    creat_softlink_checker()
    socket_server()

# main
if __name__ == "__main__":
    main()