#!/usr/bin/python
# -*- coding: utf-8 -*-
# @brief   : 2018/10/10 16:56
# @File    : app ctrl
#  @Software: Software management infrastructure

import os
import shutil
import sys
import logging
import subprocess
import time
import yaml
import pwd
import grp
import platform
from ctypes import *

class ProcessInfoStruct(Structure):
    _fields_ = [
        ("state", c_int),
        ("uiVersionId", c_uint),
        ("restart_type", c_uint),
        ("notNormalTime", c_longlong),
        ("failureTime", c_longlong)
    ]

logging.basicConfig(level=logging.INFO,
                    filename="/OSM/log/cur_debug/messages",
                    format='[%(asctime)s][%(levelname)s][%(message)s][%(filename)s, %(lineno)d]',
                    datefmt='%Y-%m-%d %H:%M:%S')

TOP_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
MY_NAME = os.path.basename(__file__)
REPO_DIR = os.path.join(TOP_DIR, "repo")
SERVICE_STATE_PATH = "/OSM/component/devm/lib"
PROCESS_ID = 21  # 进程ID
ONLINE_TIMEOUT = 300  # 进程升级后online的超时时间
RPM_DB_PATH = '/var/lib/devm_rpm'
STOP_APP_CMD = "snm.sh -t /OSM/component/devm/bin/{}_snm.py  -f /OSM/component/devm/bin/{}"
START_APP_CMD = "snm.sh -s /OSM/component/devm/bin/{}_snm.py -f /OSM/component/devm/bin/{}"
TIMEOUT_SEQ = 30
UPGRADE_RETRY_TIMES = 5
RUN_DIR = "/OSM/component/devm/"
ROOT_FLAG_FILE_PATH = "/OSM/conf/unroot_flag"

# INSTALL 加载执行的脚本
INSTALL_EXEC_CMD = ['sh /OSM/script/hns3_check_intf.sh',
                    'sh /OSM/script/net_set_neigh.sh',
                    'sh /OSM/script/net_set_firewall.sh',
                    'sh /etc/init.d/set-vrf start',
                    'sh /etc/init.d/set-ibc-network start',
                    'sh /etc/init.d/os-resume-conf-on-startup start',
                    'sh /OSM/script/os_mgtibc_netconfig.rc start',
                    'sh /etc/init.d/os_change_bayconfigd start',
                    'sh /etc/init.d/os_flush_mgt_ip_configd start',
                    'sh /OSM/script/osp_init_net.sh',
                    'sh /OSM/script/set_net_conf_dir.sh',
                    'mkdir -p /OSM/data/pangea/',
                    'sh /OSM/script/pangea_devm_install.sh',
                    'cp -af %s/manifest.yml %s/conf' % (TOP_DIR, RUN_DIR)]

# INSTALL 修改文件权限的命令
PERMISSION_EXEC_CMD = ['chmod 750 /OSM/component/devm/conf/RO',
                       'chmod 750 /OSM/component/devm/conf/maradns',
                       'chmod 640 /OSM/component/devm/conf/manifest.yml',
                       'chmod 750 /OSM/component/devm/data/',
                       'chmod 750 /OSM/conf/eam_conf',]

# upgrade 加载执行的脚本
# maradns组件升级，Stop devm后调用脚本kill, start不需要拉起，根据用户配置由devm自动拉起。
UPGRADE_EXEC_CMD_AFT_INSTALL_RPM = ['rmmod mic.ko',
                                       'insmod /OSM/modules/mic.ko',
                                       'sh /OSM/script/net_set_neigh.sh',
                                       'sh /OSM/script/net_set_firewall.sh',
                                       'sh /OSM/script/net_dns_stop.sh']

CO_PATCH_PATH = os.path.join(TOP_DIR, 'hotpatch')
CO_PATCH_RUNNING_PATH = '/OSM/component/devm/hotpatch/'

USAGE = '''
Usage:
{name:s} [option]

Options:
    start
    stop
    online
    offline   
    install
    uninstall
    check_status    
    '''.format(name=MY_NAME)

DEVM_GROUP = "OceanStorDevmGroup"
DEVM_GROUP_ID = 64700
DEVM_USR = "OceanStorDevmUser"
DEVM_USER_ID = 64700

APPDATA_USER_ID	= 64000

INFRA_GROUP_ID  = 64600
COMMON_GROUP_ID = 62900
OAM_GROUP_ID    = 64200
PANGEA_GROUP_ID = 62700
PCIE_GROUP_ID   = 62200

