#!/usr/bin/python
# coding:utf-8
import traceback
import psutil
import socket
import sys
import os
import time
import argparse
import subprocess
import logging
import logging.handlers
import json
from collections import OrderedDict
from six.moves.configparser import RawConfigParser as ConfigParser
import pwd
import grp
import re
current_dir = sys.path[0]


class MyConfigParser(ConfigParser):
    """Modified ConfigParser that allow ':' in keys and only '=' as separator.
    """
    OPTCRE = re.compile(
        r'(?P<option>[^=\s][^=]*)'          # allow only = 
        r'\s*(?P<vi>[=])\s*'                # for option separator           
        r'(?P<value>.*)$'                   
        )


class Usage(Exception):
    def __init__(self, msg):
        self.msg = msg


SUPPORTED_SERVICE = ['cinder', 'drextend', 'cps']
DEFAULT_SERVICE = 'cinder'
port = {'cinder': 10518, 'drextend': 10518, 'cps': 11520}
ip = {'cinder': '127.0.0.1', 'drextend': '127.0.0.2', 'cps': '127.0.0.1'}
usage = 'cinder'
FSC_BASE = {'cinder': '/usr/bin',
            'drextend': '/etc/cps_drextend/others/plugins/fusionstorage',
            'cps': '/opt/fusionstorage_driver_for_cps'}
LIB_BASE = {'cinder': '/usr/bin',
            'drextend': '/etc/cps_drextend/others/plugins/fusionstorage',
            'cps': '/usr/bin'}
FSC_CMD = {'cinder': 'fsc_cli', 'drextend': 'fsc_cli', 'cps': 'fsc_4_fsp_cli'}
JAVA_BASE = {'cinder': '/usr/share/dsware',
             'drextend': '/etc/cps_drextend/others/plugins/fusionstorage',
             'cps': '/usr/share/dsware'}
RUN_USER = {'cinder': 'openstack', 'drextend': 'openstack', 'cps': 'cps'}
MAIN_CLASS = 'com.huawei.fsc.tools.FSCTools'

timeout = 125
SOCKET_CONNECT_TIMEOUT = 51010018
SOCKET_READ_TIMEOUT = 51010019
UNKNOWN_FAILURE = 51011000
retry_times = 0


def is_py2():
    import sys
    return True if 2 == sys.version_info[0] else False


# python2和3版本兼容读取文件
def open_file_by_environment(file_name, mode='r'):
    if is_py2():
        return open(file_name, mode)
    else:
        return open_file_4python3(file_name, mode)


# python3 打开文件
def open_file_4python3(file_name, mode='r', encoding=None, **kwargs):
    if mode in ['r', 'rt', 'tr'] and encoding is None:
        encoding = open_file_encoding(file_name, encoding)
    return open(file_name, mode=mode, encoding=encoding, **kwargs)


def open_file_encoding(file_name, encoding=None):
    with open(file_name, 'rb') as f:
        context = f.read()
        for encoding_item in ['UTF-8', 'GBK', 'ISO-8859-1']:
            try:
                context.decode(encoding=encoding_item)
                encoding = encoding_item
                break
            except UnicodeDecodeError as e:
                logger.error("open file except %s" % e)
                pass
    return encoding


def _send(socket_obj, message):
    try:
        socket_obj.send(message)
    except socket.error:
        print("result=" + str(UNKNOWN_FAILURE))
        logger.error("description=\"System socket send error\"")
        socket_obj.close()
        exit(0)


def execute_cmd(cmd):
    pid = os.fork()
    if pid:
        sys.exit(0)
    os.chdir('/')
    os.umask(0)
    os.setsid()
    _pid = os.fork()
    if _pid:
        sys.exit(0)
    sys.stdout.flush()
    sys.stderr.flush()
    with open('/dev/null') as read_null, open('/dev/null', 'w') as write_null:
        os.dup2(read_null.fileno(), sys.stdin.fileno())
        os.dup2(write_null.fileno(), sys.stdout.fileno())
        os.dup2(write_null.fileno(), sys.stderr.fileno())
    logger.info("%s" % cmd)
    os.popen(cmd)
    exit(0)


def start_dsware_api_daemon(floatIP, listen_port):
    if os.geteuid() == 0:
        logger.info("start daemon with root")
        start_dsware_api_daemon_as_root(floatIP, listen_port)
    else:
        newpid = os.fork()
        if newpid == 0:
            logger.info("switch root to start daemon with usage %s" % usage)
            cmd = "sudo %s/%s --op rootStartServer --manage_ip %s"\
                  % (FSC_BASE[usage], FSC_CMD[usage], floatIP)
            logger.info("root start cmd: %s" % cmd)
            execute_cmd(cmd)
        else:
            os.waitpid(newpid, 0)
            logger.info("wait sub pid %s finished" % newpid)


