Source code for cup.services.heartbeat

#!/usr/bin/python
# -*- coding: utf-8 -*
# #############################################################################
#
#  Copyright (c) 2014 Baidu.com,  Inc. All Rights Reserved
#
# #############################################################################
"""
:author:
    Guannan Ma maguannan @mythmgn
:create_date:
    2014
:last_date:
    2014
:descrition:
    heartbeat related module
"""

import time
import pickle

from cup import log
from cup import net
from cup.util import conf
from cup.res import linux

try:
    # pylint: disable=W0611
    import Queue as queue
except ImportError:
    # pylint: disable=F0401
    import queue


[docs]class Device(object): """ Base class for all devices in heartbeat service """ def __init__(self, name): """ :param: the name of the device """ self._name = name self._last_healthy = time.time() self._dict_info = None
[docs] def get_last_healthy(self): """ get last_healthy time of the device """ return self._last_healthy
[docs] def set_last_healthy(self): """ set last_healthy time """ log.debug('device %s set_last_healthy' % self._name) self._last_healthy = time.time()
[docs] def serilize(self): """ serilize device info """ return pickle.dumps(self._dict_info)
[docs] def get_name(self): """get name""" return self._name
[docs]class LinuxHost(Device): """ a linux host resource """ def __init__(self, name, init_this_host=False, iface='eth0'): """ :param name: name of the LinuxHost :param init_this_host: if init_this_host is True, will initialize the object by this linux . Otherwise, you need to initialize it by yourself. """ super(self.__class__, self).__init__(name) # -1 means initialized self._dict_info = { 'iface': iface, 'ipaddr': '0.0.0.0', 'hostname': net.get_local_hostname(), 'cpu_idle': -1, 'mem_inuse': -1, # MB 'mem_total': -1, 'net_in': -1, # kb 'net_out': -1 # kb } if init_this_host: self._dict_info['ipaddr'] = net.get_hostip() cpuinfo = linux.get_cpu_usage(1) meminfo = linux.get_meminfo() self._dict_info['net_in'] = linux.get_net_recv_speed( self._dict_info['iface'], 1 ) self._dict_info['net_out'] = linux.get_net_transmit_speed( self._dict_info['iface'], 1 ) # pylint: disable=E1101 self._dict_info['cpu_idle'] = cpuinfo.idle # pylint: disable=E1101 self._dict_info['mem_inuse'] = meminfo.total - meminfo.free
[docs] def set_linux_res_bydict(self, info_dict): """ { 'iface': 'eth0', 'ipaddr': '10.10.10.1', 'port': 8089, 'cpu_idle': 50, 'mem_inuse': 1024, # MB 'mem_total': 8192, 'net_in': 8192, # kb 'net_out': 102400, # kb } """ for key in info_dict: if key not in self._dict_info: log.warn('does not have this key:%s, ignore' % key) continue self._dict_info[key] = info_dict[key] log.debug('linux info:%s updated, %s' % (key, info_dict[key]))
[docs] def set_ip_port(self, ipaddr): """ set ip information :param ipaddr: ipaddr should be string and something like 10.10.10.1 """ self._dict_info['ipaddr'] = ipaddr
[docs] def get_ip(self): """ return ip information """ return self._dict_info['ipaddr']
[docs] def set_cpu_idle(self, idle_rate): """ set cpu idle rate """ self._dict_info['cpu_idle'] = idle_rate
[docs] def get_cpu_idle(self): """ get cpu idle rate """ return self._dict_info['cpu_idle']
[docs] def set_mem_usage(self, mem_inuse, mem_total): """ set up mem_inuse and mem_total. Will update any of them if it is not None. """ if mem_inuse is not None: self._dict_info['mem_inuse'] = mem_inuse if mem_total is not None: self._dict_info['mem_total'] = mem_total
[docs] def get_mem_info(self): """ :return: (mem_inuse, mem_total), in MB """ return (self._dict_info['mem_inuse'], self._dict_info['mem_total'])
[docs] def set_net_usage(self, net_in, net_out): """ :param net_in: net_in in kB/s. If net_in is None, will update nothing. :param net_out: net_out in kB/s. If net_out is None, will update nothing. """ if net_in is not None: self._dict_info['net_in'] = net_in if net_out is not None: self._dict_info['net_out'] = net_out
[docs] def get_net_usage(self): """ :return: (net_in, net_out) """ return (self._dict_info['net_in'], self._dict_info['net_out']) # class Process(LinuxHost): # def __init__(self, procname, path):
[docs]class HeartbeatService(object): """ HeartBeat service """ def __init__(self, judge_lost_in_sec, keep_lost=False): """ :param judge_lost_in_sec: if you call function get_lost() and find that time.time() minus last_healthy time of the device > judge_lost_in_sec, the device will be marked as lost. :param keep_lost: whether we store lost deivce info """ self._judge_lost = judge_lost_in_sec self._devices = {} if keep_lost: self._lost_devices = {} else: self._lost_devices = None
[docs] def activate(self, key, device): """ activate a device in HeartBeat Service. Add one if it's new to hbs. """ device.set_last_healthy() self._devices[key] = device
[docs] def adjust_judge_lost_time(self, time_in_sec): """ adjust judge_lost_in_sec """ log.info( 'heartbeat service judge_lost_in_sec changed, old %d, new %d' % ( self._judge_lost, time_in_sec ) ) self._judge_lost = time_in_sec return
[docs] def refresh(self, key): """ :param key: refresh the device by key :return: if key does not exist, return False else, fresh the last_healthy time of the device """ assert type(key) == str, 'needs to be a str' device = self._devices.get(key) if device is None: log.warn('Device not found, key:%s' % key) return False device.set_last_healthy() return True
[docs] def get_lost(self): """ get lost devices """ now = time.time() lost_devices = [] for dkey in self._devices.keys(): device = self._devices[dkey] if now - device.get_last_healthy() > self._judge_lost: if self._lost_devices is not None: self._lost_devices[dkey] = device del self._devices[dkey] lost_devices.append(device) log.warn('heartbeat lost, device:%s' % dkey) return lost_devices
[docs] def cleanup_oldlost(self, dump_file=None): """ cleanup old lost devices. :param dump_file: if dump_file is not None, we will store devices info into dump_file Otherwise, we will cleanup the lost devices only. """ log.info('start - empty_lost devices, dump_file:%s' % dump_file) if self._lost_devices is None: log.info('end - does not keep_lost devices, return') return if dump_file is None: self._lost_devices = {} log.info('end - does not have dump_file, return') return info_dict = {} info_dict['devices'] = {} if len(self._lost_devices) != 0: info_dict['devices']['lost'] = [] info_dict['devices']['lost_num'] = len(self._lost_devices) else: info_dict['devices']['lost_num'] = 0 for dkey in self._lost_devices.keys(): try: tmp_dict = {} tmp_dict['key'] = dkey tmp_dict['last_healthy'] = self._devices[dkey].get_last_healthy() del self._lost_devices[dkey] log.info('end - empty_lost devices') info_dict['devices']['lost'].append(tmp_dict) except KeyError as error: log.warn('failed to dump lost_file, error:%s' % str(error)) conf_writer = conf.Dict2Configure(info_dict) conf_writer.write_conf(dump_file) return
def _test(): localhost = LinuxHost(name='localhost', init_this_host=True) binary = localhost.serilize() print 'binary:%s' % binary print pickle.loads(binary) if __name__ == '__main__': _test() # vi:set tw=0 ts=4 sw=4 nowrap fdm=indent