FILE_OWNER_CONF_TABLE = (
    dict(usernameid=DEVM_USER_ID, usergroupid=DEVM_GROUP_ID, filePath='/OSM/component/devm'),
    dict(usernameid=DEVM_USER_ID, usergroupid=DEVM_GROUP_ID, filePath='/etc/maradns'),
    dict(usernameid=DEVM_USER_ID, usergroupid=DEVM_GROUP_ID, filePath='/etc/mararc'),
    dict(usernameid=DEVM_USER_ID, usergroupid=DEVM_GROUP_ID, filePath='/etc/dhcp'),
    dict(usernameid=DEVM_USER_ID, usergroupid=DEVM_GROUP_ID, filePath='/var/lib/dhclient'),
    dict(usernameid=DEVM_USER_ID, usergroupid=DEVM_GROUP_ID, filePath='/etc/configer_bak.conf'),
)

USER_GROUP_CONF_TABLE = (
    dict(usergroupid=INFRA_GROUP_ID, username=DEVM_USR),
    dict(usergroupid=COMMON_GROUP_ID, username=DEVM_USR),
    dict(usergroupid=OAM_GROUP_ID, username=DEVM_USR),
    dict(usergroupid=PANGEA_GROUP_ID, username=DEVM_USR),
    dict(usergroupid=PCIE_GROUP_ID, username=DEVM_USR),
)

INSTALL_EXEC_CMD_DEROOT = [
    'chown -h :62900 /OSM/data',
    '/OSM/script/changeDevmPermission.sh',
    'mkdir -p /OSM/tmp/devm',
    'chmod 750 /OSM/tmp/devm',
    'chown -h 64700:62900 /OSM/tmp/devm',
    'mkdir -p /OSM/data/devm',
    'chmod 750 /OSM/data/devm',
    'chown -h 64700:62900 /OSM/data/devm',
    'chmod g+s /OSM/data/devm',
    'setfacl -m u:64000:rwx /OSM/data/devm/',
    'chmod 770 /OSM/data/pangea',
    'chown -hR 64700:62700 /OSM/data/pangea',
    'chmod g+s /OSM/data/pangea',
    'chmod -R 750 /OSM/conf/devm',
    'chown -hR 64700:62900 /OSM/conf/devm',
    'chown -hR 64700:62900 /OSM/conf/eam_conf',
    'chmod g+s /OSM/conf/devm',
    'mkdir -p /OSM/component/devm/tmp',
    'chmod 770 /OSM/component/devm/tmp',
    'chown -h 64700:64700 /OSM/component/devm/tmp',
    'chown -h 64700:62900 /OSM/component/devm/',
    'chmod 770 /OSM/component/devm/conf/',
    'chown -h 64700:62900 /OSM/component/devm/conf/',
    'chmod g+s /OSM/component/devm/conf/',
    'chown -h 64700:62900 /startup_disk/conf/conf_local/bay_config.ini',
    'chmod 750 /startup_disk/conf/conf_local/bay_config.ini',
    'chown -h 64700:62900 /OSM/conf/bay_config.ini',
    'chmod 750 /OSM/conf/bay_config.ini',
    'chown -hR 64700:62900 /OSM/coffer_log/log/PANGEA_log',
    'chmod g+s /OSM/coffer_log/log/PANGEA_log',
    'touch /run/xtables.lock',
    'setfacl -m u:64700:r-- /run/xtables.lock',
    'chown -h 64700:64700 /OSM/component/devm/data/even_brifnum',
    'chown -h 64700:64700 /OSM/component/devm/data/odd_brifnum',
    'chown -h 64700:64700 /tmp/net_firewall_exception_info.xml',
    'chown -h 64700:64700 /tmp/osmpf_out',
    'chown -h 64700:64700 /tmp/iptableerr',
    ]

def add_user_to_group():
    for conf_row in USER_GROUP_CONF_TABLE:
        cmd = "usermod -a -G {0} {1}".format(conf_row['usergroupid'],conf_row['username'])
        ret_code = os.system(cmd)
        if ret_code != 0:
            logging.error("Devm Upgrade: usermod -G {0} {1} failed[2].".format(conf_row['usergroupid'], conf_row['username'], ret_code))
            return 1
    
    logging.info("Devm Upgrade: add devm to user group successed.")
    return 0

def change_file_owner():
    for conf_row in FILE_OWNER_CONF_TABLE:
        cmd = "chown -hR {0}:{1} {2}".format(conf_row['usernameid'],conf_row['usergroupid'],conf_row['filePath'])
        ret_code = os.system(cmd)
        if ret_code != 0:
            logging.error("Devm Upgrade: chown {0} user({1}), group({2}) failed({3}).".format(conf_row['filePath'], conf_row['usernameid'], conf_row['usergroupid'], ret_code))

    logging.info("Devm Upgrade: change file owner successed.")
    return 0