def start_dsware_api_daemon_as_root(floatIP, listen_port):
    logger.info("root start daemon with ip %s : %s" % (floatIP, listen_port))
    ld_path = os.getenv("LD_LIBRARY_PATH")
    fsc_cli_path = LIB_BASE[usage] + "/lib"
    if not ld_path:
        os.environ["LD_LIBRARY_PATH"] = fsc_cli_path
    if ld_path and fsc_cli_path not in ld_path:
        os.environ["LD_LIBRARY_PATH"] += ":" + fsc_cli_path

    OS_ENV = os.environ.copy()

    proc = find_proc(floatIP, listen_port)
    # jar sever exist
    if proc:
        logger.warning("proc exist return")
        return
    lib_path = LIB_BASE[usage] + '/lib'
    cwd_path = LIB_BASE[usage]
    java_home = os.popen("ls -d %s/jre* | grep -v tar"
                         % JAVA_BASE[usage]).readlines()[0].replace("\n", "")
    java_path = java_home + "/bin"
    OS_ENV['JAVA_HOME'] = java_home
    OS_ENV['PATH'] = java_path + ':' + OS_ENV['PATH']

    cmd_bin = [
        "java", "-Xms256m", "-Xmx700m",
        "-Djava.ext.dirs=%s:%s/lib/ext" % (lib_path, java_home),
        MAIN_CLASS, "--op", "startServer", "--ip", ip[usage],
        "--port", str(listen_port)]
    logger.info(" ".join(cmd_bin))
    fnull = open_file_by_environment(os.devnull, 'w')

    subprocess.Popen(cmd_bin, cwd=cwd_path, env=OS_ENV, stdout=fnull,
                     stderr=fnull)
    logger.info("Start FSCTool service successfully.")


