
from __future__ import absolute_import
from __future__ import division

import logging
import socket

import six

from vdsm.common.define import Mbytes
from vdsm.config import config
from vdsm import throttledlog

from vdsm.common.cpuarch import PAGE_SIZE_BYTES
from vdsm.common import unixrpc


throttledlog.throttle('MomNotAvailable', 100)
throttledlog.throttle('MomNotAvailableKSM', 100)


class MomClient(object):

    def __init__(self, sock_path):
        self.log = logging.getLogger("MOM")
        self.log.info("Preparing MOM interface")
        self._sock_path = sock_path
        self._mom = None
        self._policy = {}

    def connect(self):
        if self._mom is not None:
            return

        self.log.info("MOM: Using named unix socket: %s",
                      self._sock_path)
        self._mom = unixrpc.UnixXmlRpcClient(self._sock_path)

    def getKsmStats(self):
        ret = {}

        try:
            stats = self._mom.getStatistics()['host']
            ret['ksmState'] = bool(stats['ksm_run'])
            ret['ksmPages'] = stats['ksm_pages_to_scan']
            ret['ksmMergeAcrossNodes'] = bool(stats['ksm_merge_across_nodes'])
            ret['memShared'] = stats['ksm_pages_sharing'] * PAGE_SIZE_BYTES
            ret['memShared'] //= Mbytes
            ret['ksmCpu'] = stats['ksmd_cpu_usage']
        except (AttributeError, socket.error):
            throttledlog.warning('MomNotAvailableKSM',
                                 "MOM not available, "
                                 "KSM stats will be missing.")

        return ret

    def setPolicy(self, policyStr):
        try:
            self._mom.setPolicy(policyStr)
        except (AttributeError, socket.error):
            self.log.warning("MOM not available, Policy could not be set.")

    def setPolicyParameters(self, key_value_store):

        self._policy.update(key_value_store)

        policy_string = "\n".join(["(set %s %r)" % (k, v)
                                   for k, v in six.iteritems(self._policy)])

        try:
            self._mom.setNamedPolicy(config.get("mom", "tuning_policy"),
                                     policy_string)
        except (AttributeError, socket.error):
            self.log.warning("MOM not available, Policy could not be set.")

    def getStatus(self):
        try:
            if self._mom.ping():
                return 'active'
            else:
                return 'inactive'
        except (AttributeError, socket.error):
            throttledlog.warning('MomNotAvailable', "MOM not available.")
            return 'inactive'