SUDOER_PANGEA_WHITE_LIST = [
    '/usr/bin/hifcadm',
    '/usr/bin/hinicadm',
    '/usr/bin/hiarmtool',
    '/usr/bin/test',
    '/usr/local/OSM/script/pcie_add_resource_grp.sh', 
    '/usr/local/OSM/script/pcie_add_uio_grp.sh',
    '/usr/bin/mkdir -m 750 /OSM/log/cur_debug/pangea/fwlog/',
    '/usr/bin/test -d /OSM/log/cur_debug/pangea/fwlog/',
    '/usr/local/OSM/script/net_add_toedev_to_grp.sh',
    '/OSM/script/getbmclog.sh',
    '/OSM/script/del_bmc_log.sh',
    '/OSM/script/scpbmclog.sh',
    '/OSM/script/acx_hi1822_tool.sh',
    '/OSM/script/acx_hi1620_tool.sh',
    '/OSM/script/pangea_hi1822chiplog_collect.sh',
    '/OSM/script/os_reset_ethx.sh',
    '/OSM/script/expect_transupdatefile.sh',
    '/OSM/script/expect_transseckeyfile.sh',
    '/OSM/script/TOE_multihost_support_check.sh',
    '/OSM/script/ses_log_compress.sh',
    '/usr/bin/ipmitool raw 0x32 0xb 0 2 0 0 0x38 1>/dev/null 2>/dev/null',
    '/OSM/script/eth_port_autoneg.sh',
    '/usr/bin/rm /tmp/inputpowerstatnew',
    '/usr/bin/rm -f /OSM/log/cur_debug/pangearundata',
    '/usr/bin/rm /OSM/log/cur_debug/inputpowerstatnewbak',
    '/usr/bin/cp -P --remove-destination /OSM/coffer_log/log/cur_debug/inputpowerstatnew /OSM/log/cur_debug/inputpowerstatnew',
    '/usr/bin/cp -P --remove-destination /tmp/inputpowerstatnew /OSM/log/cur_debug/inputpowerstatnewbak',
    '/usr/bin/cp -P --remove-destination /OSM/log/cur_debug/inputpowerstatnewbak /OSM/log/cur_debug/inputpowerstatnew',
    '/usr/bin/cp -P --remove-destination /OSM/log/cur_debug/inputpowerstatnewbak /OSM/coffer_log/log/cur_debug/inputpowerstatnew',
    '/OSM/bin/script/os_get_file.sh 127.127.127.10 /OSM/coffer_log/log/cur_debug/inputpowerstatnew /tmp/',
    '/OSM/bin/script/os_get_file.sh 127.127.127.11 /OSM/coffer_log/log/cur_debug/inputpowerstatnew /tmp/',
    '/OSM/bin/script/os_get_file.sh 127.127.127.12 /OSM/coffer_log/log/cur_debug/inputpowerstatnew /tmp/',
    '/OSM/bin/script/os_get_file.sh 127.127.127.13 /OSM/coffer_log/log/cur_debug/inputpowerstatnew /tmp/',
    '/usr/bin/chown -h OceanStorDevmUser\:OceanStorDevmGroup /OSM/log/cur_debug/inputpowerstatnew',
    '/usr/bin/chown -h OceanStorDevmUser\:OceanStorDevmGroup /OSM/coffer_log/log/cur_debug/inputpowerstatnew',
    ] 