def init_help():
    global helper
    helper = {
        "startServer": "",
        "restartServer": "",
        "rootStartServer": "",
        "changeWriteProtect": " --manage_ip \"manage_ip\" --ip "
                              "\"dswareAgentIp1,...,dswareAgentIp3\" "
                              "--volName \"volumeName\""
                              " --lunRwRight \"lunRwRight\"",
        "createBitmapVolume": " --manage_ip \"manage_ip\" "
                              "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                              " --snapNameFrom \"snapNameFrom\" "
                              "--snapNameTo \"snapNameTo\" "
                              "--volName \"volName\" --poolId \"poolID\"",
        "createFullVolumeFromSnap": " --manage_ip \"manage_ip\" "
                                    "--ip \"dswareAgentIp1,...,dswareAgentIp\""
                                    " --volName \"volumeName\""
                                    " --snapName \"sourceSnapshotName\"",
        "createSnapshot": " --manage_ip \"manage_ip\" "
                          "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                          " --snapName \"snapshotName\" "
                          "--volName \"volumeName\" --smartFlag \"smartFlag\"",
        "createVolume": " --manage_ip \"manage_ip\" "
                        "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                        " --volName \"volumeName\" --poolId \"poolID\""
                        " --volSize \"volumeSize\" --thinFlag \"thinFlag\""
                        " [--encrypted \"encrypted\"]",
        "createVolumeFromSnap": " --manage_ip \"manage_ip\" "
                                "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --volName \"volumeName\" "
                                "--volSize \"volumeSize\" "
                                "--snapNameSrc \"sourceSnapshotName\"",
        "createVolumesFromSnap": " --manage_ip \"manage_ip\" "
                                 "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                 " --volName \"volumeName1\" \"volumeName2\""
                                 " \"...\" --volSize \"volumeSize\" "
                                 "--snapNameSrc \"sourceSnapshotName\"",
        "duplicateSnapshot": " --manage_ip \"manage_ip\" "
                             "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                             "--snapNameSrc \"sourceSnapshotName\" "
                             "--snapNameDst \"destinationSnapshotName\" "
                             "--poolId \"poolID\" "
                             "--fullCopyFlag \"fullCopyFlag\" "
                             "--smartFlag \"smartFlag\"",
        "createQoS": " --manage_ip \"manage_ip\" "
                     "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                     "--qosName \"qosName\" --maxIOPS \"maxIOPS\" "
                     "--IOPSPerGB \"IOPSPerGB\" "
                     "--minBaselineIOPS \"minBaselineIOPS\" "
                     "--burstIOPS \"burstIOPS\" --creditIOPS \"creditIOPS\"  "
                     "--maxMBPS \"maxMBPS\"  --MBPSPerTB  \"MBPSPerTB\" "
                     "--burstMBPSPerTB  \"burstMBPSPerTB\" "
                     "--minBaselineMBPS  \"minBaselineMBPS\"  "
                     "--readLimitIOPS \"readLimitIOPS\" "
                     "--readLimitMBPS \"readLimitMBPS\" "
                     "--writeLimitIOPS \"writeLimitIOPS\" "
                     "--writeLimitMBPS  \"writeLimitMBPS\"",
        "associateQoSWithPool": " --manage_ip \"manage_ip\" "
                                "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                                "--qosName \"qosName\" --poolId \"poolId\"",
        "disassociateQoSWithPool": " --manage_ip \"manage_ip\" "
                                   "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                   " --qosName \"qosName\""
                                   " --poolId \"poolId\"",
        "associateQoSWithVolume": " --manage_ip \"manage_ip\" "
                                  "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                  " --qosName \"qosName\" "
                                  "--volName \"volName\"",
        "disassociateQoSWithVolume": " --manage_ip \"manage_ip\" "
                                     "--ip \"dswareAgentIp1,...,"
                                     "dswareAgentIp3\" "
                                     "--qosName \"qosName\" "
                                     "--volName \"volName\"",
        "expandVolume": " --manage_ip \"manage_ip\" "
                        "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                        " --volName \"volName\" --volSize \"newVolSize\"",
        "setQoS": " --manage_ip \"manage_ip\" "
                  "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                  "--qosName \"qosName\" --maxIOPS \"maxIOPS\" "
                  "--IOPSPerGB \"IOPSPerGB\" "
                  "--minBaselineIOPS \"minBaselineIOPS\" "
                  "--burstIOPS \"burstIOPS\" --creditIOPS \"creditIOPS\" "
                  " --maxMBPS \"maxMBPS\"  --MBPSPerTB  \"MBPSPerTB\""
                  " --burstMBPSPerTB  \"burstMBPSPerTB\" "
                  "--minBaselineMBPS  \"minBaselineMBPS\"  "
                  "--readLimitIOPS \"readLimitIOPS\" "
                  "--readLimitMBPS \"readLimitMBPS\" "
                  "--writeLimitIOPS \"writeLimitIOPS\" "
                  "--writeLimitMBPS  \"writeLimitMBPS\"",
        "deleteQoS": " --manage_ip \"manage_ip\" "
                     "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                     " --qosName \"qosName\"",
        "attachVolume": " --manage_ip \"manage_ip\" "
                        "--ip \"dswareAgentIp1\" --volName \"volName\"",
        "detachVolume": " --manage_ip \"manage_ip\" "
                        "--ip \"dswareAgentIp1\" --volName \"volName\"",
        "detachVolumeByIp": " --manage_ip \"manage_ip\" "
                            "--ip \"dswareAgentIp1\" --volName \"volName\""
                            " --detachIp \"detachIp\"",
        "batchAttachVolume": " --manage_ip \"manage_ip\" "
                             "--ip \"dswareAgentIp1\" "
                             "--volNameList \"vol1,vol2,...,voln\""
                             " --volNum \"volNum\"",
        "activeSnapshots": " --manage_ip \"manage_ip\" "
                           "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                           " --snapNameList \"snap1,snap2,...,snapn\""
                           " --volNameList \"vol1,vol2,...,voln\"",
        "deleteSnapshot": " --manage_ip \"manage_ip\" "
                          "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                          " --snapName \"snapshotName\"",
        "deleteVolume": " --manage_ip \"manage_ip\" "
                        "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                        " --volName \"volumeName\"",
        "queryAllBitmapVolume": " --manage_ip \"manage_ip\" "
                                "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --poolId \"poolID\"",
        "queryAllPoolInfo": " --manage_ip \"manage_ip\" "
                            "--ip \"dswareAgentIp1,...,dswareAgentIp3\"",
        "queryAllSnapshot": " --manage_ip \"manage_ip\" "
                            "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                            " --poolId \"poolID\"",
        "queryAllVolume": " --manage_ip \"manage_ip\" "
                          "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                          " --poolId \"poolID\"",
        "queryBitmapVolume": " --manage_ip \"manage_ip\""
                             " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                             " --volName \"volName\" --poolId \"poolID\"",
        "queryPoolInfo": " --manage_ip \"manage_ip\" "
                         "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                         "--poolId \"poolID\"",
        "querySnapOfVolume": " --manage_ip \"manage_ip\" "
                             "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                             "--volName \"volumeName\"",
        "querySnapshot": " --manage_ip \"manage_ip\" "
                         "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                         " --snapName \"snapshotName\"",
        "queryVolume": " --manage_ip \"manage_ip\""
                       " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                       " --volName \"volumeName\"",
        "queryVolumeOfSnap": " --manage_ip \"manage_ip\""
                             " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                             " --snapName \"snapshotName\"",
        "duplicateVolume": " --manage_ip \"manage_ip\" "
                           "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                           " --volNameSrc \"volNameSrc\" "
                           "--volName \"volName\" --poolIdDst \"poolIdDst\"",
        "migrateVolumeCold": " --manage_ip \"manage_ip\" "
                             "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                             "--volNameSrc \"volNameSrc\" "
                             "--poolIdDst \"poolIdDst\"",
        "queryPoolType": " --manage_ip \"manage_ip\" "
                         "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                         " --poolType \"poolType\"",
        "getDSwareIdentifier": " --manage_ip \"manage_ip\" "
                               "--ip \"dswareAgentIp1,...,dswareAgentIp3\"",
        "getDSwareClusterVersion": " --manage_ip \"manage_ip\" "
                                   "--ip \"dswareAgentIp1,...,dswareAgentIp\"",
        "query_volume_attach": " --manage_ip \"manage_ip\" "
                               "--ip \"dswareAgentIp1\" --volume \"volName\"",
        "query_all_volume": " --manage_ip \"manage_ip\" "
                            "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                            " --pool \"poolID\"",
        "query_all_snapshot": " --manage_ip \"manage_ip\" "
                              "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                              " --pool \"poolID\"",
        "queryAllVolumeBatch": " --manage_ip \"manage_ip\""
                               " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                               " --pool \"poolID\" --pageNum \"pageNum\""
                               " --pageSize \"pageSize\"",
        "querySnapOfVolumeBatch": " --manage_ip \"manage_ip\" "
                                  "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                  " --volName \"volName\" "
                                  "--pageNum \"pageNum\""
                                  " --pageSize \"pageSize\"",
        "queryAllSnapshotBatch": " --manage_ip \"manage_ip\" "
                                 "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                 " --pool \"poolID\" --pageNum \"pageNum\""
                                 " --pageSize \"pageSize\"",
        "queryQoS": " --manage_ip \"manage_ip\" "
                    "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                    "--pageNum \"pageNum\"  --pageSize \"pageSize\" "
                    "--keyword \"keyword\" --queryType \"queryType\"",
        "queryPoolQoSInfo": " --manage_ip \"manage_ip\" "
                            "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                            " --poolId \"poolId\"",
        "queryVolumeQoSInfo": " --manage_ip \"manage_ip\" "
                              "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                              " --volName \"volName\"",
        "queryQoSAssociatedPool": " --manage_ip \"manage_ip\""
                                  " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                  " --qosName \"qosName\"",
        "queryQoSDisassociatedPool": " --manage_ip \"manage_ip\" "
                                     "--ip \"dswareAgentIp1,...,"
                                     "dswareAgentIp3\" "
                                     "--qosName \"qosName\"",
        "queryQoSAssociatedVolume": " --manage_ip \"manage_ip\" "
                                    "--ip \"dswareAgentIp1,...,dswareAgentIp\""
                                    " --qosName \"qosName\" "
                                    "--poolId \"poolId\" "
                                    "--queryType \"queryType\" "
                                    "--pageNum \"pageNum\"  "
                                    "--pageSize \"pageSize\" "
                                    "--keyword \"keyword\"",
        "queryQoSDisassociatedVolume": " --manage_ip \"manage_ip\" "
                                       "--ip \"dswareAgentIp1,...,"
                                       "dswareAgentIp3\" "
                                       "--qosName \"qosName\" "
                                       "--poolId \"poolId\" "
                                       "--queryType \"queryType\" "
                                       "--pageNum \"pageNum\"  "
                                       "--pageSize \"pageSize\" "
                                       "--keyword \"keyword\"",
        "rollbackSnapshot": " --manage_ip \"manage_ip\" "
                            "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                            " --snapName \"snapName\" --volName \"volName\"",
        "createLLDVolume": " --manage_ip \"manage_ip\" "
                           "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                           " --volName \"volumeName\" --poolId \"poolID\""
                           " --volSize \"volumeSize\" --thinFlag \"thinFlag\""
                           " --imageUUID \"imageUUID\" "
                           "--dataSrcURL \"dataSrcURL\""
                           " --imageSize \"imageSize\" "
                           "--imageOffset \"imageOffset\" "
                           "--cacheFlag \"cacheFlag\" --replace \"replace\""
                           " [--encrypted \"encrypted\"] [--cmkId \"cmkId\"]"
                           " [--authCredentials \"authCredentials\"]",
        "queryImgUsingVolNum": " --manage_ip \"manage_ip\" "
                               "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                               " --imageUUID \"imageUUID\"",
        "queryTestAllPoolInfo": " --manage_ip \"manage_ip\" "
                                "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --poolId \"poolIds\"",
        "serviceCmd": " --fsaIp \"dswareAgentIp1,...,dswareAgentIp3\" "
                      "--storageServiceArgs \"storageServiceArgs\"",
        "createHost": " --manage_ip \"manage_ip\" "
                      "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                      " --hostName \"hostName\"",
        "deleteHost": " --manage_ip \"manage_ip\" "
                      "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                      " --hostName \"hostName\"",
        "createHostGroup": " --manage_ip \"manage_ip\" "
                           "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                           " --hostGroupName \"hostGroupName\"",
        "deleteHostGroup": " --manage_ip \"manage_ip\" "
                           "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                           " --hostGroupName \"hostGroupName\"",
        "createPort": " --manage_ip \"manage_ip\" "
                      "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                      " --portName \"portName\"",
        "deletePort": " --manage_ip \"manage_ip\" "
                      "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                      " --portName \"portName\"",
        "addPortToHost": " --manage_ip \"manage_ip\" "
                         "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                         " --portName \"portName\" --hostName \"hostName\"",
        "delPortFromHost": " --manage_ip \"manage_ip\" "
                           "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                           " --portName \"portName\" --hostName \"hostName\"",
        "addLunToHost": " --manage_ip \"manage_ip\" "
                        "--ip \"dswareAgentIp1,...,dswareAgentIp3\" "
                        "--hostName \"hostName\" --volName \"volName\"",
        "delLunFromHost": " --manage_ip \"manage_ip\" "
                          "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                          " --hostName \"hostName\" --volName \"volName\"",
        "addHostToHostGroup": " --manage_ip \"manage_ip\" "
                              "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                              " --hostName \"hostName\" "
                              "--hostGroupName \"hostGroupName\"",
        "delHostFromHostGroup": " --manage_ip \"manage_ip\" "
                                "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --hostName \"hostName\""
                                " --hostGroupName \"hostGroupName\"",
        "addVolumeToHostGroup": " --manage_ip \"manage_ip\" "
                                "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --hostGroupName \"hostGroupName\" "
                                "--volName \"volName\"",
        "delVolumeFromHostGroup": " --manage_ip \"manage_ip\" "
                                  "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                  " --hostGroupName \"hostGroupName\""
                                  " --volName \"volName\"",
        "queryHostLunInfo": " --manage_ip \"manage_ip\" "
                            "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                            " --hostName \"hostName\"",
        "queryLunFromHostGroup": " --manage_ip \"manage_ip\" "
                                 "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                 " --hostGroupName \"hostGroupName\"",
        "queryIscsiPortalInfo": " --manage_ip \"manage_ip\" "
                                "--ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --portName \"portName\"",
        "addChapUserToPort": " --manage_ip \"manage_ip\" "
                                " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --chapName \"chapName\""
                                " --iscsiType \"iscsiType\""
                                " --portName \"portName\"",
        "deleteChapUserFromPort": " --manage_ip \"manage_ip\" "
                                " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --chapName \"chapName\""
                                " --iscsiType \"iscsiType\""
                                " --portName \"portName\"",
        "delIscsiUser": " --manage_ip \"manage_ip\" "
                                " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --chapName \"chapName\""
                                " --type \"type\"",
        "addIscsiUser": " --manage_ip \"manage_ip\" "
                                " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --chapName \"chapName\""
                                " --chapSecret \"chapSecret\""
                                " --type \"type\"",
        "modifyPortChapStatus": " --manage_ip \"manage_ip\" "
                                " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --chapStatus \"chapStatus\"",
        "queryVbsEncryptFlag":  " --manage_ip \"manage_ip\" "
                                " --ip \"dswareAgentIp1,...,dswareAgentIp3\""
                                " --tenantId \"tenantId\""
    }


