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


import functools
import logging
import os
import platform
import re
import shutil
import sys
import tarfile
import threading
import time
import yaml

PYTHON_2 = '2.7' in sys.version
MY_DIR = os.path.dirname(os.path.realpath(__file__))
is_windows = (platform.system() == "Windows")

PKG_UPD_DIR = '/startup_disk/image/pkg_upd/packages'
PKG_CUR = '/startup_disk/image/pkg_cur/packages'
CONF_DIR = '/startup_disk/conf'
BOOT_LINK = '/startup_disk/image/boot'
EXTRACT_DIR = '/OSM/coffer_data/startup'
SYS_CUR_PATH = '/startup_disk/image/pkg_cur'
PATCH_CUR_DIR = os.path.join(SYS_CUR_PATH, "../hotpatch/patch_cur")
PATCH_TMP_DIR = os.path.join(SYS_CUR_PATH, "../hotpatch/patch_temp")

DISK_INSTALL_DIR = '/OSM/coffer_bin'
MEMORY_INSTALL_DIR = '/OSM/component'
OSM_SCRIPT_DIR = "/OSM/script"
IMAGE_DIR = '/startup_disk/image'
SCRIPT_LINK = '/OSM/script/goall'
BOARD_TYPE_TEMP_FILE = '/tmp/proc_osp_bsp.info'
BOARD_TYPE_FILE = '/OSM/script/proc_osp_bsp.info'
PROC_OS_BSP = '/proc/osp/bsp'
FUSION_BSP = '/proc/lite/bsp'
HOOK_REPLACE = '/OSM/coffer_data/install_hook/replace'
HOOK_SCRIPT = '/OSM/coffer_data/install_hook/script'
SPARE_PART_FLAG = '/startup_disk/conf/conf_local/spare_part_flag'
UPGRADE_FLAG_PATH = '/OSM/coffer_data/swm/upgrade_flag'
DATA_NODE_FLAG_FILE = '/startup_disk/conf/conf_local/data_node'
START_FINISHED_FILE = '/OSM/conf/swm_start_finished'
PATCH_RESUME_FAIL_ERROR_CODE = '1073884723'
NODE_TYPE_MISMATCH_ERROR_CODE = '1073884724'
DATA_NODE_BOARD = ['PANGEA_V6R1C00_JBOD_SAS_EXP', 'PANGEA_V6R1C00_JBOF_PALM_EXP']
CMPT_LIST = None
NODE_TYPE = None
SPARE_EXEC_SCRIPT = 'python /OSM/script/swm_spare_sync.py'
UPG_BIOS_SCRIPT = 'python /OSM/script/upgrade_bios.py {0} &>/dev/null'
THIRD_PAUSE_FLAG = "/OSM/coffer_data/sys/thirdpauseflag"
CUR_EULER_MANIFEST = os.path.join(BOOT_LINK, 'manifest.yml')


NEED_SYNC_FW_FLAG_AFTER_REBOOT = os.path.join(CONF_DIR, 'conf_local',
                                              'sync_fw_flag_after_reboot')


class BiosUpgType(object):
    STAND = '1'
    FORCE = '8'
    UPG_SLAVE = '16'


def decode_str(value):
    if not PYTHON_2 and isinstance(value, bytes):
        return value.decode(errors='ignore')
    return value


CMPT_LIST_CTL = (
    (
        'swm',
    ),
    (
        'kernel',
    ),
    (
        'devm',
    ),
    (
        'infra',
    ),
    (
        'omm_infra',
    ),
    (
        'sys',
        'fdsa',
        'cli',
        'cfg_app',
        'omm',
        'snmp',
        'app_data',
        'upgrade_check',
    )
)

CMPT_LIST_DATA = (
    (
        'swm',
        'upgrade_check',
    ),
    (
        'osd_kernel',
    ),
    (
        'osd_snm',
        'osd_fdsa',
    ),
    (
        'osd_devm',
        'osd_infra',
        'osd_omm_infra',
    ),
    (
        'osd_sys',
        'osd_cli',
        'omm',
        'osd_data',
    )
)

boot_type = {
    'os_rescue': 201,
    'os_memtest': 201,
    'os_only': 1073793434,
    'os_netboot': 1073793433,
    'os_boot_osp': None
}


def start_finish(run_func):
    @functools.wraps(run_func)
    def wrapper(*args, **kwargs):
        result = run_func(*args, **kwargs)
        if result:
            open(START_FINISHED_FILE, 'w+').close()
        return result
    return wrapper