SUDOER_DEVM_WHITE_LIST = [
    '/usr/bin/killall -9 devm',
    '/usr/bin/killall -9 ccdb_server',
    '/usr/bin/killall -9 cfg_app',
    '/usr/bin/killall -9 sys_app',
    '/usr/bin/killall -9 app_data',
    '/usr/bin/killall -11 app_data',
    '/usr/bin/killall -9 alarm',
    '/OSM/script/upgrade_common.sh',
    '/ISM/R01ism_setup.sh',
    '/OSM/script/os_upgrade_coldpatch.sh',
    '/OSM/script/ip_conflict_detect.sh',
    '/OSM/script/hinic_bond.sh',
    '/OSM/script/net_get_bond_info.sh',
    '/usr/sbin/dhclient',
    '/OSM/script/net_dhclient_stop.sh',
    '/usr/bin/systemctl restart dhcpd',
    '/OSM/script/net_set_dhcp_conf.sh',
    '/OSM/script/net_dns_start.sh',
    '/OSM/script/net_dns_stop.sh',
    '/OSM/script/exe_cmd_by_heartbeat_port.sh',
    '/OSM/script/net_config_mgtip.sh',
    '/OSM/script/net_config_mntip.sh',
    '/OSM/script/net_add_mgtip_route.sh',
    '/OSM/script/net_ip_ping.sh',
    '/OSM/script/net_ip_exist.sh',
    '/OSM/script/net_get_sys_ip_addr.sh',
    '/OSM/script/net_save_diagnose_info.sh',
    '/usr/local/OSM/script/os_change_bayconfig.sh',
    '/usr/local/OSM/script/os_write_bay_cfg.sh',
    '/OSM/script/ifm_tcp_config.sh',
    '/usr/local/OSM/script/os_write_bay_cfg.sh',
    '/OSM/script/net_install_nftables.sh',
    '/OSM/script/erase_network_config.sh',
    '/usr/bin/chmod 664 /OSM/conf/boot_acc_info.cfg',
    '/usr/bin/chown -h \:62900 /OSM/conf/boot_acc_info.cfg',
    '/OSM/script/net_write_vault_disk.sh',
    '/OSM/script/net_write_vault_encl.sh',
    '/OSM/script/chg_etfiles_dir.sh',
    '/OSM/script/os_reset_ethx.sh',
    '/OSM/script/net_reset_mnt_vlan.sh',
    '/usr/bin/install -m 644 /tmp/innerIpInformation.conf.tmp /OSM/conf/innerIpInformation.conf',
    '/OSM/script/net_query_mgtip.sh',
    '/OSM/script/save_netconfig_to_conflocal.sh',
    '/OSM/script/net_save_diagnose_info.sh',
    '/usr/bin/chown -h 64700\:64700 /etc/resolv.conf',
    '/usr/bin/chmod 644 /etc/resolv.conf',
    '/usr/bin/rm -f /var/bmc_ip_cfg_tmp',
    '/usr/bin/ip-ext',
    '/usr/sbin/nft list ruleset',
    '/usr/sbin/modprobe -r bonding',
    '/usr/sbin/modprobe bonding max_bonds=9 mode=4',
    '/OSM/script/os_sync_to_backpoint.sh',
    '/usr/sbin/ipmi_bayconfig',
    '/usr/bin/chown -h 64700\:64700 /OSM/component/devm/data/localbaycfg.ini',
    '/usr/bin/mkdir -m 770 /OSM/tmp/sys',
    '/usr/bin/touch /etc/resolv.conf',
    '/usr/bin/touch /OSM/conf/oem_patch_rollback_finish_flag',
    '/usr/bin/cp /OSM/conf/bay_config.ini /OSM/conf/bak_bay_config.ini',
    '/usr/bin/rm -f /OSM/conf/bak_bay_config.ini',
    '/usr/bin/chown -h 64700\:62900 /OSM/conf/bak_bay_config.ini',
    '/usr/bin/chmod 640 /OSM/conf/bak_bay_config.ini',
    '/OSM/script/os_load_ok.sh',
    ]

def add_user_to_sudoer():
    pangea_white_list = ','.join(SUDOER_PANGEA_WHITE_LIST)
    devm_white_list = ','.join(SUDOER_DEVM_WHITE_LIST)
    white_list = pangea_white_list + ',' + devm_white_list
    cmd = "echo \"OceanStorDevmUser ALL=(root) NOPASSWD: " + white_list + "\">/etc/sudoers.d/OceanStorDevmUser"
    ret_code = os.system(cmd)
    if ret_code != 0:
        logging.error("Devm Upgrade: add devm user to sudoer failed(%d)", ret_code)
        return 1
    return 0

def add_user_bin_to_path():
    path_list = [
                 '/usr/sbin',
                 '/usr/local/sbin',
                 ]
    for path in path_list:
        cmd = "grep {0} /home/OceanStorDevmUser/.bashrc || echo -e 'PATH=$PATH:{0}\nexport PATH' >> /home/OceanStorDevmUser/.bashrc".format(path);
        ret_code = os.system(cmd)
        if ret_code != 0:
            logging.error("Devm Upgrade: add user sbin to path(%s) failed(%d)", cmd, ret_code)
            return 1
    ret_code = os.system("source /home/OceanStorDevmUser/.bashrc")
    if ret_code != 0:
        logging.error("Devm Upgrade: source devm user failed(%d)", ret_code)
        return 1
    return 0
    