def sample_help(op):
    if op is None:
        for k, v in helper.items():
            print("    ./%s --op %s %s" % (FSC_CMD[usage], k, v))
    else:
        print("    ./%s --op %s %s" % (FSC_CMD[usage], op, helper[op]))


def find_proc(floatIP, listen_port):
    java_home = os.popen("ls -d %s/jre* | grep -v tar"
                         % JAVA_BASE[usage]).readlines()[0].replace("\n", "")
    java_path = java_home + "/bin"
    for proc in psutil.process_iter():
        # check whether the process name matches
        try:
            if proc.as_dict(attrs=['cmdline']).get('cmdline').__contains__(
                    MAIN_CLASS):
                # new version
                if proc.as_dict(attrs=['cmdline']).get('cmdline').__contains__(
                        floatIP) and proc.as_dict(attrs=['cmdline']).get(
                        'cmdline').__contains__(str(listen_port)):
                    logger.warning("Find a old FSCTool service process. PID:"
                                   + str(proc.pid))
                    return proc
                elif proc.as_dict(attrs=['cmdline']).get(
                        'cmdline').__contains__(java_path + '/java'):
                    logger.warning("Find a old FSCTool service process. PID:"
                                   + str(proc.pid))
                    return proc
        except psutil.NoSuchProcess:
            return None
    return None


