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

import os
import shutil
import subprocess
import sys
import logging
import yaml

from distutils.sysconfig import get_python_lib

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__)))
RUN_DIR = "/OSM/coffer_bin/upg_check"
MY_NAME = os.path.basename(__file__)
REPO_DIR = os.path.join(TOP_DIR, "repo")
UPGRADE_CHECK_RPM_DB_PATH = '/var/lib/upgrade_check_rpm'
PTH_FILE = os.path.join(get_python_lib(), "upg_check.pth")
IMAGE_MANIFEST_PATH = '/startup_disk/image/pkg_cur/manifest.yml'
RUN_XML_PATH = '/OSM/coffer_bin/upg_check/upd_check_item.xml'

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

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


class ProductName(object):
    Dorado = 'Dorado'
    Converged = 'Converged'
    BackupStorage = 'BackupStorage'
    Micro = 'Micro'
    Micro_Unified = 'Micro_Unified'
    Lite = 'Lite'
    Lite_Converged = 'Lite_Converged'
    ASeries = "ASeries"


def show_help():
    print(USAGE)
    return


def start():
    return 0


def stop():
    return 0


def online():
    return 0


def offline():
    return 0


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


def add_pth_2_path(pkg_dir):
    """

    :param cls:
    :param pkg_dir:
    :return:
    """
    with open(PTH_FILE, "w+") as f:
        f.write(pkg_dir)
    return


def remove_pth_from_path():
    """

    :param cls:
    :return:
    """
    if os.path.isfile(PTH_FILE):
        os.remove(PTH_FILE)
    return


def get_product_name():
    with open(IMAGE_MANIFEST_PATH) as fd:
        mnfst_yml = yaml.safe_load(fd)
        return mnfst_yml.get('SYS', {}).get('Product', '')


def get_cur_product_check_xml():
    run_dir = os.path.dirname(RUN_XML_PATH)
    dorado_xml = RUN_XML_PATH
    micro_xml = os.path.join(run_dir, 'upd_check_item_micro.xml')
    lite_xml = os.path.join(run_dir, 'upd_check_item_lite.xml')
    a_series_xml = os.path.join(run_dir, 'upd_check_item_a_series.xml')
    product_xml_map = {
        ProductName.Dorado: dorado_xml,
        ProductName.Converged: dorado_xml,
        ProductName.BackupStorage: dorado_xml,
        ProductName.Micro: micro_xml,
        ProductName.Micro_Unified: micro_xml,
        ProductName.Lite: lite_xml,
        ProductName.Lite_Converged: dorado_xml,
        ProductName.ASeries: a_series_xml,
    }
    product_name = get_product_name()
    logging.info('Current product name is %s.', product_name)
    return product_xml_map.get(product_name, dorado_xml)


def move_cur_product_check_xml():
    cur_product_xml = get_cur_product_check_xml()
    logging.info('Current product check xml is %s', cur_product_xml)

    if cur_product_xml != RUN_XML_PATH:
        try:
            shutil.move(cur_product_xml, RUN_XML_PATH)
            os.chmod(RUN_XML_PATH, 0o640)
        except Exception:
            logging.exception("Move and chmod file %s to %s failed.", cur_product_xml, RUN_XML_PATH)
            return 1

    # 删除其他没有使用的检查项xml
    dirname = os.path.dirname(cur_product_xml)
    for f in os.listdir(dirname):
        file_path = os.path.join(dirname, f)
        if os.path.isfile(file_path) \
                and f.startswith('upd_check_item_') \
                and f.endswith('xml'):
            os.remove(file_path)
    return 0


def install():
    create_rpm_dir()
    # 到repo目录下取出rpm包来进行安装
    for rpm_file in os.listdir(REPO_DIR):
        cmd = "rpm -ivh --nodeps --force --dbpath=%s %s" % (UPGRADE_CHECK_RPM_DB_PATH, os.path.join(REPO_DIR, rpm_file))
        ret_code = os.system(cmd)
        if ret_code:
            logging.error("install upgrade_check service failed")
            return 1
        cfg_path = os.path.join(RUN_DIR, 'conf')
        if not os.path.isdir(cfg_path):
            os.makedirs(cfg_path)
        ret_code = os.system('cp -af %s/manifest.yml %s' % (TOP_DIR, cfg_path))
        if ret_code:
            logging.error("copy manifest.yml file failed.")
            return 1

        ret_code = move_cur_product_check_xml()
        if ret_code:
            logging.error("move check xml failed.")
            return 1
        add_pth_2_path(RUN_DIR)
    return 0


def uninstall():
    remove_pth_from_path()
    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')
    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("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("The old version is same(%s) with new version, no need upgrade.", old_ver)
        return 1
    logging.info("The old version(%s) is different with new version(%s), need upgrade.", old_ver, new_ver)
    return 2


def upgrade():
    return install()


def rollback():
    return 0


def pre_upgrade():
    return 0


def pre_rollback():
    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)