def add_user():
    group_info = None
    usr_info = None
    try:
        group_info = grp.getgrnam(DEVM_GROUP)
    except Exception as e:
        logging.exception("Devm Upgrade: query info exception{0}.".format(e))
        pass

    try:
        usr_info = pwd.getpwnam(DEVM_USR)
    except Exception as e:
        logging.exception("Devm Upgrade: query info exception{0}.".format(e))
        pass

    if group_info:
        logging.info("Devm Upgrade: system exist group(%s) ,don't create group." % DEVM_GROUP)
    else:
        ret_code = os.system("groupadd -g {0} {1}".format(DEVM_GROUP_ID,DEVM_GROUP))
        if ret_code != 0:
            logging.error("Devm Upgrade: Create usr group(%s) failed(%d)." % (DEVM_GROUP, ret_code))
            return 1
            
    if usr_info :
        logging.info("Devm Upgrade: system exist user name(%s) ,don't create user." % DEVM_USR)
    else:
        ret_code = os.system("useradd -u {0} -g {1} -d /home/{2} -s /bin/bash {2}".format(DEVM_USER_ID, DEVM_GROUP, DEVM_USR))
        if ret_code != 0:
            logging.error("Devm Upgrade: Ceate user(%s) failed(%d)." % (DEVM_USR,ret_code))
            return 1
    
    logging.info("Devm Upgrade: add user successed.")
    
    ret_code = add_user_bin_to_path()
    if ret_code != 0:
        logging.error("Devm Upgrade: Add  user sbin/bin to path failed.")
        return 1
    
    return 0

def is_arm_device():
    cpu_type = platform.uname()
    for name in cpu_type:
        if "aarch" in name:
            return 0
    return 1

# 备份用户和组
BACKUP_USER_GROUP_CONF_TABLE = (
    dict(name="OceanStorDevmGroup", src="/etc/group", dst="/etc/group_default"),
    dict(name="OceanStorDevmUser", src="/etc/shadow", dst="/etc/shadow_default"),
    dict(name="OceanStorDevmUser", src="/etc/passwd", dst="/etc/passwd_default"),
)

# 目标备份文件不存在，不需要处理（OMM后续创建备份文件时备份）；
# 目标备份文件存在： 1）文件中已存在name用户，不需要处理；2）文件中不存在name的用户，则在源文件找出指定name的条目，以append方式写入备份文件；
def backup_usergroup(conf):
    for conf_row in conf:
        if os.path.exists(conf_row['dst']):
            regex = '^'+ conf_row['name']
            cmd ="grep -E {0} {1} ".format(regex, conf_row['dst'])
            dst_fd = os.popen(cmd, 'r')
            str = dst_fd.read()
            dst_fd.close()
            if str.find(conf_row['name']) != -1:
                continue

            regex = '^'+ conf_row['name']
            cmd ="grep -E {0} {1}".format(regex, conf_row['src'])
            src_fd = os.popen(cmd, 'r')
            str = src_fd.read()
            src_fd.close()
            if str.find(conf_row['name']) != -1:
                fd = open(conf_row['dst'], 'a')
                fd.writelines(str)
                fd.close()
                logging.info("Devm Upgrade: user group(%s) added to backup file.", str)
    logging.info("Devm Upgrade: backup user group successed.")
    return 0

def is_need_remove_root():
    if is_arm_device() != 0:
        logging.info("Devm Upgrade: This is x86 device, don't deroot.")
        return 1

    if os.getenv("NODE_TYPE") == "DATA_NODE":
        logging.info("Devm Upgrade: This is snode, don't deroot.")
        return 1

    if not os.access(ROOT_FLAG_FILE_PATH, os.F_OK):
        logging.info("Devm Upgrade: not support deroot, don't deroot")
        return 1

    return 0

# 提前创建devm写、其他进程读的sqlite文件
def create_devm_sqlite_file():
    devm_sqlite = ["/OSM/data/devm/devm_eam.db", "/OSM/data/devm/devm_net.db"]

    for dbfile in devm_sqlite:
        if not os.access(dbfile, os.F_OK):
            cmd = "touch {0}".format(dbfile)
            ret = os.system(cmd)
            if ret != 0:
                logging.error("Devm Upgrade: touch %s failed.", dbfile)
                return 1
        cmd = "chown {0}:{1} {2}".format(DEVM_USER_ID, COMMON_GROUP_ID, dbfile)
        ret = os.system(cmd)
        if ret != 0:
            logging.error("Devm Upgrade: chown %s failed.", dbfile)
            return 1
        cmd = "chmod 0640 {0}".format(dbfile)
        ret = os.system(cmd)
        if ret != 0:
            logging.error("Devm Upgrade: chmode %s failed.", dbfile)
            return 1

    ret = os.system("setfacl -m u:64000:rw- /OSM/data/devm/devm_eam.db")
    if ret != 0:
        logging.error("Devm Upgrade: setfacl devm_eam.db failed.")
        return 1

    return 0