def on_terminate(proc):
    logger.warning("process {} terminated".format(proc))


def restart_dsware_api_daemon(floatIP, listen_port):
    proc = find_proc(floatIP, listen_port)
    if proc:
        try:
            logger.warning("Terminate old FSCTool service process. PID:"
                           + str(proc.pid))
            proc.terminate()
            gone, still_alive = psutil.wait_procs([proc], 3,
                                                  callback=on_terminate)
            for p in still_alive:
                logger.warning("Send SIGKILL to old FSCTool service process."
                               " PID:" + str(p.pid))
                p.kill()
                time.sleep(3)
        except psutil.NoSuchProcess:
            pass
    start_dsware_api_daemon(floatIP, listen_port)


def run_command(floatIP, listen_port):
    input_args = sys.argv[1:]
    cmd = ' '.join(input_args)
    cmd = cmd + '\n'
    obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket.setdefaulttimeout(timeout)
    global retry_times
    retry_times = 1
    connect_to_service(floatIP, listen_port, obj)
    message_handler(cmd, obj)


def connect_to_service(floatIP, listen_port, obj):
    global retry_times
    try:
        obj.connect((ip[usage], listen_port))
    except socket.error:
        proc = find_proc(floatIP, listen_port)
        # jar sever exist
        if not proc:
            try:
                start_dsware_api_daemon(floatIP, listen_port)
            except Exception as e:
                logger.error("start dsware_api daemon exception %s" % e)
        # wait for the child process to start server successfully.
        logger.info("restart dsware and connect")
        retry_times += 1
        time.sleep(3)
        if retry_times < 3:
            connect_to_service(floatIP, listen_port, obj)