class StartUp(object):
    """
    Startup manager.
    """

    STATE_INIT = 0
    STATE_SWM_INSTALLED = 1
    STATE_ALL_INSTALLED = 2
    STATE_ALL_STARTED = 3

    state_file = '/tmp/startup.stat'

    def __init__(self):
        """

        """
        self.lock = threading.RLock()
        self.state = self.load_state()
        self.result = True
        self.cmpt_list = []
        log.info("STARTUP: Load startup stat(%d).", self.state)
        return

    def load_state(self):
        """

        :return:
        """
        try:
            return int(open(self.state_file, 'r+').read())
        except:
            return self.STATE_INIT

    def save_state(self, state):
        self.state = state
        open(self.state_file, 'w+').write(str(self.state))
        return

    @staticmethod
    def _get_cmpt_path(pkg_dir, cmpt_name):
        for root, dirs, files in os.walk(pkg_dir):
            cmpt_list = [x for x in files if x.startswith(cmpt_name + '-')]
            if cmpt_list:
                return os.path.join(root, cmpt_list[0])
        log.warning("Can not find cmpt(%s) in dir(%s).", cmpt_name, pkg_dir)
        return ''

    def get_swm_cmpt_path(self):
        """
        Get swm component package path
        :return:
        """
        cmpt_path = self._get_cmpt_path(PKG_UPD_DIR, 'swm')
        if cmpt_path:
            return cmpt_path
        if StartUp.has_swm_patch():
            swm_cmpt = [pkg for pkg in os.listdir(PATCH_CUR_DIR) if
                        re.match(r'^swm-.*\.tar\.gz$', pkg)]
            if swm_cmpt:
                return os.path.join(PATCH_CUR_DIR, swm_cmpt[0])
        cmpt_path = self._get_cmpt_path(PKG_CUR, 'swm')
        if cmpt_path:
            return cmpt_path
        log.error("STARTUP: The swm component pkg is not exist.")
        return None

    @staticmethod
    def has_swm_patch():
        if not os.path.exists(PATCH_CUR_DIR):
            return False
        file_list = os.listdir(PATCH_CUR_DIR)
        for file_name in file_list:
            if re.match(r'^swm-.*\.tar\.gz$', file_name):
                return True
        return False

    @staticmethod
    def _get_swm_root(root_dir):
        swm_dir_list = [d for d in os.listdir(root_dir) if d.startswith('swm')]
        if not swm_dir_list:
            log.error("STARTUP: Swm component install dir is not exist")
            return ''
        if len(swm_dir_list) > 1:
            log.warning("STARTUP: Swm dir is more than one.")
        swm_dir = os.path.join(root_dir, swm_dir_list[0])
        return swm_dir

    @staticmethod
    def _get_run_swm_root(root_dir):
        swm_dir_list = [d for d in os.listdir(root_dir) if d.startswith('swm')]
        if not swm_dir_list:
            log.error("STARTUP: Swm component install dir is not exist")
            return ''
        if len(swm_dir_list) > 1:
            log.warning("STARTUP: Swm dir is more than one.")
        swm_dir = os.path.join(root_dir, swm_dir_list[0])
        return swm_dir

    def exec_cmpt_cmd(self, cmpt, cmd_name):
        log.info("STARTUP: Component(%s) begin to run cmd(%s).", cmpt.name, cmd_name)
        ret = cmpt.exec_cmd(cmd_name)
        if ret:
            log.info("STARTUP: Component(%s) run cmd(%s) successfully.", cmpt.name, cmd_name)
            return True
        log.error("STARTUP: Component(%s) run cmd(%s) failed.", cmpt.name, cmd_name)
        with self.lock:
            self.result = ret
        return

    def install_swm(self):
        """

        :return:
        """
        self.handle_pkg_cur()
        swm_pkg = self.get_swm_cmpt_path()
        if not swm_pkg:
            return False
        with tarfile.open(swm_pkg, 'r:gz') as tar:
            tar.extractall(EXTRACT_DIR)
        swm_dir = self._get_swm_root(EXTRACT_DIR)
        if not swm_dir:
            log.error("STARTUP: Swm was extracted incorrectly.")
            return False
        log.info("STARTUP: Begin to custom EulerOS.")
        os_custom_script = os.path.join(swm_dir, 'action', 'custom_os.sh')
        ret_code = os.system('sh {script:s}'.format(script=os_custom_script))
        if ret_code:
            log.error("STARTUP: Exec script (%s) to custom euler os failed", os_custom_script)
            return False
        log.info("STARTUP: Begin to install component(swm).")
        app_ctl = os.path.join(swm_dir, 'action', 'appctl')
        if os.system('%s install' % app_ctl):
            log.warning("STARTUP: Install component(swm) failed.")
        else:
            log.info("STARTUP: Install component(swm) successfully.")
        self.save_state(self.STATE_SWM_INSTALLED)
        self.special_resume_handle(PATCH_TMP_DIR)
        return True

    def _load_cmpt_list(self):
        """

        :return:
        """
        if self.cmpt_list:
            return True
        sys.path.append(OSM_SCRIPT_DIR)
        sys.path.append(os.path.join(DISK_INSTALL_DIR, 'swm'))
        sys.path.append(os.path.join(MEMORY_INSTALL_DIR, 'swm'))

        cmpt_mod = __import__('cmpt', fromlist=['cmpt', ])
        for batch in CMPT_LIST:
            batch_cmpt = []
            for cmpt_name in batch:
                cmpt = cmpt_mod.Component.get(cmpt_name, PKG_CUR, EXTRACT_DIR)
                batch_cmpt.append(cmpt)
            self.cmpt_list.append(batch_cmpt)
        return True

    @staticmethod
    def modify_group_user():
        # modify 文件权限，软连接
        cmd = 'sh /OSM/script/os_modify_sftp_group_user_dir.sh'
        os.system(cmd)

    @staticmethod
    def resume_euler_special_patch():
        cmd = 'sh /OSM/script/os_upgrade_coldpatch.sh -a'
        os.system(cmd)

    @staticmethod
    def resume_swm_patch():
        try:
            cur_ver = os.readlink("/startup_disk/image/pkg_cur").split('/')[0]
            patch_path = os.path.join('/startup_disk/image/', cur_ver, 'hotpatch/patch_cur')
            patch_mod = __import__('service.hotpatch.agent.hotpatch_util', fromlist=['hotpatch_util', ])
            ret = patch_mod.PatchPkg.resume_swm_patch(patch_path)
            log.info("STARTUP: SWM patch resume return %s", ret)
            return ret
        except Exception:
            log.exception("STARTUP: Resume excepted.")
            return False

    @staticmethod
    def special_resume_handle(patch_dir):
        if not os.path.exists(patch_dir):
            return True
        file_list = os.listdir(patch_dir)
        result = True
        for script in file_list:
            log.info("Find file(%s).", script)
            if not script.startswith('special_resume_'):
                continue
            cmd = os.path.join(patch_dir, script)
            ret = os.system(cmd)
            if ret == 0:
                log.info("Special resume handle cmd(%s) successfully.", cmd)
            else:
                result = False
                log.error("Special resume handle cmd(%s) failed, result %s.",
                          cmd, ret)
        return result

    @staticmethod
    def record_error_code(error_code=''):
        get_boot_type_cmd = 'cat /proc/cmdline | egrep -o -m 1 "os_boot_osp|os_only|os_rescue|os_memtest|os_netboot"'
        if PYTHON_2:
            import commands
            (ret, output) = commands.getstatusoutput(get_boot_type_cmd)
        else:
            import subprocess
            ret, output = subprocess.getstatusoutput(get_boot_type_cmd)  # pylint: disable=E1101
        power_error_code = boot_type.get(output)
        if power_error_code or error_code:
            log.error("STARTUP: abnomal boot type %s, need record the "
                      "error code.", power_error_code or error_code)
            record_cmd = '/OSM/script/os_record_abnormal_status.sh -s %s'\
                         % (power_error_code or error_code)
            os.system(record_cmd)

    @staticmethod
    def wait_service_finish(timeout=300, interval=5):
        services = ['pxe_server', 'nvram_log']
        times = timeout // (interval if interval else 1)
        cmd = 'systemctl status {service} | grep -E "FAILURE|SUCCESS|killed"'
        log.info('STARTUP: Begin wait service finish.')
        while times:
            for service in services:
                if os.system(cmd.format(service=service)):
                    break
            else:
                break
            times -= 1
            time.sleep(interval)
        log.info('STARTUP: End wait service finish.')
        return

    def resume_euler_patch(self, resume_stage):
        try:
            self.wait_service_finish()
            cur_ver = os.readlink("/startup_disk/image/pkg_cur").split('/')[0]
            patch_path = os.path.join('/startup_disk/image/', cur_ver, 'hotpatch/patch_cur')
            patch_mod = __import__('service.hotpatch.agent.hotpatch_util', fromlist=['hotpatch_util', ])
            ret = patch_mod.PatchPkg.resume_euler_patch(patch_path, resume_stage)
            log.info("STARTUP: Euler patch resume stage %s return %s", resume_stage, ret)
            return ret
        except Exception:
            log.exception("STARTUP: Resume stage %s excepted.", resume_stage)
            return False

    def resume_dopra_patch(self):
        try:
            cur_ver = os.readlink("/startup_disk/image/pkg_cur").split('/')[0]
            patch_path = os.path.join('/startup_disk/image/', cur_ver, 'hotpatch/patch_cur')
            patch_mod = __import__('service.hotpatch.agent.hotpatch_util', fromlist=['hotpatch_util', ])
            ret = patch_mod.PatchPkg.resume_dopra_patch_file(patch_path)
            log.info("STARTUP: Dopra patch file resume return %s", ret)
            return ret
        except Exception:
            log.exception("STARTUP: Dopra patch file resume excepted.")
            return False

    def delete_hotpatch(self):
        try:
            cur_ver = os.readlink("/startup_disk/image/pkg_cur").split('/')[0]
            patch_path = os.path.join('/startup_disk/image/', cur_ver,
                                      'hotpatch')
            if not os.path.exists(patch_path):
                return
            log.info("STARTUP: Delete patch file in dir %s", patch_path)
            mount_rw = "mount -o remount,rw,async /startup_disk/image/"
            os.system(mount_rw)
            os.system("rm -rf %s" % patch_path)
            mount_ro = "mount -o remount,ro,sync /startup_disk/image/"
            os.system(mount_ro)
        except Exception:
            log.exception("STARTUP: Delete hotpatch excepted.")

    @classmethod
    def get_fusion_info(cls):
        """
        获取北冰洋设备信息
        :return: a tuple (slot, frame type, node type)
        """
        values = [None, None, None]
        try:
            with open(FUSION_BSP) as fp:
                contents = fp.read()
            patterns = (r'Slot id is:(\d+)',
                        r'Frame type is:(\w+)',
                        r'product node type is:(\d+)')
            for idx, p in enumerate(patterns):
                ret = re.search(p, contents)
                if ret:
                    values[idx] = int(ret.groups()[0]) \
                        if ret.groups()[0].isdigit() else ret.groups()[0]
            return values
        except Exception:
            log.exception("STARTUP: Get fusion info excepted.")
        return None, None, None

    @staticmethod
    def get_euler_version():
        if not os.path.exists(CUR_EULER_MANIFEST):
            return ''
        with open(CUR_EULER_MANIFEST, 'r') as fp:
            euler_info = yaml.safe_load(fp)
        euler_ver = euler_info.get('Version', '').strip()
        log.info("STARTUP: Current euler version is %s.", euler_ver)
        return euler_ver

    def check_pkg_dir_euler_version(self, pkg_dir, euler_ver):
        euler_path = self._get_cmpt_path(pkg_dir, 'euler')
        if not euler_path:
            return False
        euler_ver_str = "euler-{0}-".format(euler_ver)
        if euler_ver_str in euler_path:
            return True
        return False

    def get_upgrade_info(self):
        src_ver = None
        dst_ver = None
        if not os.path.exists(UPGRADE_FLAG_PATH):
            log.info("STARTUP: Not in upgrade, no need to handle pkg_cur.")
            return None, None
        with open(UPGRADE_FLAG_PATH) as fp:
            upg_info = fp.readlines()
        for line in upg_info:
            if "srcnumversion" in line:
                src_ver = line.strip().split('=')[1]
            if "dstnumversion" in line:
                dst_ver = line.strip().split('=')[1]
        log.info("STARTUP: src %s, dst %s", src_ver, dst_ver)
        return src_ver, dst_ver

    @staticmethod
    def change_pkg_cur_to_version(version):
        log.info("STARTUP: Change pkg_cur to version %s.", version)
        mount = "mount -o remount,rw,async /startup_disk/image/"
        if os.system(mount):
            log.error("STARTUP: mount startup_disk rw mode failed.")
        if os.system('ln -snf {src} {dst} && fsync {dst}'.format(src='{0}/system'.format(version), dst=SYS_CUR_PATH)):
            log.error("STARTUP: Change pkg_cur to version(%s) failed.", version)
        return

    def modify_pkg_cur(self, euler_ver):
        file_list = [per_file for per_file in os.listdir(IMAGE_DIR) if per_file.isdigit()]
        for version in file_list:
            if self.check_pkg_dir_euler_version(os.path.join(IMAGE_DIR, version, 'system/packages'), euler_ver):
                self.change_pkg_cur_to_version(version)
                log.info("STARTUP: Pkg cur points to %s.", version)
                return
        log.warning("STARTUP: Failed to find compatible version.")
        return

    def handle_pkg_cur(self):
        """
        For the V2R9 euler switch, package must match with euler os, else the node will can not start
        :return:
        """
        try:
            euler_ver = self.get_euler_version()
            if not euler_ver:
                log.warning("STARTUP: Get euler version failed.")
                return
            log.info("STARTUP: Get euler version %s", euler_ver)
            if self.check_pkg_dir_euler_version(PKG_CUR, euler_ver):
                log.info("STARTUP: Euler is compatible with pkg_cur.")
                return
            self.modify_pkg_cur(euler_ver)
            return
        except Exception:
            log.exception("STARTUP: Handle pkg_cur excepted.")
            return

    def install_other(self):
        """

        :return:
        """
        log.info("STARTUP: Begin to install components.")
        if not self._load_cmpt_list():
            return False
        # 启动盘设置读写
        mount = "mount -o remount,rw,async /startup_disk/image/"
        os.system(mount)
        error_code = ''
        try:
            for batch in self.cmpt_list[:]:
                tpool = []
                # 不重复安装swm
                for cmpt in batch:
                    if cmpt.name == "swm":
                        continue
                    thread = threading.Thread(target=self.exec_cmpt_cmd, args=(cmpt, 'install',))
                    thread.start()
                    tpool.append(thread)
                for thread in tpool:
                    thread.join()
            if not self.result:
                log.error("STARTUP: Any component install failed.")
                return False
            log.info("STARTUP: Install all components successfully.")
            # 变更权限
            self.modify_group_user()
            self.save_state(self.STATE_ALL_INSTALLED)
            if not self.resume_euler_patch('after_install') or \
                    not self.resume_dopra_patch():
                error_code = PATCH_RESUME_FAIL_ERROR_CODE
                return False
            return True
        except Exception:
            log.exception("install other exceped")
            return False
        finally:
            not_mount = "mount -o remount,ro,sync /startup_disk/image/"
            os.system(not_mount)
            cmd = "sh /OSM/script/os_load_select_ver.sh"
            os.system(cmd)
            self.resume_euler_special_patch()
            self.record_error_code(error_code=error_code)

    @staticmethod
    def data_node_rescue_mode():
        if NODE_TYPE != 'DATA_NODE':
            return False
        if os.readlink(BOOT_LINK) == 'boot_rescue':
            log.info("STARTUP: boot link to boot_rescue.")
            cmd = '/OSM/script/os_record_abnormal_status.sh -s 201'
            os.system(cmd)
            return True
        return False

    @staticmethod
    def exec_upg_bios_cmd(params):
        cmd = UPG_BIOS_SCRIPT.format(params)
        log.info("UPG_BIOS: begin to exec cmd(%s).", cmd)
        ret = os.system(cmd)
        log.info("UPG_BIOS: exec cmd(%s), ret(%s)", cmd, ret)
        return ret

    def bg_upg_opposite_bios(self):
        param = " ".join(['-t', BiosUpgType.UPG_SLAVE, '-k'])
        thread = threading.Thread(target=self.exec_upg_bios_cmd, args=(param,))
        thread.setDaemon(True)
        thread.start()
        return

    def upgrade_opposite_bios(self):
        """
        :return:
        """
        if os.path.exists(NEED_SYNC_FW_FLAG_AFTER_REBOOT):
            self.bg_upg_opposite_bios()
        return

    @start_finish
    def start_other(self):
        """

        :return:
        """

        if not os.system('cat /proc/cmdline |grep os_factory'):
            warn_str = "STARTUP: not support to start component in os_factory mode."
            print(warn_str)
            log.warning(warn_str)
            return True

        if self.data_node_rescue_mode():
            return True

        #  upgrade bios ahead insmod ko,change spare-part do not upgrade bios.
        if not os.path.exists(SPARE_PART_FLAG) and os.system(UPG_BIOS_SCRIPT.format('-r')):
            log.error("STARTUP: upgrade bios fail.")
            return False

        self.upgrade_opposite_bios()
        #  power-on pause function
        if os.path.exists(THIRD_PAUSE_FLAG):
            log.warning("STARTUP: sys pause record flag exist, not start component.")
            return True
        log.info("STARTUP: Begin to start other components.")
        if not self._load_cmpt_list():
            return False
        for batch in self.cmpt_list:
            # start 分组内也串行执行
            for cmpt in batch:
                if cmpt.name == 'swm':
                    continue
                ret = self.exec_cmpt_cmd(cmpt, 'start')
                # 控制器备件的场景，需要做烧盘的操作
                if cmpt.name == "kernel" and os.path.exists(SPARE_PART_FLAG) and NODE_TYPE != 'DATA_NODE':
                    ret_code = os.system(SPARE_EXEC_SCRIPT)
                    if ret_code:
                        log.error("STARTUP: spare exec result is %s.", ret_code)
                        record_error_code_cmd = '/OSM/script/os_record_abnormal_status.sh -s 203'
                        os.system(record_error_code_cmd)
                        return False
                # kernel组件即便失败，备件流程也要能进行下去
                if not ret:
                    log.error("STARTUP: Any component start failed.")
                    record_error_code_cmd = '/OSM/script/os_record_abnormal_status.sh -s 203'
                    os.system(record_error_code_cmd)
                    return False
        self.save_state(self.STATE_ALL_STARTED)
        log.info("STARTUP: Start all components successfully.")
        shutil.rmtree(EXTRACT_DIR, ignore_errors=True)
        return self.resume_euler_patch('after_start')

    def start_swm(self):
        """
        :description:just start swm part
        :return:
        """
        log.info("STARTUP: Begin to start components.")
        if not self._load_cmpt_list():
            return False
        for batch in self.cmpt_list:
            for cmpt in batch:
                if cmpt.name != 'swm':
                    continue
                if not self.exec_cmpt_cmd(cmpt, 'start'):
                    log.error("STARTUP: swm component start failed.")
                    return False
        log.info("STARTUP: Start swm components successfully.")
        return True

    @staticmethod
    def install_hook():
        if os.path.exists(HOOK_REPLACE):
            cmd = 'cd %s; cp -af * /' % HOOK_REPLACE
            os.system(cmd)
        if os.path.exists(HOOK_SCRIPT):
            for script in os.listdir(HOOK_SCRIPT):
                cmd = 'sh %s/%s' % (HOOK_SCRIPT, script)
                os.system(cmd)
        return True

    def prepare(self):
        """

        :return:
        """
        if self.STATE_INIT != self.state:
            return
        shutil.rmtree(EXTRACT_DIR, ignore_errors=True)
        os.makedirs(EXTRACT_DIR, 0o755)
        return

    def run(self):
        self.prepare()
        run_list = []
        if self.STATE_ALL_STARTED == self.state:
            return True
        if self.STATE_INIT == self.state:
            run_list = [self.install_swm, self.install_other, self.install_hook, self.start_swm, self.start_other]
        elif self.STATE_SWM_INSTALLED == self.state:
            run_list = [self.install_other, self.install_hook, self.start_swm, self.start_other]
        elif self.STATE_ALL_INSTALLED == self.state:
            run_list = [self.install_hook, self.start_swm, self.start_other]

        # 如果为os_only模式，且系统没有执行过startall，则只执行install，不执行start动作
        if not os.system('cat /proc/cmdline |grep os_only') or not os.system('cat /proc/cmdline |grep os_rescue') \
                or not os.system('cat /proc/cmdline |grep os_netboot'):
            if self.state == self.STATE_INIT:
                log.info("STARTUP: System is os_only mode, do not start components.")
                run_list.remove(self.start_other)
                run_list.remove(self.install_hook)
                if os.system('cat /proc/cmdline |grep os_rescue'):
                    run_list.remove(self.start_swm)

        for func in run_list:
            if not func():
                return False
        return True