# 提前创建app_data写、devm进程读的文件
def create_appdata_file():
    appdata_file = ["/OSM/data/devm/cpu_usage", "/OSM/data/devm/dirty_data_rate", "/OSM/data/devm/sys_disk_ver"]

    for file in appdata_file:
        if not os.access(file, os.F_OK):
            cmd = "touch {0}".format(file)
            ret = os.system(cmd)
            if ret != 0:
                logging.error("Devm Upgrade: touch %s failed.", file)
                return 1
        cmd = "chown {0}:{1} {2}".format(APPDATA_USER_ID, COMMON_GROUP_ID, file)
        ret = os.system(cmd)
        if ret != 0:
            logging.error("Devm Upgrade: chown %s failed.", file)
            return 1
        cmd = "chmod 0640 {0}".format(file)
        ret = os.system(cmd)
        if ret != 0:
            logging.error("Devm Upgrade: chmode %s failed.", file)
            return 1
    return 0

def create_file_addvanced():
    create_devm_sqlite_file()
    create_appdata_file()
    return 0

def process_remove_root():
    if is_need_remove_root() != 0:
        logging.info("Devm Upgrade: not support deroot, don't create user")
        return 0

    ret_code = add_user()
    if ret_code != 0:
        logging.error("Devm Upgrade: Add user failed.")
        return 1
    
    ret_code = add_user_to_sudoer()
    if ret_code != 0:
        logging.error("Devm Upgrade: Add sudoer failed.")
        return 1

    ret_code = change_file_owner()
    if ret_code != 0:
        logging.error("Devm Upgrade: Change file owner failed.")
        return 1

    ret_code = add_user_to_group()
    if ret_code != 0:
        logging.error("Devm Upgrade: Add user to group failed.")
        return 1

    ret_code = backup_usergroup(BACKUP_USER_GROUP_CONF_TABLE)
    if ret_code != 0:
        logging.error("Devm Upgrade: backup user and group failed.")
        return 1

    # 忽略执行结果继续执行
    logging.info("Devm Upgrade: start set dir owner.")
    for exec_cmd in INSTALL_EXEC_CMD_DEROOT:
        ret_code = os.system(exec_cmd)
        if ret_code:
            logging.error("Devm Upgrade: exec script (%s) failed", exec_cmd)

    # 提前创建文件，并配置权限
    create_file_addvanced()

    logging.info("Devm Upgrade: Process remove root success.")
    return 0

def upgrade_param():
    if os.getenv("NODE_TYPE") == "DATA_NODE":
        app_name = "osd_devm"
        app_cfg = "osd_devm_snm.xml"
    else:
        app_name = "devm"
        app_cfg = "devm_snm.xml"
    return app_name, app_cfg


def show_help():
    print(USAGE)
    return


def get_cna_type():
    """
    get board_type
    :return:
    """
    if os.getenv('NODE_TYPE') == 'DATA_NODE':
        cna_type = 'DATA_NODE'
        return cna_type
    else:
        cna_type = os.getenv('BOARD_TYPE')
        if not (cna_type == 'PANGEA_V2R1C00' or cna_type == 'PANGEA_V2R1C01'):
            cna_type = 'PANGEA_V2R3C01'
        return cna_type


def devm_is_exist():
    cmd = "ps -ef | grep \"devm -l 21 -v\" | grep -v grep"
    ret_code = os.system(cmd)
    if ret_code:
        return False
    else:
        return True

def start():
    app_name, app_cfg = upgrade_param()
    cmd = START_APP_CMD.format(app_name, app_cfg)
    ret_code = os.system(cmd)
    if ret_code:
        logging.error("Devm Upgrade: start devm process failed(%d)", ret_code)
        return -1
    for i in range(TIMEOUT_SEQ):
        if devm_is_exist():
            logging.info("Devm Upgrade: start %s successful", app_name)
            return 0
        else:
            time.sleep(0.2)
    logging.error("Devm Upgrade: start %s timeout", app_name)
    return 1


def stop():
    app_name, app_cfg = upgrade_param()
    cmd = STOP_APP_CMD.format(app_name, app_cfg)
    ret_code = os.system(cmd)
    if ret_code:
        logging.error("Devm Upgrade: stop devm process failed(%d)", ret_code)
        return -1
    for i in range(TIMEOUT_SEQ):
        if devm_is_exist():
            time.sleep(0.2)
        else:
            logging.info("Devm Upgrade: stop %s successful", app_name)
            return 0
    logging.error("Devm Upgrade: kill %s timeout", app_name)
    return 1