def message_handler(cmd, obj):
    try:
        _send(obj, cmd.encode("UTF-8"))
        logger.debug(cmd)
        logger.info('------' + cmd.split(" ")[1] + ' begin------')
        length = obj.recv(4)
        total_size = 0
        for i in range(len(length)):
            rsp_len = length[i]
            if isinstance(rsp_len, str):
                rsp_len = ord(rsp_len)
            total_size = total_size * 256 + rsp_len
        buf_size = 2048 if total_size >= 2048 else total_size
        sum_size = 0
        result = ''
        while sum_size < total_size:
            ret_bytes = obj.recv(buf_size)
            # when server socket disconnect, returned data is empty string.
            if not ret_bytes:
                break
            if isinstance(ret_bytes, bytes):
                ret_bytes = ret_bytes.decode()
            result += str(ret_bytes)
            sum_size += len(ret_bytes)
        print(result)
    except socket.timeout:
        print("result=" + str(SOCKET_READ_TIMEOUT))
        print("description=\"socket recv timeout\"")
        raise Exception("socket recv timeout")
    except socket.error:
        print("result=" + str(UNKNOWN_FAILURE))
        print("description=\"System socket recv error\"")
        raise Exception("System socket recv error")
    finally:
        logger.info('------' + cmd.split(" ")[1] + ' end------')
        obj.close()


