#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
import time

from oslo_config import cfg
from oslo_log import log as logging
from futurist import periodics
from node_agent.common.utils import execute_shell

CONF = cfg.CONF
LOG = logging.getLogger(__name__)
DIO_OPEN_TIME_PATH = "/sf/data/dio_expire_time"
PHXDFS_CONF_PATH = "/root/phxstor-rootfs/etc/phxdfs/phxdfs.conf"
FIVE_MIN_TIME = 5 * 60


class MonitorDioStatus(object):
    def collect(self, handler):
        """
        监控dio分层状态，是否已经达到过期时间，若过期则禁用dio分层
        """
        import rpdb
        rpdb.set_trace('/tmp/monitor_dio_status')

        if not self.get_dio_status():
            # dio分层设置为全局设置，而osd预分配设置为逐节点设置，需特殊处理
            if os.path.exists(DIO_OPEN_TIME_PATH):
                # dio分层已关闭，但dio分层记录文件仍存在，则代表当前节点未开osd预分配
                self.open_osd_prelloc()
                # 再删一次dio分层记录文件
                os.remove(DIO_OPEN_TIME_PATH)
            return

        self.check_dio_expire_time()

    def check_dio_expire_time(self):
        """检测dio分层开启时间"""

        now_time = time.time()
        if not os.path.exists(DIO_OPEN_TIME_PATH):
            LOG.debug("dio_open_time file not exists, skip check")
            return

        with open(DIO_OPEN_TIME_PATH, "r") as fp:
            dio_expire_time = json.loads(fp.read())
            dio_open_time = dio_expire_time.get("dio_open_time")
            expire_time = dio_expire_time.get("expire_time")
        # 开启时间至今超过过期时间，则禁用dio分层
        if now_time - dio_open_time >= expire_time * 60 * 60:
            self.open_osd_prelloc()

            LOG.debug("the time for enabling dio layering exceeds {}h, dio layering is to be disabled.".format(expire_time))
            # 超过过期时间，则禁用dio分层
            cmd = "eds_manager ceph_ops --set_dio_mode false"
            execute_shell(cmd)
            LOG.debug("set mds_enable_dio to false success.")

            cluster_host = self.get_cluster_host()
            curl_cmd = "curl http://{}:9999/flags_index/ocs/bool_option_force_all_dio?setvalue=0".format(cluster_host)
            execute_shell(curl_cmd)
            execute_shell("rm -rf {}".format(DIO_OPEN_TIME_PATH))
            LOG.debug("set bool_option_force_all_dio to 0 success.")

    def open_osd_prelloc(self):
        """开启所有osd预分配"""
        get_osd_id_cmd = "chroot /root/phxstor-rootfs/ supervisorctl status |grep 'osd' | awk '{print $1}'| grep -o '[0-9]\+'"
        osd_ids = execute_shell(get_osd_id_cmd)
        if osd_ids:
            for osd_id in osd_ids.strip().split():
                execute_shell("chroot /root/phxstor-rootfs/ timeout 10 phxstor daemon osd.{} plogstore_tool 'spac 256'".format(osd_id))
                # 检查是否设置成功
                cmd = "chroot /root/phxstor-rootfs/ timeout 10 " \
                      "phxstor daemon osd.{} plogstore_tool 'gpac'| grep 'prealloc_num'| grep -w '256'".format(osd_id)
                try:
                    execute_shell(cmd)
                except Exception as e:
                    LOG.error("set osd.{} failed, error: {}".format(osd_id, e))
                    raise

                LOG.debug("set osd.{} prealloc_count to 256 success.".format(osd_id))

    def get_cluster_host(self):
        # 获取phxstor-mgr主控节点
        cmd = "chroot /root/phxstor-rootfs/ phxstor -s |grep 'mgr:' |awk '{print $2}' |cut -d '(' -f 1"
        hostname = execute_shell(cmd)
        cmd = "grep '%s' /etc/hosts |awk '{print $1}'"
        cluster_host = execute_shell(cmd % hostname)
        return cluster_host.strip()

    def get_dio_status(self):
        """获取当前dio分层开启状态"""
        cmd = "cat /root/phxstor-rootfs/etc/phxdfs/phxdfs.conf 2>&1| grep -w 'mds_enable_dio'| awk '{print $2}'"
        mds_enable_dio_status = execute_shell(cmd)
        if not mds_enable_dio_status.strip() or mds_enable_dio_status.strip() == "false":
            return False

        cluster_host = self.get_cluster_host()
        cmd = "curl http://{}:9999/flags_index/ocs/bool_option_force_all_dio".format(cluster_host)
        dio_info = execute_shell(cmd)
        if "bool_option_force_all_dio" not in dio_info:
            return False

        dio_info = dio_info.strip().split("\n")[-1]
        dio_value = dio_info.split("|")[1]
        if int(dio_value.strip()) == 0:
            return False
        return True


@periodics.periodic(FIVE_MIN_TIME)
def periodic_task(handler):
    collector = MonitorDioStatus()
    collector.collect(handler)