def online():
    cmd = 'LD_LIBRARY_PATH=/OSM/component/devm/lib:/lib64:/usr/lib64:/usr/local/lib ' \
          'python %s/action/appctl get_online_result' % TOP_DIR
    ret_code = os.system(cmd)
    return ret_code // 256


def get_online_result():
    if SERVICE_STATE_PATH not in sys.path:
        sys.path.append(SERVICE_STATE_PATH)

    p_info = ProcessInfoStruct()
    libs = CDLL("libsrv_client.so")
    check_time = 0
    try:
        # online timeout 升级失败
        logging.info("Devm Upgrade: get devm state start")
        while check_time < ONLINE_TIMEOUT:
            ret_code = libs.process_get_info(PROCESS_ID, byref(p_info))
            if ret_code == 0 and p_info.state == 2:
                logging.info("Devm Upgrade: check devm online state(%d) on check time(%d).", p_info.state, check_time)
                return 0
            logging.error("Devm Upgrade: state(%d) abnormal(%d) on check time(%d).", p_info.state, ret_code, check_time)
            time.sleep(1)
            check_time += 1
    except Exception as e:
        logging.error("Devm Upgrade: devm process online except %s", e)

    logging.error("Devm Upgrade: devm process online timeout")
    return 1


def offline():
    return 0


def create_rpm_dir():
    """
    创建rpm的db目录
    :return:
    """
    if not os.path.exists(RPM_DB_PATH):
        cmd = "mkdir -p %s" % RPM_DB_PATH
        os.system(cmd)


def install():
    create_rpm_dir()
    # 到repo目录下取出rpm包来进行安装
    for rpm_file in os.listdir(REPO_DIR):
        cmd = "rpm -ivh --nodeps --force --dbpath=%s %s" % (RPM_DB_PATH, os.path.join(REPO_DIR, rpm_file))
        ret_code = os.system(cmd)
        if ret_code:
            logging.error("Devm Upgrade: install devm service failed(%d)", ret_code)
            return -1
    
    for exec_cmd in INSTALL_EXEC_CMD:
        ret_code = os.system(exec_cmd)
        if ret_code:
            logging.error("Devm Upgrade: exec script(%s) failed(%d)", exec_cmd, ret_code)
    
    for exec_permission_cmd in PERMISSION_EXEC_CMD:
        ret_code = os.system(exec_permission_cmd)
        if ret_code:
            logging.error("Devm Upgrade: exec chmod cmd(%s) failed(%d)", exec_permission_cmd, ret_code)

    cna_type = get_cna_type()
    cmd = "cd /OSM/component/devm/bin; mv node_config.%s.xml node_config.xml" % cna_type
    ret_code = os.system(cmd)
    if ret_code:
        logging.error("Devm Upgrade: install node_config.xml failed(%d)", ret_code)
        return -1

    ret_code = process_remove_root()
    if ret_code != 0:
        logging.error("Devm Upgrade: remove root failed.")
        return 1
        
    logging.info("Devm Upgrade: install successful")
    return 0

def uninstall():
    create_rpm_dir()
    # 到repo目录下取出rpm包来卸载
    for rpm_file in os.listdir(REPO_DIR):
        rpm_name = rpm_file[0:rpm_file.index(".rpm")]
        cmd = "rpm -e --nodeps --dbpath=%s %s" % (RPM_DB_PATH, rpm_name)
        ret_code = os.system(cmd)
        if ret_code:
            logging.error("Devm Upgrade: uninstall devm service failed(%d)", ret_code)
            return -1
    return 0


def check_status():
    return 0


# 检查组件升级模式
def check_upgrade():
    old_cfg_path = os.path.join(RUN_DIR, 'conf', 'manifest.yml')
    new_cfg_path = os.path.join(TOP_DIR, 'manifest.yml')
    old_cfg = None
    new_cfg = None
    with open(old_cfg_path, 'r') as fp:
        content = fp.read()
        old_cfg = yaml.safe_load(content)
    with open(new_cfg_path, 'r') as fp:
        content = fp.read()
        new_cfg = yaml.safe_load(content)
    if not (old_cfg and new_cfg):
        logging.error("Devm Upgrade: Get yaml info failed(old: %s, new: %s).", old_cfg, new_cfg)
        return 0
    old_ver = old_cfg.get('Version')
    new_ver = new_cfg.get('Version')
    if old_ver == new_ver:
        logging.info("Devm Upgrade: The old version is same(%s) with new version, no need upgrade.", old_ver)
        return 1
    logging.info("Devm Upgrade: The old version(%s) is different with new version(%s), need upgrade.", old_ver, new_ver)
    return 2