def init_logging():
    # create console handler and set level to debug
    global logger
    logfile_dir = "/var/log/%s" % FSC_CMD[usage]
    logfile = os.path.join(logfile_dir, "fsc_cli_cmd.log")
    logger = logging.getLogger()
    try:
        logger.setLevel(logging.DEBUG)
        ch = logging.StreamHandler()
        ch.setLevel(logging.WARNING)
        if not os.path.exists(logfile_dir):
            os.makedirs(logfile_dir)
            os.chmod(logfile_dir, 600)
        rht = logging.handlers.RotatingFileHandler(filename=logfile, maxBytes=10 * 1024 * 1024, backupCount=20)
        rht.setLevel(logging.WARNING)
        # create formatter
        formatter = logging.Formatter(
            "[%(asctime)s] [%(levelname)s] [%(filename)s.%(funcName)s:%(lineno)s]"
            " %(levelname)s - %(message)s",
            "%Y-%m-%d %H:%M:%S")

        # add formatter to ch
        ch.setFormatter(formatter)
        rht.setFormatter(formatter)

        # add ch to logger
        logger.addHandler(ch)
        logger.addHandler(rht)
    except Exception as e:
        return False
    return True


def main(argv=None):
    try:
        init_help()
        parser = argparse.ArgumentParser(description='Fsc_cli cli for'
                                                     ' FusionStorage Block.')
        parser.add_argument("-o", "--op", dest="operation",
                            choices=list(iter(helper.keys())),
                            help="Choose one of operations")
        parser.add_argument("-S", "--sample", action="store_true",
                            dest="sample_help",
                            help="Print operation samples.",
                            default=False)
        parser.add_argument("-u", "--usage", dest="usage",
                            help="cinder or drextend", default=None,
                            choices=SUPPORTED_SERVICE)
        parser.add_argument("--authCredentials", dest="authCredentials",
                            help="authCredentials.")
        parser.add_argument("--burstIOPS", dest="burstIOPS", help="burstIOPS.")
        parser.add_argument("--burstMBPSPerTB", dest="burstMBPSPerTB",
                            help="burstMBPSPerTB.")
        parser.add_argument("--cacheFlag", dest="cacheFlag", help="cacheFlag.")
        parser.add_argument("--cmkId", dest="cmkId", help="cmkId.")
        parser.add_argument("--creditIOPS", dest="creditIOPS",
                            help="creditIOPS.")
        parser.add_argument("--dataSrcURL", dest="dataSrcURL",
                            help="dataSrcURL.")
        parser.add_argument("--encrypted", dest="encrypted",
                            help="encrypted.")
        parser.add_argument("--fsaIp", dest="fsaIp", help="fsaIp.")
        parser.add_argument("--fullCopyFlag", dest="fullCopyFlag",
                            help="fullCopyFlag.")
        parser.add_argument("--imageOffset", dest="imageOffset",
                            help="imageOffset.")
        parser.add_argument("--imageSize", dest="imageSize", help="imageSize.")
        parser.add_argument("--imageUUID", dest="imageUUID", help="imageUUID.")
        parser.add_argument("--IOPSPerGB", dest="IOPSPerGB", help="IOPSPerGB.")
        parser.add_argument("--ip", dest="ip", help="ip.")
        parser.add_argument("--keyword", dest="keyword", help="keyword.")
        parser.add_argument("--lunRwRight", dest="lunRwRight",
                            help="lunRwRight.")
        parser.add_argument("--manage_ip", dest="manage_ip", help="manage_ip.")
        parser.add_argument("--maxIOPS", dest="maxIOPS", help="maxIOPS.")
        parser.add_argument("--maxMBPS", dest="maxMBPS", help="maxMBPS.")
        parser.add_argument("--MBPSPerTB", dest="MBPSPerTB", help="MBPSPerTB.")
        parser.add_argument("--minBaselineIOPS", dest="minBaselineIOPS",
                            help="minBaselineIOPS.")
        parser.add_argument("--minBaselineMBPS", dest="minBaselineMBPS",
                            help="minBaselineMBPS.")
        parser.add_argument("--pageNum", dest="pageNum", help="pageNum.")
        parser.add_argument("--pageSize", dest="pageSize", help="pageSize.")
        parser.add_argument("--pool", dest="pool", help="pool.")
        parser.add_argument("--poolId", dest="poolId", help="poolId.")
        parser.add_argument("--poolIdDst", dest="poolIdDst", help="poolIdDst.")
        parser.add_argument("--poolType", dest="poolType", help="poolType.")
        parser.add_argument("--qosName", dest="qosName", help="qosName.")
        parser.add_argument("--queryType", dest="queryType", help="queryType.")
        parser.add_argument("--readLimitIOPS", dest="readLimitIOPS",
                            help="readLimitIOPS.")
        parser.add_argument("--readLimitMBPS", dest="readLimitMBPS",
                            help="readLimitMBPS.")
        parser.add_argument("--replace", dest="replace", help="replace.")
        parser.add_argument("--smartFlag", dest="smartFlag", help="smartFlag.")
        parser.add_argument("--snapName", dest="snapName", help="snapName.")
        parser.add_argument("--snapNameDst", dest="snapNameDst",
                            help="snapNameDst.")
        parser.add_argument("--snapNameFrom", dest="snapNameFrom",
                            help="snapNameFrom.")
        parser.add_argument("--snapNameList", dest="snapNameList",
                            help="snapNameList.")
        parser.add_argument("--snapNameSrc", dest="snapNameSrc",
                            help="snapNameSrc.")
        parser.add_argument("--snapNameTo", dest="snapNameTo",
                            help="snapNameTo.")
        parser.add_argument("--storageServiceArgs", dest="storageServiceArgs",
                            help="storageServiceArgs.")
        parser.add_argument("--thinFlag", dest="thinFlag", help="thinFlag.")
        parser.add_argument("--volName", dest="volName", help="volName.")
        parser.add_argument("--volNameList", dest="volNameList",
                            help="volNameList.")
        parser.add_argument("--volNameSrc", dest="volNameSrc",
                            help="volNameSrc.")
        parser.add_argument("--volNum", dest="volNum", help="volNum.")
        parser.add_argument("--volSize", dest="volSize", help="volSize.")
        parser.add_argument("--volume", dest="volume", help="volume.")
        parser.add_argument("--writeLimitIOPS", dest="writeLimitIOPS",
                            help="writeLimitIOPS.")
        parser.add_argument("--writeLimitMBPS", dest="writeLimitMBPS",
                            help="writeLimitMBPS.")
        parser.add_argument("--hostName", dest="hostName", help="hostName.")
        parser.add_argument("--hostGroupName", dest="hostGroupName",
                            help="hostGroupName.")
        parser.add_argument("--portName", dest="portName", help="portName.")
        parser.add_argument("--detachIp", dest="detachIp", help="detachIp.")
        parser.add_argument("--needRestart", dest="needRestart",
                            help="needRestart.")
        parser.add_argument("--chapName", dest="chapName", help="chapName.")
        parser.add_argument("--chapSecret", dest="chapSecret", help="chapSecret.")
        parser.add_argument("--iscsiType", dest="iscsiType", help="iscsiType.")
        parser.add_argument("--type", dest="type", help="type.")
        parser.add_argument("--chapStatus", dest="chapStatus", help="chapStatus.")
        parser.add_argument("--tenantId", dest="tenantId", help="tenantId.")

        options = parser.parse_args()
        global usage
        if options.usage:
            usage = options.usage
        else:
            for key, directory in FSC_BASE.items():
                if directory == current_dir:
                    usage = key
                    break
        init_logging()

        op = options.operation
        floatIP = options.manage_ip
        if not floatIP:
            floatIP = ip[usage]
        cfg_file_path = os.path.join(LIB_BASE[usage], "storage_port.ini")
        listen_port = None
        if os.path.exists(cfg_file_path):
            configParser = MyConfigParser()
            configParser.read(cfg_file_path)
            section = "default"
            if configParser.has_option(section, floatIP):
                listen_port = configParser.getint(section, floatIP)
        if not listen_port:
            listen_port = port[usage]
        logger.info("listening port %s for float IP %s" % (listen_port,
                                                           floatIP))

        if options.sample_help:
            sample_help(op)
            return
        elif op is not None:
            if op == "startServer":
                start_dsware_api_daemon(floatIP, listen_port)
                return
            elif op == "restartServer":
                restart_dsware_api_daemon(floatIP, listen_port)
                return
            elif op == "rootStartServer":
                if len(sys.argv) > 5:
                    logger.error("param is wrong %s" % sys.argv)
                start_dsware_api_daemon_as_root(floatIP, listen_port)
                return
            else:
                run_command(floatIP, listen_port)

    except Usage as err:
        logger.error(err.msg)
        logger.error("for help use --help")
        return 2
    except Exception as err:
        logger.error(traceback.format_exc())
        logger.error("cmd exc %s" % err)
        return 1


def load_json_file(file_name):
    with open(file_name, 'r') as fr:
        content = fr.read()
    result_json = json.loads(content, object_pairs_hook=OrderedDict)
    return result_json


if __name__ == "__main__":
    sys.exit(main())