def set_node_type():
    global NODE_TYPE
    if os.getenv('BOARD_TYPE', None) in DATA_NODE_BOARD:
        cmd = 'mkdir -p /startup_disk/conf/conf_local/; touch %s; sync' % DATA_NODE_FLAG_FILE
        os.system(cmd)
    NODE_TYPE = 'CTRL_NODE' if not os.path.exists(DATA_NODE_FLAG_FILE) else 'DATA_NODE'
    os.environ['NODE_TYPE'] = NODE_TYPE
    log.info('NODE_TYPE is %s.', NODE_TYPE)


def set_board_type():
    board_type = ''
    if not os.path.exists(BOARD_TYPE_FILE):
        cmd = 'cat %s>%s' % (PROC_OS_BSP, BOARD_TYPE_TEMP_FILE)
    else:
        cmd = 'cp -rf %s %s' % (BOARD_TYPE_FILE, BOARD_TYPE_TEMP_FILE)
    ret_code = os.system(cmd)
    if ret_code:
        log.error("set_env: get board type failed")
        return 1
    try:
        with open(BOARD_TYPE_TEMP_FILE, 'rb') as f:
            value_list = f.readlines()
        for value in value_list:
            context = decode_str(value).lstrip().rstrip()
            if "Product Name is " in context:
                tmp = context.split(' ')
                board_type = tmp[len(tmp) - 1]
                break
    except Exception as e:
        log.error("set_env: get board type except %s.", e)
        return 1
    finally:
        os.remove(BOARD_TYPE_TEMP_FILE)
        os.environ['BOARD_TYPE'] = board_type