def call_cmd_with_retry(func):
    ret_code, i = -1, 0
    for i in range(UPGRADE_RETRY_TIMES):
        ret_code = func()
        if ret_code == 0:
            break
        time.sleep(1)
    logging.info("Devm Upgrade: call upgrade func %s (ret: %d, retry: %d).", func.__name__, ret_code, i)
    return ret_code

def copy_patch_file():
    if os.path.exists(CO_PATCH_RUNNING_PATH):
        shutil.rmtree(CO_PATCH_RUNNING_PATH)

    if not os.path.isdir(CO_PATCH_PATH):
        logging.info("Devm Upgrade No hotpatch to copy.")
        return 0

    logging.info("Devm Upgrade: Copy patch in %s.", CO_PATCH_PATH)
    shutil.copytree(CO_PATCH_PATH, CO_PATCH_RUNNING_PATH)
    logging.info("Devm Upgrade: Copy patch successful.")
    return 0

def exec_cmd_aft_install_rpm():
    logging.info("Devm Upgrade: start exec cmd after install rpm")
    for exec_cmd in UPGRADE_EXEC_CMD_AFT_INSTALL_RPM:
        ret_code = os.system(exec_cmd)
        if ret_code:
            logging.error("Devm Upgrade: exec script(%s) failed(%d)", exec_cmd, ret_code)
            return -1
    logging.info("Devm Upgrade: exec cmd success after install rpm")
    return 0

def upgrade():
    logging.info("Devm Upgrade: upgrade start")
    create_rpm_dir()
        
    # 到repo目录下取出rpm包来进行安装
    for rpm_file in os.listdir(REPO_DIR):
        cmd = "rpm -ivh --nodeps --force --dbpath=%s %s" % (RPM_DB_PATH, os.path.join(REPO_DIR, rpm_file))
        ret_code = os.system(cmd)
        if ret_code:
            logging.error("Devm Upgrade: upgrade devm service failed(%d)", ret_code)
            return -1
    
    ret_code = copy_patch_file()
    if ret_code:
        logging.error("Devm Upgrade: Copy patch file failed(%d)", ret_code)
        return -1
    
    cna_type = get_cna_type()
    cmd = "cd /OSM/component/devm/bin; mv node_config.%s.xml node_config.xml" % cna_type
    ret_code = os.system(cmd)
    if ret_code:
        logging.error("Devm Upgrade: upgrade node_config.xml failed(%d)", ret_code)

    # todo del: 组件化升级不需要去root
    ret_code = process_remove_root()   
    if ret_code != 0:
        logging.error("Devm Upgrade: remove root failed.")
        return 1

    if call_cmd_with_retry(stop) != 0:
        return -1
    
    if call_cmd_with_retry(exec_cmd_aft_install_rpm) != 0:
        return -1

    if call_cmd_with_retry(start) != 0:
        return -1
    
    ret_code = os.system('cp -af %s/manifest.yml %s/conf' % (TOP_DIR, RUN_DIR))
    logging.info("Devm Upgrade: cp -af %s/manifest.yml %s/conf", TOP_DIR, RUN_DIR)
    if ret_code:
        logging.error("Devm Upgrade: copy manifest.yml file failed(%d)", ret_code)
        return 1

    logging.info("Devm Upgrade: upgrade successful")
    return 0

def enable_bridge_forward():
    cmd = "[ -f /OSM/script/net_bridge_forward_ctrl.sh ] && /OSM/script/net_bridge_forward_ctrl.sh delete || exit 0"
    ret_code = os.system(cmd)
    if ret_code:
        logging.error("Devm Upgrade: enable bridge forward failed.")
    return 0
    
def rollback():
    return upgrade()


# 升级前打开网桥转发功能，避免降级到低版本，网桥转发功能被关闭了
def pre_upgrade():
    enable_bridge_forward()
    return 0


# 回滚前打开网桥转发功能，避免回滚到低版本，网桥转发功能被关闭了
def pre_rollback():
    enable_bridge_forward()
    return 0


def exec_build(args):
    """

    :param args:
    :return:
    """
    if 2 != len(args):
        show_help()
        return -1
    func_name = args[1]
    this_module = sys.modules[__name__]
    try:
        func = getattr(this_module, func_name)
    except Exception as e:
        logging.exception("param is error %s", e)
        return -1
    if func is None:
        return -1
    return func()


if __name__ == "__main__":
    ret = exec_build(sys.argv)
    sys.exit(ret)