def set_active_patch_flag():
    try:
        os.environ['ACTIVE_PATCH_FLAG'] = "ACTIVE_PATCH"
        cur_ver = os.readlink(SYS_CUR_PATH).split('/')[0]
        patch_path = os.path.join('/startup_disk/image/', cur_ver,
                                  'hotpatch/patch_cur')
        if os.path.exists(os.path.join(patch_path, "bsp_acstatus.ko")):
            log.info("STARTUP: The bsp ko in patch.")
            cmd = "insmod %s" % os.path.join(patch_path, "bsp_acstatus.ko")
            if not os.system(cmd):
                if not os.system("cat /proc/bspacstatus |grep 'acstatus:1'"):
                    log.error("STARTUP: Power-off and do not active patch.")
                    os.environ['ACTIVE_PATCH_FLAG'] = "ACTIVE_NO_PATCH"
            cmd = "rmmod bsp_acstatus"
            os.system(cmd)
    except Exception as e:
        log.error("set_env: get active patch flag %s.", e)
        return 1

# 设置环境变量
def set_env():
    os.environ['PATH'] = "/OSM/bin:/OSM/bin/script:/OSM/script:" + os.getenv('PATH')
    set_board_type()
    set_node_type()
    os.environ['ENV_PATCH_RESUME_STAGE'] = 'POWER_ON_RESUME'
    set_active_patch_flag()


def get_cmpt_list():
    global CMPT_LIST

    if not NODE_TYPE:
        return False
    if NODE_TYPE == 'DATA_NODE':
        CMPT_LIST = CMPT_LIST_DATA
    else:
        CMPT_LIST = CMPT_LIST_CTL
    return True


def exec_cmd():
    exec_cmd_list = [
        'taskset -cp 0-255 %d' % os.getpid(),
        'cp -af /startup_disk/image/pkg_cur/manifest.yml /OSM/conf/',
    ]
    for cmd in exec_cmd_list:
        os.system(cmd)
    set_env()
    get_cmpt_list()
    result = StartUp().run()
    return 0 if result else 1


def wait_installed():
    su = StartUp()
    for _dummy in range(600):
        su.load_state()
        if su.load_state() >= su.STATE_ALL_INSTALLED:
            log.info("STARTUP: Wait system installed successfully.")
            return 0
        time.sleep(1)
    log.error("STARTUP: Wait system installed timeout.")
    return 1


if __name__ == '__main__':
    log = logging.getLogger("startup")
    formatter = logging.Formatter(fmt="[%(asctime)s][%(levelname)s][%(message)s][%(filename)s, %(lineno)d]",
                                  datefmt="%b %d %Y %H:%M:%S")
    file_handler = logging.FileHandler(filename="/OSM/log/cur_debug/startup.log")
    file_handler.setFormatter(formatter)
    log.addHandler(file_handler)
    log.setLevel(logging.INFO)

    fork_ret = os.fork()
    if fork_ret:
        sys.exit(wait_installed())
    else:
        sys.exit(exec_cmd())
