3831 lines
		
	
	
		
			157 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			3831 lines
		
	
	
		
			157 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python2
 | |
| # -*- mode: python;coding: utf-8 -*-
 | |
| 
 | |
| # dooba ---
 | |
| #
 | |
| # Filename: dooba
 | |
| # Description: `dooba' is a easy tools monitoring oceanbase cluster for
 | |
| #               oceanbase admins. It's based on python curses library, and is a
 | |
| #               powerful tool for watching oceanbase cluster status with
 | |
| #               straightfoward vision.
 | |
| 
 | |
| 
 | |
| # This program is free software; you can redistribute it and/or
 | |
| # modify it under the terms of the GNU Lesser General Public License
 | |
| # as published by the Free Software Foundation; either version 3, or
 | |
| # (at your option) any later version.
 | |
| #
 | |
| # This program is distributed in the hope that it will be useful,
 | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| # Lesser General Public License for more details.
 | |
| #
 | |
| # You should have received a copy of the GNU Lesser General Public
 | |
| # License along with this program; see the file COPYING. If not, see
 | |
| # <http://www.gnu.org/licenses/>. 
 | |
| #
 | |
| 
 | |
| # Code:
 | |
| 
 | |
| from collections import deque
 | |
| from datetime import datetime, timedelta, date
 | |
| from errno import *
 | |
| from getopt import getopt, GetoptError
 | |
| from locale import setlocale, LC_ALL
 | |
| from os import environ, read, setsid
 | |
| from pprint import pformat
 | |
| from random import shuffle
 | |
| from subprocess import Popen, PIPE, STDOUT, call
 | |
| from telnetlib import Telnet
 | |
| from threading import Thread
 | |
| from time import sleep, strftime
 | |
| from urllib2 import urlopen, URLError
 | |
| import BaseHTTPServer
 | |
| import atexit
 | |
| import bz2
 | |
| import curses
 | |
| import curses.textpad
 | |
| import itertools
 | |
| import json
 | |
| import math
 | |
| import os
 | |
| import select
 | |
| import signal
 | |
| import socket
 | |
| import struct
 | |
| import sys
 | |
| import tempfile
 | |
| import textwrap
 | |
| import types
 | |
| import traceback
 | |
| import time
 | |
| import pdb
 | |
| 
 | |
| f_data_log = ''
 | |
| def seconds(td):
 | |
|     return float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / (10**6);
 | |
| 
 | |
| 
 | |
| def check_datalog(datalog, tenantid=1):
 | |
|     global f_data_log
 | |
| 
 | |
|     d = os.path.split(datalog)[0]
 | |
|     l = os.path.split(datalog)[1]
 | |
| 
 | |
|     now = datetime.now()
 | |
|     l = l + "." + str(tenantid) + "_" + now.strftime("%Y%m%d-%H%M%S")
 | |
| 
 | |
|     if not os.path.isdir(d):
 | |
|         return False
 | |
|     try:
 | |
|         f = open(d+"/"+l, "w")
 | |
|         f.write("----")
 | |
|         f.close()
 | |
|     except:
 | |
|         f.close()
 | |
|         return False
 | |
| 
 | |
|     f_data_log = d+"/"+l
 | |
| 
 | |
|     return True
 | |
| 
 | |
| class Global:
 | |
|     MAX_LINES = 900
 | |
|     WIDGET_HEIGHT = 7
 | |
|     DEFAULT_USER = ''
 | |
|     DEFAULT_PASS = ''
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| class Options(object):
 | |
|     host = '127.0.0.1'
 | |
|     port = 2881
 | |
|     user = "root"
 | |
|     password = ""
 | |
|     database = "oceanbase"
 | |
|     supermode = False
 | |
|     interval = 1
 | |
|     dataid = 0
 | |
|     using_ip_port = False
 | |
|     env = 'unknown'
 | |
|     machine_interval = 5
 | |
|     degradation = False
 | |
|     show_win_file = None
 | |
|     daemon = False
 | |
|     http = False
 | |
|     daemon_action = 'start'
 | |
|     http_port = 33244
 | |
|     debug = False
 | |
|     datalog = ''
 | |
| 
 | |
|     def __str__(self):
 | |
|         result = {}
 | |
|         for k in dir(self):
 | |
|             v = getattr(self, k)
 | |
|             if k.find('__') == 0:
 | |
|                 continue
 | |
|             result[k] = v
 | |
|         return pformat(result)
 | |
| 
 | |
| # auxiliary functions
 | |
| class ColumnFactory(object):
 | |
|     def __init__(self, svr, ip):
 | |
|         DEBUG(self.__init__, "ColumnFactory.__init__(svr='%s',ip='%s') " % (svr, ip), "")
 | |
|         self.__svr = svr
 | |
|         self.__ip = ip
 | |
| 
 | |
|     def count(self, name, sname, obname, duration=True, enable=False):
 | |
|         DEBUG(self.count, "ColumnFactory.count(name='%s',sname='%s',obname='%s' " % (name, sname, obname), "" )
 | |
|         if type(obname) == str:
 | |
|             pass
 | |
|         elif type(obname) == list:
 | |
|             obname = [name for name in obname]
 | |
|         else:
 | |
|             raise Exception("unsupport type %s" % type(obname))
 | |
| 
 | |
|         return self.count0(name, sname, obname, duration, enable)
 | |
| 
 | |
|     def count0(self, name, sname, obname,duration=True, enable=False):
 | |
| 
 | |
|         svr = self.__svr
 | |
|         ip = self.__ip
 | |
|         def calc_func(stat,ip=ip):
 | |
|             def try_get(d, k, b):
 | |
|                 try:
 | |
|                     if d.has_key(k):
 | |
|                         return d['%s' % k]
 | |
|                     else:
 | |
|                         return d['%s' % b]
 | |
|                 except Exception as e:
 | |
|                     raise e
 | |
|             try:
 | |
| 
 | |
|                 if type(obname) == str:
 | |
|                     return try_get(stat, svr, oceanbase.get_current_tenant())[ip][obname]
 | |
|                 elif type(obname) == list:
 | |
|                     return sum([try_get(stat, svr, oceanbase.get_current_tenant())[ip][name] for name in obname])
 | |
|                 else:
 | |
|                     raise Exception("ColumnFactory.count0 unsupport type %s" % type(obname))
 | |
|             except KeyError as e:
 | |
|                 DEBUG(calc_func, "ColumnFactory.count0( stat='%s', ip='%s') exception :" % (stat, ip) ,  e)
 | |
|                 pass
 | |
| 
 | |
|         return Column(name, calc_func, 7, duration=duration, enable=enable, sname=sname)
 | |
| 
 | |
|     def time(self, name, sname, obnamet, obnamec=None, duration=False, enable=False):
 | |
|         if obnamec is None:
 | |
|             obnamec = obnamet
 | |
|         return self.time0(name, sname, obnamet, obnamec, duration=duration,enable=enable)
 | |
| 
 | |
|     def time0(self, name, sname, obnamet, obnamec=None, duration=False, enable=False):
 | |
|         DEBUG(self.time0, "ColumnFactory.time0(svr='%s',ip='%s',name='%s',sname='%s',obnamet='%s', obnamec='%s')" % (self.__svr, self.__ip, name, sname, obnamet, obnamec) , "")
 | |
| 
 | |
|         svr = self.__svr
 | |
|         ip = self.__ip
 | |
| 
 | |
| 
 | |
|         def calc_func(stat,ip=ip):
 | |
|             def try_get(d, k, b):
 | |
|                 if d.has_key(k):
 | |
|                     return d['%s' % k]
 | |
|                 else:
 | |
|                     return d['%s' % b]
 | |
|             try:
 | |
| 
 | |
|                 if type(obnamec) == str:
 | |
|                     total_count = try_get(stat, svr, oceanbase.get_current_tenant())[ip][obnamec]
 | |
|                 elif type(obnamec) == list:
 | |
|                     total_count = sum([try_get(stat, svr, oceanbase.get_current_tenant())[ip][name] for name in obnamec])
 | |
| 
 | |
|                 return try_get(stat, svr, oceanbase.get_current_tenant())[ip][obnamet] / 1000 / float(total_count or 1)
 | |
|             except Exception as e:
 | |
|                 DEBUG(calc_func, "ColumnFactory.time0.calc_func(stat='%s',ip='%s') exception:" % (stat, ip), e)
 | |
|                 pass
 | |
| 
 | |
|         return Column(name, calc_func, 7, duration=duration, enable=enable, sname=sname)
 | |
| 
 | |
|     def cache(self, name, sname, obname):
 | |
|         svr = self.__svr
 | |
|         ip = self.__ip
 | |
|         return Column(name, lambda stat,ip=ip: stat[svr][ip][obname+"_cache_hit"]  / float(stat[svr][ip][obname+"_cache_hit"] + stat[svr][ip][obname+"_cache_miss"] or 1),
 | |
|                       7, enable=False, sname=sname)
 | |
| 
 | |
| 
 | |
| def mem_str(mem_int, bit=False):
 | |
|     mem_int = int(mem_int)
 | |
|     if mem_int < 1024:
 | |
|         return str(mem_int) + (bit and 'b' or '')
 | |
|     mem_int = float(mem_int)
 | |
|     mem_int /= 1024
 | |
|     if mem_int < 1024:
 | |
|         return "%.1fK" % mem_int + (bit and 'b' or '')
 | |
|     mem_int /= 1024
 | |
|     if mem_int < 1024:
 | |
|         return "%.1fM" % mem_int + (bit and 'b' or '')
 | |
|     mem_int /= 1024
 | |
|     if mem_int < 1024:
 | |
|         return "%.2fG" % mem_int + (bit and 'b' or '')
 | |
|     mem_int /= 1024
 | |
|     if mem_int < 1024:
 | |
|         return "%.2fT" % mem_int + (bit and 'b' or '')
 | |
|     return "UNKNOW"
 | |
| 
 | |
| def count_str(count_int, kilo=True):
 | |
|     return str(count_int)
 | |
| 
 | |
| def percent_str(percent_int):
 | |
|     return str(round(float(percent_int) * 100,1)) + "%"
 | |
| 
 | |
| class Cowsay(object):
 | |
|     '''Copyright 2011 Jesse Chan-Norris <jcn@pith.org>
 | |
|        https://github.com/jcn/cowsay-py/blob/master/cowsay.py'''
 | |
|     def __init__(self, str, length=40):
 | |
|         self.__result = self.build_bubble(str, length) + self.build_cow()
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.__result
 | |
| 
 | |
|     def build_cow(self):
 | |
|         return """
 | |
|          \   ^__^
 | |
|           \  (oo)\_______
 | |
|              (__)\       )\/\\
 | |
|                  ||----w |
 | |
|                  ||     ||
 | |
|                 """
 | |
| 
 | |
|     def build_bubble(self, str, length=40):
 | |
|         bubble = []
 | |
|         lines = self.normalize_text(str, length)
 | |
|         bordersize = len(lines[0])
 | |
|         bubble.append("  " + "_" * bordersize)
 | |
| 
 | |
|         for index, line in enumerate(lines):
 | |
|             border = self.get_border(lines, index)
 | |
|             bubble.append("%s %s %s" % (border[0], line, border[1]))
 | |
|             bubble.append("  " + "-" * bordersize)
 | |
| 
 | |
|         return "\n".join(bubble)
 | |
| 
 | |
|     def normalize_text(self, str, length):
 | |
|         lines  = textwrap.wrap(str, length)
 | |
|         maxlen = len(max(lines, key=len))
 | |
|         return [ line.ljust(maxlen) for line in lines ]
 | |
| 
 | |
|     def get_border(self, lines, index):
 | |
|         if len(lines) < 2:
 | |
|             return [ "<", ">" ]
 | |
|         elif index == 0:
 | |
|             return [ "/", "\\" ]
 | |
|         elif index == len(lines) - 1:
 | |
|             return [ "\\", "/" ]
 | |
|         else:
 | |
|             return [ "|", "|" ]
 | |
| 
 | |
| 
 | |
| class Daemon:
 | |
|         """
 | |
|         A generic daemon class.
 | |
| 
 | |
|         Usage: subclass the Daemon class and override the run() method
 | |
|         """
 | |
|         def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
 | |
|                 self.stdin = stdin
 | |
|                 self.stdout = stdout
 | |
|                 self.stderr = stderr
 | |
|                 self.pidfile = pidfile
 | |
| 
 | |
|         def daemonize(self):
 | |
|                 """
 | |
|                 do the UNIX double-fork magic, see Stevens' "Advanced
 | |
|                 Programming in the UNIX Environment" for details (ISBN 0201563177)
 | |
|                 http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
 | |
|                 """
 | |
|                 try:
 | |
|                         pid = os.fork()
 | |
|                         if pid > 0:
 | |
|                                 # exit first parent
 | |
|                                 sys.exit(0)
 | |
|                 except OSError, e:
 | |
|                         sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
 | |
|                         sys.exit(1)
 | |
| 
 | |
|                 # decouple from parent environment
 | |
|                 os.chdir("/")
 | |
|                 os.setsid()
 | |
|                 os.umask(0)
 | |
| 
 | |
|                 # do second fork
 | |
|                 try:
 | |
|                         pid = os.fork()
 | |
|                         if pid > 0:
 | |
|                                 # exit from second parent
 | |
|                                 sys.exit(0)
 | |
|                 except OSError, e:
 | |
|                         sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
 | |
|                         sys.exit(1)
 | |
| 
 | |
|                 # redirect standard file descriptors
 | |
|                 sys.stdout.flush()
 | |
|                 sys.stderr.flush()
 | |
|                 si = file(self.stdin, 'r')
 | |
|                 so = file(self.stdout, 'a+')
 | |
|                 se = file(self.stderr, 'a+', 0)
 | |
|                 os.dup2(si.fileno(), sys.stdin.fileno())
 | |
|                 os.dup2(so.fileno(), sys.stdout.fileno())
 | |
|                 os.dup2(se.fileno(), sys.stderr.fileno())
 | |
| 
 | |
|                 # write pidfile
 | |
|                 atexit.register(self.delpid)
 | |
|                 pid = str(os.getpid())
 | |
|                 file(self.pidfile,'w+').write("%s\n" % pid)
 | |
| 
 | |
|         def delpid(self):
 | |
|                 os.remove(self.pidfile)
 | |
| 
 | |
|         def start(self):
 | |
|                 """
 | |
|                 Start the daemon
 | |
|                 """
 | |
|                 # Check for a pidfile to see if the daemon already runs
 | |
|                 try:
 | |
|                         pf = file(self.pidfile,'r')
 | |
|                         pid = int(pf.read().strip())
 | |
|                         pf.close()
 | |
|                 except IOError:
 | |
|                         pid = None
 | |
| 
 | |
|                 if pid:
 | |
|                         message = "pidfile %s already exist. Daemon already running?\n"
 | |
|                         sys.stderr.write(message % self.pidfile)
 | |
|                         sys.exit(1)
 | |
| 
 | |
|                 # Start the daemon
 | |
|                 self.daemonize()
 | |
|                 self.run()
 | |
| 
 | |
|         def stop(self):
 | |
|                 """
 | |
|                 Stop the daemon
 | |
|                 """
 | |
|                 # Get the pid from the pidfile
 | |
|                 try:
 | |
|                         pf = file(self.pidfile,'r')
 | |
|                         pid = int(pf.read().strip())
 | |
|                         pf.close()
 | |
|                 except IOError:
 | |
|                         pid = None
 | |
| 
 | |
|                 if not pid:
 | |
|                         message = "pidfile %s does not exist. Daemon not running?\n"
 | |
|                         sys.stderr.write(message % self.pidfile)
 | |
|                         return # not an error in a restart
 | |
| 
 | |
|                 # Try killing the daemon process
 | |
|                 try:
 | |
|                         while 1:
 | |
|                                 os.kill(pid, signal.SIGTERM)
 | |
|                                 sleep(0.1)
 | |
|                 except OSError, err:
 | |
|                         err = str(err)
 | |
|                         if err.find("No such process") > 0:
 | |
|                                 if os.path.exists(self.pidfile):
 | |
|                                         os.remove(self.pidfile)
 | |
|                         else:
 | |
|                                 print str(err)
 | |
|                                 sys.exit(1)
 | |
| 
 | |
|         def restart(self):
 | |
|                 """
 | |
|                 Restart the daemon
 | |
|                 """
 | |
|                 self.stop()
 | |
|                 self.start()
 | |
| 
 | |
|         def run(self):
 | |
|                 """
 | |
|                 You should override this method when you subclass Daemon. It will be called after the process has been
 | |
|                 daemonized by start() or restart().
 | |
|                 """
 | |
| 
 | |
| 
 | |
| class Blowfish:
 | |
| 
 | |
|     """Blowfish encryption Scheme
 | |
| 
 | |
|     This class implements the encryption and decryption
 | |
|     functionality of the Blowfish cipher.
 | |
| 
 | |
|     Public functions:
 | |
| 
 | |
|         def __init__ (self, key)
 | |
|             Creates an instance of blowfish using 'key'
 | |
|             as the encryption key. Key is a string of
 | |
|             length ranging from 8 to 56 bytes (64 to 448
 | |
|             bits). Once the instance of the object is
 | |
|             created, the key is no longer necessary.
 | |
| 
 | |
|         def encrypt (self, data):
 | |
|             Encrypt an 8 byte (64-bit) block of text
 | |
|             where 'data' is an 8 byte string. Returns an
 | |
|             8-byte encrypted string.
 | |
| 
 | |
|         def decrypt (self, data):
 | |
|             Decrypt an 8 byte (64-bit) encrypted block
 | |
|             of text, where 'data' is the 8 byte encrypted
 | |
|             string. Returns an 8-byte string of plaintext.
 | |
| 
 | |
|         def cipher (self, xl, xr, direction):
 | |
|             Encrypts a 64-bit block of data where xl is
 | |
|             the upper 32-bits and xr is the lower 32-bits.
 | |
|             'direction' is the direction to apply the
 | |
|             cipher, either ENCRYPT or DECRYPT constants.
 | |
|             returns a tuple of either encrypted or decrypted
 | |
|             data of the left half and right half of the
 | |
|             64-bit block.
 | |
| 
 | |
|         def initCTR(self):
 | |
|             Initializes CTR engine for encryption or decryption.
 | |
| 
 | |
|         def encryptCTR(self, data):
 | |
|             Encrypts an arbitrary string and returns the
 | |
|             encrypted string. The method can be called successively
 | |
|             for multiple string blocks.
 | |
| 
 | |
|         def decryptCTR(self, data):
 | |
|             Decrypts a string encrypted with encryptCTR() and
 | |
|             returns the decrypted string.
 | |
| 
 | |
|     Private members:
 | |
| 
 | |
|         def __round_func (self, xl)
 | |
|             Performs an obscuring function on the 32-bit
 | |
|             block of data 'xl', which is the left half of
 | |
|             the 64-bit block of data. Returns the 32-bit
 | |
|             result as a long integer.
 | |
| 
 | |
|     """
 | |
| 
 | |
|     # Cipher directions
 | |
|     ENCRYPT = 0
 | |
|     DECRYPT = 1
 | |
| 
 | |
|     # For the __round_func
 | |
|     modulus = long (2) ** 32
 | |
| 
 | |
|     def __init__ (self, key):
 | |
| 
 | |
|         if not key or len (key) < 8 or len (key) > 56:
 | |
|             raise RuntimeError, "Attempted to initialize Blowfish cipher with key of invalid length: %s" % len (key)
 | |
| 
 | |
|         self.p_boxes = [
 | |
|             0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
 | |
|             0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
 | |
|             0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
 | |
|             0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
 | |
|             0x9216D5D9, 0x8979FB1B
 | |
|         ]
 | |
| 
 | |
|         self.s_boxes = [
 | |
|             [
 | |
|                 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
 | |
|                 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
 | |
|                 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
 | |
|                 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
 | |
|                 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
 | |
|                 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
 | |
|                 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
 | |
|                 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
 | |
|                 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
 | |
|                 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
 | |
|                 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
 | |
|                 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
 | |
|                 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
 | |
|                 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
 | |
|                 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
 | |
|                 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
 | |
|                 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
 | |
|                 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
 | |
|                 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
 | |
|                 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
 | |
|                 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
 | |
|                 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
 | |
|                 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
 | |
|                 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
 | |
|                 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
 | |
|                 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
 | |
|                 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
 | |
|                 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
 | |
|                 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
 | |
|                 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
 | |
|                 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
 | |
|                 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
 | |
|                 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
 | |
|                 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
 | |
|                 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
 | |
|                 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
 | |
|                 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
 | |
|                 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
 | |
|                 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
 | |
|                 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
 | |
|                 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
 | |
|                 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
 | |
|                 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
 | |
|                 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
 | |
|                 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
 | |
|                 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
 | |
|                 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
 | |
|                 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
 | |
|                 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
 | |
|                 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
 | |
|                 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
 | |
|                 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
 | |
|                 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
 | |
|                 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
 | |
|                 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
 | |
|                 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
 | |
|                 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
 | |
|                 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
 | |
|                 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
 | |
|                 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
 | |
|                 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
 | |
|                 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
 | |
|                 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
 | |
|                 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
 | |
|             ],
 | |
|             [
 | |
|                 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
 | |
|                 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
 | |
|                 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
 | |
|                 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
 | |
|                 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
 | |
|                 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
 | |
|                 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
 | |
|                 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
 | |
|                 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
 | |
|                 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
 | |
|                 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
 | |
|                 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
 | |
|                 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
 | |
|                 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
 | |
|                 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
 | |
|                 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
 | |
|                 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
 | |
|                 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
 | |
|                 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
 | |
|                 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
 | |
|                 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
 | |
|                 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
 | |
|                 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
 | |
|                 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
 | |
|                 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
 | |
|                 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
 | |
|                 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
 | |
|                 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
 | |
|                 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
 | |
|                 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
 | |
|                 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
 | |
|                 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
 | |
|                 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
 | |
|                 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
 | |
|                 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
 | |
|                 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
 | |
|                 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
 | |
|                 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
 | |
|                 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
 | |
|                 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
 | |
|                 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
 | |
|                 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
 | |
|                 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
 | |
|                 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
 | |
|                 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
 | |
|                 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
 | |
|                 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
 | |
|                 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
 | |
|                 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
 | |
|                 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
 | |
|                 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
 | |
|                 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
 | |
|                 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
 | |
|                 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
 | |
|                 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
 | |
|                 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
 | |
|                 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
 | |
|                 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
 | |
|                 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
 | |
|                 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
 | |
|                 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
 | |
|                 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
 | |
|                 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
 | |
|                 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
 | |
|             ],
 | |
|             [
 | |
|                 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
 | |
|                 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
 | |
|                 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
 | |
|                 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
 | |
|                 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
 | |
|                 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
 | |
|                 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
 | |
|                 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
 | |
|                 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
 | |
|                 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
 | |
|                 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
 | |
|                 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
 | |
|                 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
 | |
|                 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
 | |
|                 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
 | |
|                 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
 | |
|                 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
 | |
|                 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
 | |
|                 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
 | |
|                 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
 | |
|                 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
 | |
|                 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
 | |
|                 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
 | |
|                 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
 | |
|                 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
 | |
|                 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
 | |
|                 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
 | |
|                 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
 | |
|                 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
 | |
|                 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
 | |
|                 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
 | |
|                 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
 | |
|                 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
 | |
|                 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
 | |
|                 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
 | |
|                 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
 | |
|                 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
 | |
|                 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
 | |
|                 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
 | |
|                 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
 | |
|                 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
 | |
|                 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
 | |
|                 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
 | |
|                 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
 | |
|                 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
 | |
|                 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
 | |
|                 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
 | |
|                 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
 | |
|                 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
 | |
|                 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
 | |
|                 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
 | |
|                 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
 | |
|                 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
 | |
|                 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
 | |
|                 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
 | |
|                 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
 | |
|                 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
 | |
|                 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
 | |
|                 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
 | |
|                 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
 | |
|                 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
 | |
|                 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
 | |
|                 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
 | |
|                 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
 | |
|             ],
 | |
|             [
 | |
|                 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
 | |
|                 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
 | |
|                 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
 | |
|                 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
 | |
|                 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
 | |
|                 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
 | |
|                 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
 | |
|                 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
 | |
|                 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
 | |
|                 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
 | |
|                 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
 | |
|                 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
 | |
|                 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
 | |
|                 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
 | |
|                 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
 | |
|                 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
 | |
|                 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
 | |
|                 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
 | |
|                 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
 | |
|                 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
 | |
|                 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
 | |
|                 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
 | |
|                 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
 | |
|                 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
 | |
|                 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
 | |
|                 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
 | |
|                 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
 | |
|                 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
 | |
|                 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
 | |
|                 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
 | |
|                 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
 | |
|                 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
 | |
|                 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
 | |
|                 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
 | |
|                 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
 | |
|                 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
 | |
|                 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
 | |
|                 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
 | |
|                 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
 | |
|                 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
 | |
|                 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
 | |
|                 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
 | |
|                 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
 | |
|                 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
 | |
|                 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
 | |
|                 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
 | |
|                 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
 | |
|                 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
 | |
|                 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
 | |
|                 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
 | |
|                 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
 | |
|                 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
 | |
|                 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
 | |
|                 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
 | |
|                 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
 | |
|                 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
 | |
|                 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
 | |
|                 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
 | |
|                 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
 | |
|                 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
 | |
|                 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
 | |
|                 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
 | |
|                 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
 | |
|                 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
 | |
|             ]
 | |
|         ]
 | |
| 
 | |
|         # Cycle through the p-boxes and round-robin XOR the
 | |
|         # key with the p-boxes
 | |
|         key_len = len (key)
 | |
|         index = 0
 | |
|         for i in range (len (self.p_boxes)):
 | |
|             val = (ord (key[index % key_len]) << 24) + \
 | |
|                   (ord (key[(index + 1) % key_len]) << 16) + \
 | |
|                   (ord (key[(index + 2) % key_len]) << 8) + \
 | |
|                    ord (key[(index + 3) % key_len])
 | |
|             self.p_boxes[i] = self.p_boxes[i] ^ val
 | |
|             index = index + 4
 | |
| 
 | |
|         # For the chaining process
 | |
|         l, r = 0, 0
 | |
| 
 | |
|         # Begin chain replacing the p-boxes
 | |
|         for i in range (0, len (self.p_boxes), 2):
 | |
|             l, r = self.cipher (l, r, self.ENCRYPT)
 | |
|             self.p_boxes[i] = l
 | |
|             self.p_boxes[i + 1] = r
 | |
| 
 | |
|         # Chain replace the s-boxes
 | |
|         for i in range (len (self.s_boxes)):
 | |
|             for j in range (0, len (self.s_boxes[i]), 2):
 | |
|                 l, r = self.cipher (l, r, self.ENCRYPT)
 | |
|                 self.s_boxes[i][j] = l
 | |
|                 self.s_boxes[i][j + 1] = r
 | |
| 
 | |
|         self.initCTR()
 | |
| 
 | |
| 
 | |
|     def cipher (self, xl, xr, direction):
 | |
|         """Encryption primitive"""
 | |
|         if direction == self.ENCRYPT:
 | |
|             for i in range (16):
 | |
|                 xl = xl ^ self.p_boxes[i]
 | |
|                 xr = self.__round_func (xl) ^ xr
 | |
|                 xl, xr = xr, xl
 | |
|             xl, xr = xr, xl
 | |
|             xr = xr ^ self.p_boxes[16]
 | |
|             xl = xl ^ self.p_boxes[17]
 | |
|         else:
 | |
|             for i in range (17, 1, -1):
 | |
|                 xl = xl ^ self.p_boxes[i]
 | |
|                 xr = self.__round_func (xl) ^ xr
 | |
|                 xl, xr = xr, xl
 | |
|             xl, xr = xr, xl
 | |
|             xr = xr ^ self.p_boxes[1]
 | |
|             xl = xl ^ self.p_boxes[0]
 | |
|         return xl, xr
 | |
| 
 | |
| 
 | |
|     def __round_func (self, xl):
 | |
|         a = (xl & 0xFF000000) >> 24
 | |
|         b = (xl & 0x00FF0000) >> 16
 | |
|         c = (xl & 0x0000FF00) >> 8
 | |
|         d = xl & 0x000000FF
 | |
| 
 | |
|         # Perform all ops as longs then and out the last 32-bits to
 | |
|         # obtain the integer
 | |
|         f = (long (self.s_boxes[0][a]) + long (self.s_boxes[1][b])) % self.modulus
 | |
|         f = f ^ long (self.s_boxes[2][c])
 | |
|         f = f + long (self.s_boxes[3][d])
 | |
|         f = (f % self.modulus) & 0xFFFFFFFF
 | |
| 
 | |
|         return f
 | |
| 
 | |
| 
 | |
|     def encrypt (self, data):
 | |
|         if not len (data) == 8:
 | |
|             raise RuntimeError, "Attempted to encrypt data of invalid block length: %s" % len(data)
 | |
| 
 | |
|         # Use big endianess since that's what everyone else uses
 | |
|         xl = ord (data[3]) | (ord (data[2]) << 8) | (ord (data[1]) << 16) | (ord (data[0]) << 24)
 | |
|         xr = ord (data[7]) | (ord (data[6]) << 8) | (ord (data[5]) << 16) | (ord (data[4]) << 24)
 | |
| 
 | |
|         cl, cr = self.cipher (xl, xr, self.ENCRYPT)
 | |
|         chars = ''.join ([
 | |
|             chr ((cl >> 24) & 0xFF), chr ((cl >> 16) & 0xFF), chr ((cl >> 8) & 0xFF), chr (cl & 0xFF),
 | |
|             chr ((cr >> 24) & 0xFF), chr ((cr >> 16) & 0xFF), chr ((cr >> 8) & 0xFF), chr (cr & 0xFF)
 | |
|         ])
 | |
|         return chars
 | |
| 
 | |
| 
 | |
|     def decrypt (self, data):
 | |
|         if not len (data) == 8:
 | |
|             raise RuntimeError, "Attempted to encrypt data of invalid block length: %s" % len(data)
 | |
| 
 | |
|         # Use big endianess since that's what everyone else uses
 | |
|         cl = ord (data[3]) | (ord (data[2]) << 8) | (ord (data[1]) << 16) | (ord (data[0]) << 24)
 | |
|         cr = ord (data[7]) | (ord (data[6]) << 8) | (ord (data[5]) << 16) | (ord (data[4]) << 24)
 | |
| 
 | |
|         xl, xr = self.cipher (cl, cr, self.DECRYPT)
 | |
|         chars = ''.join ([
 | |
|             chr ((xl >> 24) & 0xFF), chr ((xl >> 16) & 0xFF), chr ((xl >> 8) & 0xFF), chr (xl & 0xFF),
 | |
|             chr ((xr >> 24) & 0xFF), chr ((xr >> 16) & 0xFF), chr ((xr >> 8) & 0xFF), chr (xr & 0xFF)
 | |
|         ])
 | |
|         return chars
 | |
| 
 | |
| 
 | |
|     # ==== CBC Mode ====
 | |
|     def initCBC(self, iv=0):
 | |
|         """Initializes CBC mode of the cypher"""
 | |
|         assert struct.calcsize("Q") == self.block_size()
 | |
|         self.cbc_iv = struct.pack("Q", iv)
 | |
| 
 | |
| 
 | |
|     def encryptCBC(self, data):
 | |
|         """
 | |
|         Encrypts a buffer of data using CBC mode. Multiple successive buffers
 | |
|         (belonging to the same logical stream of buffers) can be encrypted
 | |
|         with this method one after the other without any intermediate work.
 | |
|         Each buffer must be a multiple of 8-octets (64-bits) in length.
 | |
|         """
 | |
|         if type(data) != types.StringType:
 | |
|             raise RuntimeError, "Can only work on 8-bit strings"
 | |
|         if (len(data) % 8) != 0:
 | |
|             raise RuntimeError, "Can only work with data in 64-bit multiples in CBC mode"
 | |
| 
 | |
|         xor = lambda t: ord(t[0]) ^ ord(t[1])
 | |
|         result = ''
 | |
|         block_size = self.block_size()
 | |
|         for i in range(0, len(data), block_size):
 | |
|             p_block = data[i:i+block_size]
 | |
|             pair = zip(p_block, self.cbc_iv)
 | |
|             j_block = ''.join(map(chr, map(xor, pair)))
 | |
|             c_block = self.encrypt(j_block)
 | |
|             result += c_block
 | |
|             self.cbc_iv = c_block
 | |
|         return result
 | |
| 
 | |
| 
 | |
|     def decryptCBC(self, data):
 | |
|         if type(data) != types.StringType:
 | |
|             raise RuntimeError, "Can only work on 8-bit strings"
 | |
|         if (len(data) % 8) != 0:
 | |
|             raise RuntimeError, "Can only work with data in 64-bit multiples in CBC mode"
 | |
| 
 | |
|         xor = lambda t: ord(t[0]) ^ ord(t[1])
 | |
|         result = ''
 | |
|         block_size = self.block_size()
 | |
|         for i in range(0, len(data), block_size):
 | |
|             c_block = data[i:i+block_size]
 | |
|             j_block = self.decrypt(c_block)
 | |
|             pair = zip(j_block, self.cbc_iv)
 | |
|             p_block = ''.join(map(chr, map(xor, pair)))
 | |
|             result += p_block
 | |
|             self.cbc_iv = c_block
 | |
|         return result
 | |
| 
 | |
| 
 | |
|     # ==== CTR Mode ====
 | |
|     def initCTR(self, iv=0):
 | |
|         """Initializes CTR mode of the cypher"""
 | |
|         assert struct.calcsize("Q") == self.block_size()
 | |
|         self.ctr_iv = iv
 | |
|         self._calcCTRBUF()
 | |
| 
 | |
| 
 | |
|     def _calcCTRBUF(self):
 | |
|         """Calculates one block of CTR keystream"""
 | |
|         self.ctr_cks = self.encrypt(struct.pack("Q", self.ctr_iv)) # keystream block
 | |
|         self.ctr_iv += 1
 | |
|         self.ctr_pos = 0
 | |
| 
 | |
| 
 | |
|     def _nextCTRByte(self):
 | |
|         """Returns one byte of CTR keystream"""
 | |
|         b = ord(self.ctr_cks[self.ctr_pos])
 | |
|         self.ctr_pos += 1
 | |
|         if self.ctr_pos >= len(self.ctr_cks):
 | |
|             self._calcCTRBUF()
 | |
|         return b
 | |
| 
 | |
| 
 | |
|     def encryptCTR(self, data):
 | |
|         """
 | |
|         Encrypts a buffer of data with CTR mode. Multiple successive buffers
 | |
|         (belonging to the same logical stream of buffers) can be encrypted
 | |
|         with this method one after the other without any intermediate work.
 | |
|         """
 | |
|         if type(data) != types.StringType:
 | |
|             raise RuntimeException, "Can only work on 8-bit strings"
 | |
|         result = []
 | |
|         for ch in data:
 | |
|             result.append(chr(ord(ch) ^ self._nextCTRByte()))
 | |
|         return "".join(result)
 | |
| 
 | |
| 
 | |
|     def decryptCTR(self, data):
 | |
|         return self.encryptCTR(data)
 | |
| 
 | |
| 
 | |
|     def block_size(self):
 | |
|         return 8
 | |
| 
 | |
| 
 | |
|     def key_length(self):
 | |
|         return 56
 | |
| 
 | |
| 
 | |
|     def key_bits(self):
 | |
|         return 56 * 8
 | |
| 
 | |
|     @staticmethod
 | |
|     def testVectors():
 | |
|         import binascii
 | |
|         # for more vectors see http://www.schneier.com/code/vectors.txt
 | |
|         vectors = (
 | |
|             ('0000000000000000',        '0000000000000000',        '4EF997456198DD78'),
 | |
|             ('FFFFFFFFFFFFFFFF',        'FFFFFFFFFFFFFFFF',        '51866FD5B85ECB8A'),
 | |
|             ('3000000000000000',        '1000000000000001',        '7D856F9A613063F2'),
 | |
|             ('1111111111111111',        '1111111111111111',        '2466DD878B963C9D'),
 | |
|             ('49E95D6D4CA229BF',        '02FE55778117F12A',        'CF9C5D7A4986ADB5'),
 | |
|             ('E0FEE0FEF1FEF1FE',        '0123456789ABCDEF',        'C39E072D9FAC631D'),
 | |
|             ('07A7137045DA2A16',        '3BDD119049372802',        '2EEDDA93FFD39C79'),
 | |
|         )
 | |
|         ok = True
 | |
|         for v in vectors:
 | |
|             c = Blowfish(binascii.a2b_hex(v[0]))
 | |
|             e = binascii.b2a_hex(c.encrypt(binascii.a2b_hex(v[1]))).upper()
 | |
|             if e != v[2]:
 | |
|                 print "VECTOR TEST FAIL: expecting %s, got %s" % (repr(v), e)
 | |
|                 ok = False
 | |
|         return ok
 | |
| 
 | |
| 
 | |
| class oceanbase(object):
 | |
|     instant_key_list = [
 | |
|     # mergeserver
 | |
|     'ms_memory_limit', 'ms_memory_total', 'ms_memory_parser',
 | |
|     'ms_memory_transformer', 'ms_memory_ps_plan', 'ms_memory_rpc_request',
 | |
|     'ms_memory_sql_array', 'ms_memory_expression', 'ms_memory_row_store',
 | |
|     'ms_memory_session', 'ps_count',
 | |
|     # chunkserver
 | |
|     'serving_version', 'old_ver_tablets_num', 'old_ver_merged_tablets_num',
 | |
|     'new_ver_tablets_num', 'new_ver_tablets_num', 'memory_used_default',
 | |
|     'memory_used_network', 'memory_used_thread_buffer', 'memory_used_tablet',
 | |
|     'memory_used_bi_cache', 'memory_used_block_cache',
 | |
|     'memory_used_bi_cache_unserving', 'memory_used_block_cache_unserving',
 | |
|     'memory_used_join_cache', 'memory_used_sstable_row_cache',
 | |
|     'memory_used_merge_buffer', 'memory_used_merge_split_buffer',
 | |
|     # updateserver
 | |
|     'memory_total', 'memory_limit', 'memtable_total', 'memtable_used',
 | |
|     'total_rows', 'active_memtable_limit', 'active_memtable_total',
 | |
|     'active_memtable_used', 'active_total_rows', 'frozen_memtable_limit',
 | |
|     'frozen_memtable_total', 'frozen_memtable_used', 'frozen_total_rows',
 | |
|     'low_prio_queued_count', 'normal_prio_queued_count', 'high_prio_queued_count',
 | |
|     'hotspot_queued_count',
 | |
|     # machine stat
 | |
|     'load1', 'load5', 'load15', 'MemTotal', 'MemFree',
 | |
|     # mock
 | |
|     'timestamp',
 | |
|     'tenant','memstore limit','total memstore used','active sessions','cpu usage'
 | |
|     ]
 | |
| 
 | |
|     delta_key_list = [
 | |
|     # sql
 | |
|     'active memstore used',
 | |
|     'active sessions',
 | |
|     'block cache hit',
 | |
|     'block cache miss',
 | |
|     'block index cache hit',
 | |
|     'block index cache miss',
 | |
|     'bloom filter cache hit',
 | |
|     'bloom filter cache miss',
 | |
|     'bloom filter filts',
 | |
|     'bloom filter passes',
 | |
|     'io read bytes',
 | |
|     'io read count',
 | |
|     'io write bytes',
 | |
|     'io write count',
 | |
|     'location cache hit',
 | |
|     'location cache miss',
 | |
|     'row cache hit',
 | |
|     'row cache miss',
 | |
|     'rpc deliver fail',
 | |
|     'rpc net delay',
 | |
|     'rpc net frame delay',
 | |
|     'rpc packet in',
 | |
|     'sql delete count',
 | |
|     'sql delete time',
 | |
|     'sql distributed count',
 | |
|     'sql insert count',
 | |
|     'sql insert time',
 | |
|     'sql local count',
 | |
|     'sql remote count',
 | |
|     'sql replace count',
 | |
|     'sql replace time',
 | |
|     'sql select count',
 | |
|     'sql select time',
 | |
|     'sql update count',
 | |
|     'sql update time',
 | |
|     'trans commit count',
 | |
|     'trans commit time',
 | |
|     'trans rollback count',
 | |
|     'time_delta'
 | |
|     ]
 | |
| 
 | |
|     sum_key_list = [
 | |
|     'tenant',
 | |
|     'total memstore used',
 | |
|     'memstore limit',
 | |
|     'major freeze trigger',
 | |
|     'timestamp'
 | |
|     ]
 | |
| 
 | |
|     app_info = {'username':None, 'password':None}
 | |
| 
 | |
|     def __init__(self, dataid=None):
 | |
|         self.__q = {}
 | |
|         self.__stop = True
 | |
|         self.__machine_stat = {}
 | |
|         self.__host = Options.host
 | |
|         self.__port = Options.port
 | |
|         self.update_dataid(dataid)
 | |
|         self.__cur_cluster_svrs = None
 | |
|         self.__cur_tenant_id = 1
 | |
|         self.tenant = []
 | |
| 
 | |
|     def update_dataid(self, dataid):
 | |
|         if dataid:
 | |
|             self.app_info = ObConfigHelper().get_app_info(dataid)
 | |
| 
 | |
|     def dosql(self, sql, host=None, port=None, database=None):
 | |
| 	cmd = "mysql -V"        
 | |
| 	p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
 | |
|         err = p.wait()
 | |
|         if err:
 | |
|             raise Exception('please install mysql', cmd)	
 | |
| 
 | |
| 	if host is None:
 | |
|             host = self.__host
 | |
|         if port is None:
 | |
|             port = self.__port
 | |
|         if host is None:
 | |
|             host = Options.host
 | |
|         if port is None:
 | |
|             port = Options.port
 | |
|         if database is None:
 | |
|             database = Options.database
 | |
|         username = Options.user or self.app_info['username'] or Global.DEFAULT_USER
 | |
|         password = Options.password or self.app_info['password'] or Global.DEFAULT_PASS
 | |
| 
 | |
|         if password == "":
 | |
|             mysql = "mysql --connect_timeout=10 -c -s -N -A -h%s -P%d -u%s  %s" % (host, port, username, database)
 | |
|         else:
 | |
|             mysql = "mysql --connect_timeout=10 -c -s -N -A -h%s -P%d -u%s -p'%s'  %s" % (host, port, username, password, database)
 | |
| 
 | |
|         cmd = "%s -e \"%s\"" % (mysql, sql)
 | |
|         DEBUG(self.dosql, "oceanbase.dosql : ", cmd)
 | |
| 
 | |
|         p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
 | |
|         output = p.communicate()[0]
 | |
|         err = p.wait()
 | |
|         if err:
 | |
|             raise Exception('popen Fail', cmd)
 | |
|         return output
 | |
| 
 | |
|     def show_sql_result(self, sql, host=None, port=None):
 | |
|         if host is None:
 | |
|             host = self.__host
 | |
|         if port is None:
 | |
|             port = self.__port
 | |
|         if host is None:
 | |
|             host = Options.host
 | |
|         if port is None:
 | |
|             port = Options.port
 | |
|         if database is None:
 | |
|             database = Options.database
 | |
|         username = Options.user or self.app_info['username'] or Global.DEFAULT_USER
 | |
|         password = Options.password or self.app_info['password'] or Global.DEFAULT_PASS
 | |
| 
 | |
|         if password == "":
 | |
|             mysql = "mysql --connect_timeout=10 -c -s -N -A -h%s -P%d -u%s  %s" % (host, port, username, database)
 | |
|         else:
 | |
|             mysql = "mysql --connect_timeout=10 -c -s -N -A -h%s -P%d -u%s -p'%s'  %s" % (host, port, username, password, database)
 | |
| 
 | |
|         cmd = "%s -e \"%s\" | less" % (mysql, sql)
 | |
|         curses.endwin()
 | |
|         call("clear")
 | |
| 
 | |
|         DEBUG(self.dosql, "oceanbase.show_sql_result : ", cmd)
 | |
| 
 | |
|         os.system(cmd)
 | |
|         curses.doupdate()
 | |
| 
 | |
|     def mysql(self, host=None, port=None):
 | |
|         if host is None:
 | |
|             host = self.__host
 | |
|         if port is None:
 | |
|             port = self.__port
 | |
|         if host is None:
 | |
|             host = Options.host
 | |
|         if port is None:
 | |
|             port = Options.port
 | |
|         if database is None:
 | |
|             database = Options.database
 | |
|         username = Options.user or self.app_info['username'] or Global.DEFAULT_USER
 | |
|         password = Options.password or self.app_info['password'] or Global.DEFAULT_PASS
 | |
|         cmd = "mysql --connect_timeout=10 -c -A -h%s -P%d -u%s -p'%s' %s" % (host, port, username, password, database)
 | |
|         environ['MYSQL_PS1'] = "(\u@\h) [%s]> " % self.app
 | |
|         call('clear')
 | |
|         try:
 | |
|             call(cmd, shell=True)
 | |
|         except KeyboardInterrupt:
 | |
|             pass
 | |
|         call('clear')
 | |
| 
 | |
|     def ssh(self, host):
 | |
|         cmd = "ssh -o StrictHostKeyChecking=no %s" % host
 | |
|         call('clear')
 | |
|         try:
 | |
|             call(cmd, shell=True)
 | |
|         except KeyboardInterrupt:
 | |
|             pass
 | |
|         call('clear')
 | |
| 
 | |
|     def test_alive(self, fatal=True, do_false=None, do_true=None, host=None, port=None):
 | |
|         if host is None:
 | |
|             host = Options.host
 | |
|         if port is None:
 | |
|             port = Options.port
 | |
|         try:
 | |
|             oceanbase.dosql('select 1', host=host, port=port)
 | |
|             if do_true is not None:
 | |
|                 do_true("Check oceanbase alive successfully! [%s:%d]" % (host, port))
 | |
|         except Exception:
 | |
|             if do_false is not None:
 | |
|                 do_false("Can't connect oceanbase, plz check options!\n"
 | |
|                          "Options: [IP:%s] [PORT:%d] [USER:%s] [PASS:%s]"
 | |
|                          % (host, port, Options.user, Options.password))
 | |
|             if fatal:
 | |
|                 exit(1)
 | |
|             else:
 | |
|                 return False
 | |
|         return True
 | |
| 
 | |
|     def __check_schema(self):
 | |
|         stat_ids = "stat_id in (10000,10004,10005,10006,30007,30008,30009,"\
 | |
|                 "40000,40001,40002,40003,40004,40005,40006,40007,40008,40009,40010,40011,40012,40013,"\
 | |
|                 "50000,50001,50002,50003,50004,50005,50006,50007,50008,50009,50010,50011,"\
 | |
|                 "60000,60002,60003,60005,130000,130001,130002,130004,"\
 | |
|                 "190001,190005,190405,190401,190205,190201,190105,190101,190305,190301,190505,190501,190903,190003,190403,190203,"\
 | |
|                 "190103,190303,190503,190901,190004,190404,190204,190104,190304,190504,190902"\
 | |
|                 ") "
 | |
| 
 | |
|         sql = """ select current_time(), stat.con_id, stat.svr_ip, stat.svr_port, stat.name, stat.value from gv\$sysstat stat where stat.class IN (1,4,8,16,32,4096) and con_id = %s and (%s) """  % (  str(self.get_current_tenant()) , stat_ids)
 | |
| 
 | |
|         DEBUG(self.__check_schema, "oceanbase.check schema sql : ", sql)
 | |
| 
 | |
|         return sql
 | |
| 
 | |
|     def __get_cpu_usage(self):
 | |
|     	#sql = """SELECT t1.tenant_id,t2.zone, t1.svr_ip,t1.svr_port , round(cpu_quota_used/t4.max_cpu, 3) cpu_usage FROM __all_tenant_resource_usage t1 JOIN  __all_server t2 ON (t1.svr_ip=t2.svr_ip and t1.svr_port=t2.svr_port) JOIN __all_resource_pool t3 ON (t1.tenant_id=t3.tenant_id) JOIN __all_unit_config t4 ON (t3.unit_config_id=t4.unit_config_id) WHERE report_time > date_sub(now(), INTERVAL 30 SECOND) AND t1.tenant_id IN (%s)  ORDER BY t1.tenant_id, t2.zone, t1.svr_ip, t1.svr_port; """    % (str(self.get_current_tenant()))
 | |
|         sql = """SELECT t1.con_id tenant_id,t2.zone, t1.svr_ip,t1.svr_port , round(t1.value/(100*t4.max_cpu), 3) cpu_usage FROM gv\$sysstat t1 JOIN  __all_server t2 ON (t1.svr_ip=t2.svr_ip and t1.svr_port=t2.svr_port) JOIN __all_resource_pool t3 ON (t1.con_id=t3.tenant_id) JOIN __all_unit_config t4 ON (t3.unit_config_id=t4.unit_config_id) WHERE  t1.con_id IN (%s) and t1.stat_id=140006  ORDER BY t1.con_id, t2.zone, t1.svr_ip, t1.svr_port; """    % (str(self.get_current_tenant()))
 | |
|     	res = self.dosql(sql)
 | |
| 
 | |
|         DEBUG(self.__get_cpu_usage, "oceanbase.get cpu usage res : ", res)
 | |
|     	r = dict()
 | |
| 
 | |
|     	for one in res.split("\n")[:-1]:
 | |
|             a = one.split("\t")
 | |
|             tnt = a[0]
 | |
|             #ip = a[2]
 | |
|             #port = a[3]
 | |
|             ip = '%s:%s' % (a[2],a[3])
 | |
|             name = "cpu usage"
 | |
|             value = float(a[4])
 | |
| 
 | |
|             if tnt not in r:
 | |
|                 r[tnt] = dict()
 | |
|             if ip not in r[tnt]:
 | |
|                 r[tnt][ip] = dict()
 | |
|             r[tnt][ip][name] = value
 | |
| 
 | |
|         DEBUG(self.__get_cpu_usage, "oceanbase.get cpu usage r: ", r)
 | |
| 
 | |
|         return r;
 | |
| 
 | |
| 
 | |
|     def __get_all_stat(self):
 | |
|         sql = self.__check_schema()
 | |
|         res = self.dosql(sql)
 | |
|         r = self.__get_cpu_usage()
 | |
| 
 | |
|         time = str(datetime.now())
 | |
|         now = datetime.strptime(time, '%Y-%m-%d %H:%M:%S.%f')
 | |
|         if not self.__using_server_time():
 | |
|             time = str(datetime.now())
 | |
|         for one in res.split("\n")[:-1]:
 | |
|             a = one.split("\t")
 | |
|             if self.__using_server_time():
 | |
|                 time = a[0]
 | |
|             now = datetime.strptime(time, '%Y-%m-%d %H:%M:%S.%f')
 | |
|             tnt = a[1]
 | |
|             #ip = a[2]
 | |
|             #port = a[3]
 | |
|             ip = '%s:%s' % (a[2],a[3])
 | |
|             name = a[4]
 | |
|             value = int(a[5])
 | |
| 
 | |
|             if tnt not in r:
 | |
|                 r[tnt] = dict()
 | |
|             if ip not in r[tnt]:
 | |
|                 r[tnt][ip] = dict()
 | |
|             r[tnt][ip][name] = value
 | |
| 
 | |
|         r['time_delta'] = timedelta()
 | |
|         r['timestamp'] = now
 | |
|         r['tenant'] = int(a[1])
 | |
| 
 | |
|         DEBUG(self.__get_all_stat, "oceanbase.__get_all_stat returned: ", r)
 | |
|         DEBUG(self.__get_all_stat, "oceanbase.__get_all_stat finished with r['tenant']=%d" % r['tenant'], "")
 | |
| 
 | |
|         return r
 | |
| 
 | |
|     def __get_stat(self, stat):
 | |
|         r = ''
 | |
|         for k in stat.keys():
 | |
| 
 | |
|             if type(stat[k]) == dict:
 | |
|                 r = r + self.__get_stat(stat[k]) + ","
 | |
|             else:
 | |
|                 r = r + "'" +  k + "':" + str(stat[k]) + ","
 | |
| 
 | |
|         return r.rstrip(',')
 | |
| 
 | |
|     def __print_stat(self, stat):
 | |
|         now = datetime.now()
 | |
| 
 | |
|         s = now.strftime("%Y%m%d%H%M%S")
 | |
| 
 | |
|         if f_data_log != '':
 | |
|             s = s + ',' + self.__get_stat(stat)
 | |
|             f = open(f_data_log, "a")
 | |
|             f.write(s+"\n")
 | |
|             f.close()
 | |
| 
 | |
| 
 | |
|     def sub_stat(self, now, prev):
 | |
| 
 | |
|         r = self.__sub_stat(now, prev)
 | |
|         return r
 | |
| 
 | |
|     def __sub_stat(self, now, prev):
 | |
|         r = {}
 | |
|         for k in now.keys():
 | |
| 
 | |
|             if k in self.instant_key_list:
 | |
|                 r[k] = now[k]
 | |
|             elif k == 'time_delta':
 | |
|                 r[k] = now['timestamp'] - prev['timestamp']
 | |
|             else:
 | |
|                 if type(now[k]) == dict:
 | |
|                     r.update({k: self.__sub_stat(now[k], prev[k])})
 | |
|                 elif type(now[k]) == int:
 | |
|                     r[k] = now[k] - prev[k]
 | |
|                 elif type(now[k]) == float:
 | |
|                 	r[k] = round(now[k] - prev[k],2)
 | |
|                 else:
 | |
|                     DEBUG(self.__sub_stat, "unknown type of now['%s'] : " % k, type(now[k]))
 | |
|                     pass
 | |
| 
 | |
|         self.__print_stat(r)
 | |
| 
 | |
|         return r
 | |
| 
 | |
|     def __init_stat(self, stat):
 | |
|         r = stat.copy()
 | |
| 
 | |
|         for k in r.keys():
 | |
|             if k == 'tenant':
 | |
|                 r[k] = stat[k]
 | |
|             elif k == 'time_delta':
 | |
|                 r[k] = timedelta()
 | |
|             else:
 | |
|                 if type(r[k]) == dict:
 | |
|                     r[k] = self.__init_stat(r[k])
 | |
|                 elif type(r[k]) == type(datetime.min):
 | |
|                     r[k] = datetime.strptime('2016-11-11 00:00:00', "%Y-%m-%d %H:%M:%S")
 | |
|                 else:
 | |
|                     if k in ( 'tenant'):
 | |
|                         stat_sum[k] = 1
 | |
|                     elif type(r[k]) == float:
 | |
|                         r[k] = 0.0
 | |
|                     else:
 | |
|                         r[k] = 0
 | |
| 
 | |
|         return r;
 | |
| 
 | |
|     def __op_stat(self, stat_sum, stat_new, op_type):
 | |
|         r = stat_sum.copy()
 | |
| 
 | |
|         for k in stat_sum.keys():
 | |
|             #if k == 'time_delta':
 | |
|                 #DEBUG(self.__op_stat, "oceanbase.__op_stat 'time_delta' : ",  stat_sum[k])
 | |
| 
 | |
|             if type(stat_sum[k]) == dict:
 | |
|                 r[k] = self.__op_stat(stat_sum[k], stat_new[k], op_type)
 | |
|             elif k == 'timestamp':
 | |
|                 r[k] = datetime.strptime('2016-11-11 00:00:00', "%Y-%m-%d %H:%M:%S")
 | |
|             elif k in self.delta_key_list:
 | |
|                 if op_type == 'add':
 | |
|                     r[k] = stat_sum[k] + stat_new[k]
 | |
|                 elif op_type == 'sub':
 | |
|                     r[k] = stat_sum[k] - stat_new[k]
 | |
|             else:
 | |
|                 r[k] = stat_new[k]
 | |
| 
 | |
|             #if k == 'time_delta':
 | |
|                 #DEBUG(self.__op_stat, "oceanbase.__op_stat 'time_delta' : ",  stat_sum[k])
 | |
| 
 | |
| 
 | |
|         return r;
 | |
| 
 | |
| 
 | |
| 
 | |
|     def __update_oceanbase_stat_runner(self):
 | |
|         DEBUG(self.__update_oceanbase_stat_runner, "oceanbase.__update_oceanbase_stat_runner : ",  "")
 | |
| 
 | |
|         q = self.__q
 | |
|         prev = self.__get_all_stat()
 | |
| 
 | |
| 
 | |
|         while not self.__stop:
 | |
| 
 | |
| 
 | |
|             sleep(Options.interval)
 | |
|             if self.__stop:
 | |
|                 break
 | |
|             try:
 | |
|                 cur = self.__get_all_stat()
 | |
|             except Exception:
 | |
|                 continue
 | |
|             if str(oceanbase.get_current_tenant()) not in cur:
 | |
|                 # tid has changed before result returned, ignore it.
 | |
|                 prev = self.__get_all_stat()
 | |
|                 continue
 | |
|             try:
 | |
|                 stat_new = self.__sub_stat(cur, prev)
 | |
|                 DEBUG(self.__update_oceanbase_stat_runner, "oceanbase.__update_oceanbase_stat_runner stat_new :", stat_new)
 | |
| 
 | |
| 
 | |
|                 if len(q) == 0:
 | |
|                     stat_sum = self.__init_stat(prev)
 | |
|                     stat_sum['timestamp'] = stat_new['timestamp']
 | |
|                     #stat_avg = stat_sum.copy()
 | |
| 
 | |
|                     #q.appendleft(stat_avg)
 | |
|                     q.appendleft(stat_sum)
 | |
| 
 | |
| 
 | |
|                 stat_sum = q.popleft()
 | |
|                 #q.popleft()
 | |
| 
 | |
|                 DEBUG(self.__update_oceanbase_stat_runner, "oceanbase.__update_oceanbase_stat_runner stat_sum :", stat_sum)
 | |
| 
 | |
| 
 | |
|                 q.appendleft(stat_new)
 | |
| 
 | |
|                 stat_sum = self.__op_stat(stat_sum, stat_new, 'add')
 | |
| 
 | |
|                 DEBUG(self.__update_oceanbase_stat_runner, "oceanbase.__update_oceanbase_stat_runner stat_sum :", stat_sum)
 | |
| 
 | |
|                 #DEBUG(self.__update_oceanbase_stat_runner, "oceanbase.__update_oceanbase_stat_runner stat_avg :", stat_avg)
 | |
| 
 | |
| 
 | |
|                 #stat_avg = self.__avg_stat(stat_sum, len(q) )
 | |
| 
 | |
|                 #DEBUG(self.__update_oceanbase_stat_runner, "oceanbase.__update_oceanbase_stat_runner stat_avg :", stat_avg)
 | |
| 
 | |
|                 if (len(q) > Global.MAX_LINES):
 | |
|                     r = q.pop()
 | |
|                     stat_sum = self.__op_stat(stat_sum, r, 'sub')
 | |
|                     #stat_avg = self.__avg_stat(stat_sum, len(q))
 | |
| 
 | |
|                 #q.appendleft(stat_avg)
 | |
|                 q.appendleft(stat_sum)
 | |
| 
 | |
| 
 | |
|             except Exception, e:
 | |
|                 DEBUG(self.__update_oceanbase_stat_runner, "oceanbase.__update_oceanbase_stat_runner tenant changed from %d to %d , exception" % (prev['tenant'], cur['tenant']), e)
 | |
| 
 | |
|                 q.clear()
 | |
|                 prev = cur
 | |
|                 pass
 | |
| 
 | |
|             prev = cur
 | |
| 
 | |
| 
 | |
|     def __do_ssh(self, host, cmd):
 | |
|         BUFFER_SIZE = 1 << 16
 | |
|         ssh = Popen(['ssh', '-o', 'PreferredAuthentications=publickey', '-o', 'StrictHostKeyChecking=no', host, cmd],
 | |
|                     stdout=PIPE, stderr=PIPE, preexec_fn=setsid, shell=False)
 | |
|         output = ssh.communicate()[0]
 | |
|         err = ssh.wait()
 | |
|         if err:
 | |
|             raise Exception('popen Fail', "%s: %s" % (host, cmd))
 | |
|         return output
 | |
| 
 | |
|     def __get_machine_stat(self, ip):
 | |
|         cmd = ("cat <(date +%s%N) <(cat /proc/stat | head -1 | cut -d' ' -f 3-9) "
 | |
|                "/proc/loadavg  <(cat /proc/meminfo) <(echo END_MEM) "
 | |
|                "<(cat /proc/net/dev | sed -n 3~1p) <(echo END_NET) "
 | |
|                "<(cat /proc/diskstats | grep '  8  ') <(echo END_DISK)")
 | |
|         try:
 | |
|             output = self.__do_ssh(ip, cmd)
 | |
|         except Exception:
 | |
|             return {}
 | |
| 
 | |
|         lines = output.split('\n')
 | |
| 
 | |
|         res = {}
 | |
|         res['time_delta'] = float(lines[0]) / 1000   # ms
 | |
|         lines = lines[1:]
 | |
| 
 | |
|         cpuinfo = lines[0]
 | |
|         columns = cpuinfo.split(" ")
 | |
|         res['user'] = int(columns[0])
 | |
|         res['nice'] = int(columns[1])
 | |
|         res['sys'] = int(columns[2])
 | |
|         res['idle'] = int(columns[3])
 | |
|         res['iowait'] = int(columns[4])
 | |
|         res['irq'] = int(columns[5])
 | |
|         res['softirq'] = int(columns[6])
 | |
|         res['total'] = 0
 | |
|         for c in columns:
 | |
|             res['total'] += int(c)
 | |
|         lines = lines[1:]
 | |
| 
 | |
|         loadavg = lines[0]
 | |
|         columns = loadavg.split(" ")
 | |
|         res['load1'] = columns[0]
 | |
|         res['load5'] = columns[1]
 | |
|         res['load15'] = columns[2]
 | |
|         lines = lines[1:]
 | |
| 
 | |
|         # mem
 | |
|         for line in lines:
 | |
|             if 'END_MEM' == line:
 | |
|                 break
 | |
|             kv = line.split()
 | |
|             k = kv[0][:-1]
 | |
|             v = kv[1]
 | |
|             res[k] = int(v) * 1024
 | |
|         idx = lines.index('END_MEM')
 | |
|         lines = lines[idx + 1:]
 | |
| 
 | |
|         # net
 | |
|         res['net'] = {}
 | |
|         for line in lines:
 | |
|             if 'END_NET' == line:
 | |
|                 break
 | |
|             colon = line.find(':')
 | |
|             assert colon > 0, line
 | |
|             name = line[:colon].strip()
 | |
|             res['net'][name] = {}
 | |
|             fields = line[colon+1:].strip().split()
 | |
|             res['net'][name]['bytes_recv'] = int(fields[0])
 | |
|             res['net'][name]['packets_recv'] = int(fields[1])
 | |
|             res['net'][name]['errin'] = int(fields[2])
 | |
|             res['net'][name]['dropin'] = int(fields[3])
 | |
|             res['net'][name]['bytes_sent'] = int(fields[8])
 | |
|             res['net'][name]['packets_sent'] = int(fields[9])
 | |
|             res['net'][name]['errout'] = int(fields[10])
 | |
|             res['net'][name]['dropout'] = int(fields[11])
 | |
|         idx = lines.index('END_NET')
 | |
|         lines = lines[idx + 1:]
 | |
| 
 | |
|         res['disk'] = {}
 | |
|         SECTOR_SIZE = 512
 | |
|         for line in lines:
 | |
|             # http://www.mjmwired.net/kernel/Documentation/iostats.txt
 | |
|             if 'END_DISK' == line:
 | |
|                 break
 | |
|             _, _, name, reads, _, rbytes, rtime, writes, _, wbytes, wtime = line.split()[:11]
 | |
|             res['disk'][name] = {}
 | |
|             res['disk'][name]['rbytes'] = int(rbytes) * SECTOR_SIZE
 | |
|             res['disk'][name]['wbytes'] = int(wbytes) * SECTOR_SIZE
 | |
|             res['disk'][name]['reads'] = int(reads)
 | |
|             res['disk'][name]['writes'] = int(writes)
 | |
|             res['disk'][name]['rtime'] = int(rtime)
 | |
|             res['disk'][name]['wtime'] = int(wtime)
 | |
|         return res
 | |
|         idx = lines.index('END_DISK')
 | |
|         lines = lines[idx + 1:]
 | |
| 
 | |
|     def __update_server_stat_runner(self):
 | |
|         prev = {}
 | |
|         for ip in self.ip_list:
 | |
|             prev[ip] = self.__get_machine_stat(ip)
 | |
|         while not self.__stop:
 | |
|             sleep(Options.machine_interval)
 | |
|             shuffle(self.ip_list)
 | |
|             for ip in self.ip_list:
 | |
|                 if self.__stop:
 | |
|                     break
 | |
|                 cur = self.__get_machine_stat(ip)
 | |
|                 try:
 | |
|                     result = self.__sub_stat(cur, prev[ip])
 | |
|                     self.__machine_stat.update({ip: result})
 | |
|                 except KeyError:
 | |
|                     pass
 | |
|                 prev[ip] = cur
 | |
| 
 | |
|     def __update_version(self):
 | |
|         self.version = "Unknown"
 | |
|         res = self.dosql("show variables like 'version_comment'")
 | |
|         for one in res.split("\n")[:-1]:
 | |
|             a = one.split("\t")
 | |
|             self.version = a[1]
 | |
|         self.app = oceanbase.dosql("select value from __all_sys_config_stat"
 | |
|                                      " where name='appname' limit 1;")[:-1]
 | |
| 
 | |
|     def __using_server_time(self):
 | |
|         return False
 | |
| 
 | |
|     def start(self):
 | |
|         self.__stop = False
 | |
|         self.__q = deque([])
 | |
|         self.__th = Thread(target=self.__update_oceanbase_stat_runner, args=())
 | |
|         self.__th.daemon = True
 | |
|         self.__th.start()
 | |
|         if Options.env == 'online':
 | |
|             self.__update_ip_list()
 | |
|             self.__machine_stat = {}
 | |
|             self.__svr_th = Thread(target=self.__update_server_stat_runner, args=())
 | |
|             self.__svr_th.daemon = True
 | |
|             self.__svr_th.start()
 | |
| 
 | |
|     def dump_queue(self):
 | |
|         print self.__q
 | |
| 
 | |
|     def now(self):
 | |
|         return self.__q[1]
 | |
| 
 | |
|     def stat_count(self):
 | |
|         return len(self.__q)
 | |
| 
 | |
| 
 | |
|     def latest(self, num=1):
 | |
|         return list(self.__q)[0:num]
 | |
| 
 | |
|     def machine_stat(self):
 | |
|         return self.__machine_stat
 | |
| 
 | |
|     def update_tenant_info(self):
 | |
|         DEBUG(self.update_tenant_info, "oceanbase.update_tenant_info" , "")
 | |
|         class Tenant:
 | |
|             def __init__(self, tid, name, zone_list, selected):
 | |
| 
 | |
|                 self.tenant_id = tid
 | |
|                 self.tenant_name = name
 | |
|                 self.zone_list = zone_list
 | |
|                 self.selected = selected
 | |
|                 self.svr_list = {"observer":[]}
 | |
|         res = self.dosql("select tenant_id, tenant_name, zone_list from __all_tenant")
 | |
|         self.tenant = []
 | |
|         flg = True
 | |
|         for line in res.split("\n")[0:-1]:
 | |
|             tnt = line.split("\t")
 | |
|             self.tenant.append(Tenant(tnt[0], tnt[1], tnt[2], flg))
 | |
|             flg = False
 | |
| 
 | |
| 
 | |
|         svrs = self.dosql("select server.svr_ip, server.svr_port, server.id, server.zone, server.inner_port, server.with_rootserver, server.status, pool.tenant_id, unit.migrate_from_svr_ip, unit.migrate_from_svr_port, server.zone from __all_server server join __all_unit unit on (server.svr_ip=unit.svr_ip and server.svr_port=unit.svr_port) join __all_resource_pool pool on (unit.resource_pool_id=pool.resource_pool_id) ")
 | |
|         for line in svrs.rstrip("\n").split("\n"):
 | |
|             svr = line.split("\t")
 | |
|             for tnt in self.tenant:
 | |
|                 if tnt.tenant_id == svr[7]:
 | |
|                     tnt.svr_list["observer"].append({"zone":svr[10], "ip":svr[0], "port":svr[1], "role":svr[5]})
 | |
|                     if svr[8] != '':
 | |
|                     	tnt.svr_list["observer"].append({"zone":svr[10], "ip":svr[8], "port":svr[9], "role":svr[5]})
 | |
| 
 | |
|         #self.__update_version()
 | |
|         #self.__update_ip_list()
 | |
|         self.__update_cur_cluster_info()
 | |
|         self.__update_sample()
 | |
| 
 | |
| #   def update_cluster_info(self):
 | |
| #       class Cluster:
 | |
| #           def __init__(self, id, vip, port, role):
 | |
| #               self.id = id
 | |
| #               self.vip = vip
 | |
| #               try:
 | |
| #                   self.port = int(port)
 | |
| #               except ValueError:
 | |
| #                   self.port = 0
 | |
| #               self.role = role
 | |
| #               self.selected = False
 | |
| #               self.svr_list = {'chunkserver':[], 'mergeserver':[], 'rootserver':[], 'updateserver':[]}
 | |
| 
 | |
| #       res = self.dosql('SELECT cluster_id,cluster_vip,cluster_port,cluster_role FROM __all_cluster')
 | |
| #       self.cluster = []
 | |
| #       for line in res.split("\n")[:-1]:
 | |
| #           clu = line.split("\t")
 | |
| #           self.cluster.append(Cluster(int(clu[0]), clu[1], clu[2], int(clu[3])))
 | |
| 
 | |
| #       svrs = oceanbase.dosql("select svr_type,cluster_id,svr_ip,svr_port,svr_role from __all_server")
 | |
| #       for line in svrs.rstrip("\n").split("\n"):
 | |
| #           svr = line.split("\t")
 | |
| #           for clu in self.cluster:
 | |
| #               if clu.id == int(svr[1]):
 | |
| #                   clu.svr_list[svr[0]].append({'ip': svr[2], 'port': int(svr[3]), 'role': int(svr[4])})
 | |
| 
 | |
| #       if Options.dataid:
 | |
| #           self.update_lms()
 | |
| 
 | |
| #       self.__update_version()
 | |
| #       self.__update_ip_list()
 | |
| #       self.__update_cur_cluster_info()
 | |
| #       self.__update_sample()
 | |
| 
 | |
|     def check_lms(self, say):
 | |
|         if Options.dataid is not None:
 | |
|             lms_list = self.app_info['lms_list']
 | |
|             if not lms_list or len(lms_list) <= 0:
 | |
|                 say('Get lms list fail, plz check'
 | |
|                     + ' [ dataid = %s, lms_list = %s ]' % (Options.dataid, lms_list))
 | |
|             else:
 | |
|                 for lms in lms_list:
 | |
|                     say('checking lms [%s:%s]' % lms)
 | |
|                     if oceanbase.test_alive(host=lms[0], port=lms[1], fatal=False,
 | |
|                                             do_false=say, do_true=say):
 | |
|                         self.__host = lms[0]
 | |
|                         self.__port = lms[1]
 | |
|                         #oceanbase.update_cluster_info()
 | |
|                         oceanbase.update_tenant_info()
 | |
|                         return True
 | |
|         return False
 | |
| 
 | |
|     def __update_sample(self):
 | |
|         self.sample = self.__get_all_stat()
 | |
| 
 | |
| 
 | |
|         DEBUG(self.__update_sample, "stat:" , self.sample)
 | |
| 
 | |
|     def __update_ip_list(self):
 | |
|         ip_list = []
 | |
|         ip_map = {}
 | |
|         for clu in self.tenant:
 | |
|             svr_list = clu.svr_list
 | |
|             for name in ("observer"):
 | |
|                 ip_list += [svr["ip"] for svr in svr_list[name]]
 | |
|                 for ip in [svr["ip"] for svr in svr_list[name]]:
 | |
|                     if ip in ip_map:
 | |
|                         ip_map[ip].append(name)
 | |
|                     else:
 | |
|                         ip_map[ip] = [name]
 | |
|         self.ip_list = list(set(ip_list))
 | |
|         self.ip_map = ip_map
 | |
| 
 | |
| #   def __update_ip_list(self):
 | |
| #       ip_list = []
 | |
| #       ip_map = {}
 | |
| #       for clu in self.cluster:
 | |
| #           svr_list = clu.svr_list
 | |
| #           for name in ('chunkserver', 'mergeserver', 'updateserver', 'rootserver'):
 | |
| #               ip_list += [svr['ip'] for svr in svr_list[name]]
 | |
| #               for ip in [svr['ip'] for svr in svr_list[name]]:
 | |
| #                   if ip in ip_map:
 | |
| #                       ip_map[ip].append(name)
 | |
| #                   else:
 | |
| #                       ip_map[ip] = [name]
 | |
| #       self.ip_list = list(set(ip_list))
 | |
| #       self.ip_map = ip_map
 | |
| 
 | |
|     def __update_cur_cluster_info(self):
 | |
|         for tnt in self.tenant:
 | |
| 
 | |
|             if int(self.__cur_tenant_id)== int(tnt.tenant_id) :
 | |
|                 self.__cur_cluster_svrs = tnt.svr_list
 | |
| 
 | |
|                 DEBUG(self.__update_cur_cluster_info, "oceanbase.__update_cur_cluster_info return tenant_id : %s, cluster_svrs : " % tnt.tenant_id , self.__cur_cluster_svrs)
 | |
|                 return self.__cur_cluster_svrs
 | |
| 
 | |
| 
 | |
|     def update_lms(self):
 | |
|         svrs = oceanbase.dosql("select svr_ip, svr_port from __all_server where with_rootserver = 1 limit 1")
 | |
|         for line in svrs.rstrip("\n").split("\n"):
 | |
|             svr = line.split("\t")
 | |
|             ip = svr[0]
 | |
|             try:
 | |
|                 port = int(svr[1])
 | |
|                 self.__host = svr[0]
 | |
|                 self.__port = svr[1]
 | |
|             except ValueError:
 | |
|                 return
 | |
| 
 | |
| 
 | |
|     def set_current_tenant(self, tid):
 | |
|         DEBUG(self.set_current_tenant, "oceanbase.set_current_tenant(tid='%s')" % (tid), "")
 | |
|         self.__cur_tenant_id = tid
 | |
| 
 | |
|     def get_current_tenant(self):
 | |
|         return self.__cur_tenant_id
 | |
| 
 | |
|     def get_tenant_svr(self, tid=None):
 | |
|         for tnt in self.tenant:
 | |
|             if True == tnt.selected:
 | |
|                 return tnt.svr_list
 | |
| 
 | |
|     def find_svr_list(self):
 | |
|         if not self.__cur_cluster_svrs:
 | |
|             self.__update_cur_cluster_info()
 | |
|         return self.__cur_cluster_svrs
 | |
| 
 | |
|     def stop(self):
 | |
|         self.__stop = True
 | |
| 
 | |
|     def switch_tenant(self, tid):
 | |
|         for tnt in self.tenant:
 | |
|             if tid == tnt.tenant_id:
 | |
|                 tnt.selected = True
 | |
|                 self.__q.clear()
 | |
|             else:
 | |
|                 tnt.selected = False
 | |
|                 DEBUG(self.switch_tenant, "selected false!", tnt)
 | |
| 
 | |
|         DEBUG(self.switch_tenant, "oceanbase.switch_tenant : ", [" ".join([tnt.tenant_id, str(tnt.selected)]) for tnt in self.tenant])
 | |
|         self.__update_cur_cluster_info()
 | |
|         self.__update_sample()
 | |
| 
 | |
| class Page(object):
 | |
|     def __init__(self, parent, layout, y, x, height, width):
 | |
| 
 | |
|         self.__parent = parent
 | |
|         self.__layout = layout
 | |
|         self.__widgets = []
 | |
|         self.__win = parent.derwin(height, width, y, x)
 | |
|         self.__y = y
 | |
|         self.__x = x
 | |
|         self.__height = height
 | |
|         self.__width = width
 | |
|         self.border()
 | |
|         self.__win.nodelay(1)
 | |
|         self.__win.timeout(0)
 | |
|         self.__win.keypad(1)
 | |
|         self.move(y, x)
 | |
|         self.resize(height, width)
 | |
|         self.__cur_select = 0
 | |
|         self.__shown_widget_num = 0
 | |
|         self.cur_tenant_id = 1
 | |
|         self.__cur_tenant_id = 1
 | |
| 
 | |
|     def get_current_tenant(self):
 | |
|         return self.__cur_tenant_id
 | |
| 
 | |
|     def set_current_tenant(self, tid):
 | |
|         DEBUG(self.set_current_tenant, "Page.set_current_tenant(tid='%s' )" % tid, "")
 | |
|         self.__cur_tenant_id = tid
 | |
| 
 | |
|     def add_widget(self, widget):
 | |
|         DEBUG(self.add_widget, "Page.add_widget(widget='%s') " % widget, "")
 | |
|         if 0 == len(self.__widgets):
 | |
|             widget.select(True)
 | |
|         self.__widgets.append(widget)
 | |
|         self.__rearrange()
 | |
| 
 | |
|     def update_widgets(self):
 | |
|         pass
 | |
| 
 | |
|     def __rearrange(self):
 | |
|         undeleted_widgets = filter(lambda w: False == w.delete(), self.__widgets)
 | |
|         self.__layout.rearrange(0, 0, self.__height, self.__width, undeleted_widgets)
 | |
| 
 | |
|     def rearrange(self):
 | |
|         self.__rearrange()
 | |
| 
 | |
|     def update(self):
 | |
|         self.update_widgets()
 | |
| 
 | |
|     def clear_widgets(self):
 | |
|         self.__widgets = []
 | |
| 
 | |
|     def resize(self, height, width):
 | |
|         self.__height = height
 | |
|         self.__width = width
 | |
|         self.__win.resize(height, width)
 | |
|         self.__rearrange()
 | |
| 
 | |
|     def move(self, y, x):
 | |
|         self.__x = x
 | |
|         self.__y = y
 | |
|         self.__win.mvderwin(y, x)
 | |
|         self.__rearrange()
 | |
| 
 | |
|     def __reset_widgets(self):
 | |
|         if len(self.__widgets) <= 0:
 | |
|             return
 | |
|         shown_widgets = self.shown_widgets()
 | |
|         map(lambda w: w.select(False), self.__widgets)
 | |
|         map(lambda w: w.delete(False), self.__widgets)
 | |
|         self.__cur_select = 0
 | |
|         self.__widgets[self.__cur_select].select(True)
 | |
|         self.__rearrange()
 | |
| 
 | |
|     def __delete_current_widget(self):
 | |
|         shown_widgets = self.shown_widgets()
 | |
|         if len(shown_widgets) <= 0:
 | |
|             return
 | |
|         shown_widgets[self.__cur_select].select(False)
 | |
|         shown_widgets[self.__cur_select].delete(True)
 | |
|         self.__cur_select -= 1
 | |
|         self.select_next()
 | |
|         self.__rearrange()
 | |
| 
 | |
|     def border(self):
 | |
|         pass
 | |
| 
 | |
|     def process_key(self, ch):
 | |
| 
 | |
|         if ch == ord('d'):
 | |
|             self.__delete_current_widget()
 | |
|         elif ch == ord('R'):
 | |
|             self.__reset_widgets()
 | |
|         elif ch == ord('m'):
 | |
|             curses.endwin()
 | |
|             oceanbase.mysql()
 | |
|             curses.doupdate()
 | |
|         elif ch == ord('j'):
 | |
|             curses.endwin()
 | |
|             w = self.selected_widget()
 | |
|             oceanbase.ssh(w.host())
 | |
|             curses.doupdate()
 | |
| 
 | |
|     def redraw(self):
 | |
|         self.erase()
 | |
|         self.__layout.redraw(self.shown_widgets())
 | |
| 
 | |
|     def getch(self):
 | |
|         return self.__win.getch()
 | |
| 
 | |
|     def erase(self):
 | |
|         self.__win.erase()
 | |
| 
 | |
|     def win(self):
 | |
|         return self.__win
 | |
| 
 | |
|     def title(self):
 | |
|         return 'Untitled'
 | |
| 
 | |
|     def select_next(self):
 | |
|         shown_widgets = self.shown_widgets()
 | |
|         if len(shown_widgets) <= 0:
 | |
|             return
 | |
|         shown_widgets[self.__cur_select].select(False)
 | |
|         self.__cur_select = (self.__cur_select + 1) % len(shown_widgets)
 | |
|         shown_widgets[self.__cur_select].select(True)
 | |
| 
 | |
|     def parent(self):
 | |
|         return self.__parent
 | |
| 
 | |
|     def shown_widgets(self):
 | |
|         '''Actually shown widgets that is all widgets except for
 | |
|         1. deleted widgets and,
 | |
|         2. couldn\'t display widgets as no space for them.
 | |
|         '''
 | |
|         return filter(lambda w: w.show() and False == w.delete(), self.__widgets)
 | |
| 
 | |
|     def valid_widgets(self):
 | |
|         '''All widgets excpet for the deleted widgets.'''
 | |
|         return filter(lambda w: False == w.delete(), self.__widgets)
 | |
| 
 | |
|     def all_widgets(self):
 | |
|         return self.__widgets
 | |
| 
 | |
|     def selected_widget(self):
 | |
|         return self.shown_widgets()[self.__cur_select]
 | |
| 
 | |
|     def select_columns(self):
 | |
|         if len(self.all_widgets()) > 0:
 | |
|             all_widgets = [hc_widget.column_widget() for hc_widget in self.all_widgets()]
 | |
|             columns = all_widgets[0].valid_columns()
 | |
|             columns_ret = ColumnCheckBox('Select Columns', columns, self.__parent).run()
 | |
|             for widget in all_widgets:
 | |
|                 for idx in range(0, len(columns)):
 | |
|                     widget.valid_columns()[idx].enable(columns[idx].enable(enable=True))
 | |
|                 widget.update()
 | |
|             [hc_widget.resize() for hc_widget in self.all_widgets()]
 | |
|             self.rearrange()
 | |
| 
 | |
| 
 | |
| class Layout(object):
 | |
|     def __init__(self):
 | |
|         pass
 | |
| 
 | |
|     def redraw(self, widgets):
 | |
|         for widget in widgets:
 | |
|             try:
 | |
|                 if widget.show():
 | |
|                     widget.redraw()
 | |
|             except Exception:
 | |
|                 pass
 | |
| 
 | |
|     def __calc_widget_height(self, height, width, widgets):
 | |
|         max_min_height = max([ widget.min_height() for widget in widgets ])
 | |
|         for widget in widgets:
 | |
|             widget.min_height(max_min_height)
 | |
| 
 | |
|         wwidths = [ widget.min_width() for widget in widgets ]
 | |
|         cur_width = 0
 | |
|         nline = 1
 | |
|         for wwidth in wwidths:
 | |
|             if cur_width + wwidth <= width:
 | |
|                 cur_width += wwidth
 | |
|             else:
 | |
|                 cur_width = wwidth
 | |
|                 nline += 1
 | |
|         widget_height = height / nline
 | |
|         return max(widget_height, max_min_height)
 | |
| 
 | |
|     def rearrange(self, y, x, height, width, widgets):
 | |
|         if height <= 0 or width <= 0 or len(widgets) <= 0:
 | |
|             return 0
 | |
|         widget_height = self.__calc_widget_height(height, width, widgets)
 | |
| 
 | |
|         for widget in widgets:
 | |
|             widget.show(False)
 | |
|         cur_y = 0
 | |
|         cur_x = 0
 | |
|         for index,widget in enumerate(widgets):
 | |
|             if cur_x + widget.min_width() > width:
 | |
|                 cur_y += widget_height
 | |
|                 cur_x = 0
 | |
|             try:
 | |
|                 widget.move(0, 0)
 | |
|                 widget.resize(widget_height, widget.min_width())
 | |
|                 widget.move(cur_y + y, cur_x + x)
 | |
|                 widget.show(True)
 | |
|             except curses.error:
 | |
|                 return index
 | |
|             cur_x += widget.min_width()
 | |
|         return len(widgets)
 | |
| 
 | |
| 
 | |
| class Widget(object):
 | |
|     def __init__(self, min_height, min_width, parent, use_win=False):
 | |
|         DEBUG(self.__init__, "Widget.__init__(%d, %d, %s)" % (min_height, min_width, parent), "")
 | |
|         if use_win:
 | |
|             self.__win = parent
 | |
|         else:
 | |
|             self.__win = parent.derwin(min_height, min_width, 0, 0)
 | |
|         self.__min_height = min_height
 | |
|         self.__min_width = min_width
 | |
|         self.__height, self.__width = self.__win.getmaxyx()
 | |
|         self.__y, self.__x = self.__win.getmaxyx()
 | |
|         self.__select = False
 | |
|         self.__show = False
 | |
|         self.__deleted = False
 | |
| 
 | |
|     def resize(self, height, width):
 | |
|         self.__height = height
 | |
|         self.__width = width
 | |
|         self.__win.resize(height, width)
 | |
| 
 | |
|     def move(self, y, x):
 | |
|         self.__win.mvderwin(y, x)
 | |
|         self.__y = y
 | |
|         self.__x = x
 | |
| 
 | |
|     def mvwin(self, y, x):
 | |
|         self.__win.mvwin(y, x)
 | |
|         self.__y = y
 | |
|         self.__x = x
 | |
| 
 | |
|     def min_height(self, height=None):
 | |
|         if height:
 | |
|             self.__min_height = height
 | |
|         return self.__min_height
 | |
| 
 | |
|     def min_width(self, width=None):
 | |
|         if width:
 | |
|             self.__min_width = width
 | |
|         return self.__min_width
 | |
| 
 | |
|     def geometry(self):
 | |
|         return self.__y, self.__x, self.__height, self.__width
 | |
| 
 | |
|     def height(self):
 | |
|         return self.__height
 | |
| 
 | |
|     def width(self):
 | |
|         return self.__width
 | |
| 
 | |
|     def redraw(self):
 | |
|         pass
 | |
| 
 | |
|     def refresh(self):
 | |
|         self.__win.refresh()
 | |
| 
 | |
|     def erase(self):
 | |
|         self.__win.erase()
 | |
| 
 | |
|     def win(self):
 | |
|         return self.__win
 | |
| 
 | |
|     def select(self, select = None):
 | |
|         if select is not None:
 | |
|             self.__select = select
 | |
|         return self.__select
 | |
| 
 | |
|     def win(self):
 | |
|         return self.__win
 | |
| 
 | |
|     def show(self, show=None):
 | |
|         if show is not None:
 | |
|             self.__show = show
 | |
|         return self.__show
 | |
| 
 | |
|     def update(self):
 | |
|         pass
 | |
| 
 | |
|     def delete(self, delete=None):
 | |
|         if delete is not None:
 | |
|             self.__deleted = delete
 | |
|         return self.__deleted
 | |
| 
 | |
| 
 | |
| class Column(object):
 | |
|     def __init__(self, name, filter, width, duration=False, enable=True, sname=None):
 | |
|         DEBUG(self.__init__, "Column.__init__(name='%s', filter='%s', width=%d) " % (name, filter, width), "")
 | |
|         self.__name = name
 | |
|         self.__filter = filter
 | |
|         self.__width = width
 | |
|         self.__duration = duration
 | |
|         self.__enable = enable
 | |
|         self.__sname = sname or name
 | |
|         self.__valid = True
 | |
| 
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.name() + " (" + self.sname() + ")"
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return self.name()
 | |
| 
 | |
|     def __eq__(self, obj):
 | |
|         return isinstance(obj, Column) and self.name() == obj.name()
 | |
| 
 | |
|     def name(self):
 | |
|         return self.__name
 | |
| 
 | |
|     def sname(self):
 | |
|         return self.__sname
 | |
| 
 | |
|     def header(self):
 | |
|         return self.__sname.center(self.__width).upper()
 | |
| 
 | |
|     def value(self, stat):
 | |
|         def seconds(td):
 | |
|             return float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / (10**6);
 | |
| 
 | |
|         d = self.__filter(stat)
 | |
| 
 | |
| 
 | |
|         DEBUG(self.__init__, "Column.__init__ , %s : " % self.__name , d )
 | |
| 
 | |
|         if type(d) == type(0.0):
 | |
|             div = (seconds(stat['time_delta']) or 1.0) if self.__duration else 1.0
 | |
| 
 | |
|             DEBUG(self.__init__, "Column.__init__ , div : " , div )
 | |
| 
 | |
|             v = d / div
 | |
|             if (v > 100):
 | |
|                 v = int(v)
 | |
|                 return mem_str(v).center(self.__width)[:self.__width]
 | |
|             elif self.__sname == "PCT.":
 | |
|                 return percent_str(v).center(self.__width)[:self.__width]
 | |
|             return ("%.2f" % v).center(self.__width)[:self.__width]
 | |
|         elif type(d) == type(0):
 | |
|             div = (seconds(stat['time_delta']) or 1.0) if self.__duration else 1.0
 | |
| 
 | |
|             DEBUG(self.__init__, "Column.__init__ , div : " , div )
 | |
| 
 | |
|             v = int(d / div)
 | |
|             if (self.__sname == 'ni' or self.__sname == 'no'):
 | |
|                 return mem_str(v).center(self.__width)[:self.__width]
 | |
|             return mem_str(v).center(self.__width)[:self.__width]
 | |
|         elif d == "00:00:00":
 | |
|             v = str(stat['time_delta'])
 | |
| 
 | |
|             return v[0:v.find('.')].center(self.__width)[:self.__width]
 | |
|         elif type(d) == type(''):
 | |
|             return d.center(self.__width)[:self.__width]
 | |
| 
 | |
|     def enable(self, enable=None):
 | |
|         if enable is not None:
 | |
|             self.__enable = enable
 | |
|         return self.__enable
 | |
| 
 | |
|     def valid(self, valid=None):
 | |
|         if valid is not None:
 | |
|             self.__valid = valid
 | |
|         return self.__valid
 | |
| 
 | |
| class MachineStatWidget(Widget):
 | |
|     def __init__(self, name, parent, border=True):
 | |
|         self.__name = name
 | |
|         self.__border = border
 | |
|         width = 48
 | |
|         Widget.__init__(self, 25, width, parent)
 | |
| 
 | |
|     def host(self):
 | |
|         return self.__name.split(':')[0]
 | |
| 
 | |
|     def type_str(self):
 | |
|         return self.__name.split(':')[1]
 | |
| 
 | |
|     def redraw(self):
 | |
|         if self.__border:
 | |
|             if self.select():
 | |
|                 self.win().attron(curses.color_pair(1) | curses.A_BOLD)
 | |
|                 self.win().box()
 | |
|                 self.win().attroff(curses.color_pair(1) | curses.A_BOLD)
 | |
|             else:
 | |
|                 self.win().box()
 | |
|             self.win().addstr(0, 2, " " + self.__name + " ", curses.color_pair(3))
 | |
| 
 | |
|         try:
 | |
|             stat = oceanbase.machine_stat()[self.host()]
 | |
|         except KeyError:
 | |
|             return
 | |
| 
 | |
|         if self.__border:
 | |
|             # cpu info
 | |
|             self.win().addstr(1, 2, "%-7s%4s%%" % ("CPU", "100"), curses.color_pair(7) | curses.A_BOLD)
 | |
|             # self.win().attron(curses.color_pair(8))
 | |
|             self.win().addstr(1, 17, "%-7s%4.1f%%" % ("nice:", float(stat['nice']) / stat['total'] * 100))
 | |
|             self.win().addstr(2, 2, "%-7s%4.1f%%" % ("user:", float(stat['user']) / stat['total'] * 100))
 | |
|             self.win().addstr(2, 17, "%-7s%4.1f%%" % ("iowait:", float(stat['iowait']) / stat['total'] * 100))
 | |
|             self.win().addstr(3, 2, "%-7s%4.1f%%" % ("sys:", float(stat['sys']) / stat['total'] * 100))
 | |
|             self.win().addstr(3, 17, "%-7s%4.1f%%" % ("irq:", float(stat['irq']) / stat['total'] * 100))
 | |
|             self.win().addstr(4, 2, "%-7s%4.1f%%" % ("idle:", float(stat['idle']) / stat['total'] * 100))
 | |
|             self.win().addstr(4, 17, "%-7s%4.1f%%" % ("sirq:", float(stat['softirq']) / stat['total'] * 100))
 | |
|             # self.win().attroff(curses.color_pair(8))
 | |
| 
 | |
|             # load
 | |
|             self.win().addstr(1, 32, "%-7s%6s" % ("Load", "x-core"), curses.color_pair(7) | curses.A_BOLD)
 | |
|             # self.win().attron(curses.color_pair(8))
 | |
|             self.win().addstr(2, 32, "%-7s%6s" % ("1 min:", stat['load1']))
 | |
|             self.win().addstr(3, 32, "%-7s%6s" % ("5 min:", stat['load5']))
 | |
|             self.win().addstr(4, 32, "%-7s%6s" % ("15 min:", stat['load15']))
 | |
|             # self.win().attroff(curses.color_pair(8))
 | |
| 
 | |
|             # mem info
 | |
|             self.win().addstr(6, 2, "%-6s%7s" % ("Mem", mem_str(stat['MemTotal'])), curses.color_pair(7) | curses.A_BOLD)
 | |
|             self.win().addstr(7, 2, "%-6s%7s" % ("used:", mem_str(stat['MemTotal'] - stat['MemFree'])))
 | |
|             self.win().addstr(8, 2, "%-6s%7s" % ("free:", mem_str(stat['MemFree'])))
 | |
| 
 | |
|             # net info
 | |
|             self.win().addstr(6, 17, "%-9s%9s%9s" % ("Network", 'Rx/s', 'Tx/s'), curses.color_pair(7) | curses.A_BOLD)
 | |
|             for idx,item in enumerate(stat['net'].items()):
 | |
|                 if idx > 5:
 | |
|                     break
 | |
|                 self.win().addstr(7 + idx, 17, "%-9s%9s%9s" %
 | |
|                                   (item[0],
 | |
|                                    mem_str(item[1]['bytes_recv'] * pow(10, 6) / float(stat['time_delta']), bit=True),
 | |
|                                    mem_str(item[1]['bytes_sent'] * pow(10, 6) / float(stat['time_delta']), bit=True)))
 | |
| 
 | |
|             # disk io info
 | |
|             self.win().addstr(14, 2, "%-5s%6s%9s" % ("Disk I/O", 'In/s', 'Out/s'), curses.color_pair(7) | curses.A_BOLD)
 | |
|             idx = 15
 | |
|             for item in stat['disk'].items():
 | |
|                 if idx >= self.height() - 1:
 | |
|                     break
 | |
|                 if item[1]['rbytes'] <= 0 and item[1]['wbytes'] <= 0:
 | |
|                     continue
 | |
|                 self.win().addstr(idx, 2, "%-5s%9s%9s" %
 | |
|                                   (item[0],
 | |
|                                    mem_str(item[1]['rbytes'] * pow(10, 6) / float(stat['time_delta'])),
 | |
|                                    mem_str(item[1]['wbytes'] * pow(10, 6) / float(stat['time_delta']))))
 | |
|                 idx += 1
 | |
| 
 | |
| 
 | |
| class ColumnWidget(Widget):
 | |
|     def __init__(self, name, columns, parent, border=True, colorindex=0):
 | |
|         DEBUG(self.__init__, "ColumnWidget.__init__(name='%s', columns='%s', parent='%s')" % (name, columns, parent), "")
 | |
| 
 | |
|         self.__check_column_valid(columns)
 | |
|         self.__name = name
 | |
|         self.__columns = columns
 | |
|         self.__border = border
 | |
|         self.__colorindex = colorindex
 | |
|         enabled_columns = filter(lambda c: c.enable(), self.valid_columns())
 | |
|         width = len(" ".join([c.header() for c in enabled_columns])) + 2 # 2 padding
 | |
|         width = max(width, 18)
 | |
|         if border:
 | |
|             width += 2
 | |
|         Widget.__init__(self, Global.WIDGET_HEIGHT, width, parent)
 | |
| 
 | |
|     def __check_column_valid(self, columns):
 | |
|         for c in columns:
 | |
|             try:
 | |
|                 c.value(oceanbase.sample)
 | |
|             except KeyError:
 | |
|                 c.valid(False)
 | |
| 
 | |
|     def valid_columns(self):
 | |
|         return filter(lambda c: c.valid(), self.__columns)
 | |
| 
 | |
|     def update(self):
 | |
|         enabled_columns = filter(lambda c: c.enable(), self.valid_columns())
 | |
|         width = len(" ".join([c.header() for c in enabled_columns])) + 2 # 2 border + 2 padding
 | |
|         if self.__border:
 | |
|             width += 2
 | |
|         self.min_width(width)
 | |
| 
 | |
|     def redraw(self):
 | |
|         def stat_count():
 | |
|             return oceanbase.stat_count()
 | |
|         def latest(num):
 | |
|             return oceanbase.latest(num)
 | |
| 
 | |
|         enabled_columns = filter(lambda c: c.enable(), self.valid_columns())
 | |
| 
 | |
|         DEBUG(self.redraw, "ColumnWidget.redraw(stat_count=%d, enabled_columns='%s') " % (oceanbase.stat_count(), enabled_columns), "")
 | |
| 
 | |
|         if self.__border:
 | |
|             if self.select():
 | |
|                 self.win().attron(curses.color_pair(1) | curses.A_BOLD)
 | |
|                 self.win().box()
 | |
|                 self.win().attroff(curses.color_pair(1) | curses.A_BOLD)
 | |
|             else:
 | |
|                 self.win().box()
 | |
|             if self.__name:
 | |
|                 self.win().addstr(0, 2, " " + self.__name + " ", curses.color_pair(3))
 | |
|             print_lines = min(stat_count(), self.height() - 3)
 | |
|             self.win().addstr(1, 1, " " + " ".join([ c.header() for c in enabled_columns ]) + " ", curses.color_pair(2))
 | |
|             border_offset = 1
 | |
|         else:
 | |
|             print_lines = min(stat_count(), self.height() - 1)
 | |
|             self.win().addstr(0, 0, " " + " ".join([ c.header() for c in enabled_columns ]) + " ", curses.color_pair(2))
 | |
|             border_offset = 0
 | |
|         latest = latest(print_lines)
 | |
| 
 | |
|         DEBUG(self.redraw, "ColumnWidget.redraw  latest stat[%s/%s]:" % (print_lines, stat_count()) , latest)
 | |
| 
 | |
| 
 | |
| 
 | |
|         li = []
 | |
|         for i in range(0, len(latest)):
 | |
|             item = []
 | |
|             for c in enabled_columns:
 | |
| 
 | |
|                 v = c.value(latest[i])
 | |
| 
 | |
|                 DEBUG(self.redraw, "ColumnWidget.redraw : item value:  %s:%s" % (c, v), "")
 | |
| 
 | |
|                 item.append(str(v))
 | |
| 
 | |
| 
 | |
|             li.append(" " + " ".join(item))
 | |
| 
 | |
| 
 | |
|             for ii in range(0, len(li)):
 | |
|                 if ii==0:
 | |
|                     self.win().addstr(ii + 1 + border_offset, border_offset, li[ii], curses.color_pair(10))
 | |
|                 else:
 | |
|                     self.win().addstr(ii + 1 + border_offset, border_offset, li[ii], curses.color_pair(self.__colorindex))
 | |
| 
 | |
|         #DEBUG(self.redraw, "ColumnWidget.redraw latest output :", li[3])
 | |
| 
 | |
| class HeaderColumnWidget(Widget):
 | |
|     def __init__(self, name, columns, parent, padding=0, get_header=None, colorindex=0):
 | |
|         DEBUG(self.__init__, "HeaderColumnWidget.__init__(name='%s', columns='%s', parent='%s')" % (name, columns, parent), "")
 | |
|         self.__name = name
 | |
|         self.__padding = padding
 | |
|         self.__get_header = get_header
 | |
|         Widget.__init__(self, Global.WIDGET_HEIGHT, 0, parent)
 | |
| 
 | |
|         self.__column_widget = ColumnWidget(None, columns, self.win(), False, colorindex)
 | |
|         self.min_width(self.__column_widget.min_width() + 2)
 | |
|         self.resize(self.min_height(), self.min_width())
 | |
| 
 | |
| 
 | |
|     def redraw(self):
 | |
|         DEBUG(self.redraw, "HeaderColumnWidget.redraw() ", "")
 | |
|         if self.select():
 | |
|             self.win().attron(curses.color_pair(1))
 | |
|             self.win().box()
 | |
|             self.win().attroff(curses.color_pair(1))
 | |
|         else:
 | |
|             self.win().box()
 | |
| 
 | |
|         nline = 1
 | |
| 
 | |
|         if self.__get_header and oceanbase.stat_count() > 0:
 | |
|             header = self.__get_header(oceanbase.now())
 | |
|             string = ""
 | |
|             hitems = header.items()
 | |
|             hitems.sort()
 | |
|             DEBUG(self.redraw, "HeaderColumnWidget.redraw() header.items() ", hitems)
 | |
|             for item in hitems :
 | |
|                 item_str = ": ".join([item[0], str(item[1])])
 | |
|                 if (len(string) + len(item_str) + 2 > self.min_width() - 2):
 | |
|                     string = string[2:]
 | |
|                     self.win().addstr(nline, 1, string.center(self.min_width() - 2))
 | |
|                     string = ""
 | |
|                     nline += 1
 | |
|                 string += "  " + item_str
 | |
|             if string:
 | |
|                 string = string[2:]
 | |
|                 self.win().addstr(nline, 1, string.center(self.min_width() - 2))
 | |
|                 self.__set_padding(nline)
 | |
|             else:                         # fix ob 0.4.1 wired bug
 | |
|                 self.__set_padding(0)
 | |
|         self.__column_widget.redraw()
 | |
|         if self.__name:
 | |
|             self.win().addstr(0, 2, " " + self.__name + " ", curses.color_pair(3))
 | |
|         time = strftime(" %Y-%m-%d %T ")
 | |
|         self.win().addstr(0, self.width() - len(time) - 2, time, curses.color_pair(3))
 | |
| 
 | |
|     def resize(self, height=None, width=None):
 | |
|         DEBUG(self.resize, "height, width", "|".join([str(height), str(width)]))
 | |
|         if height is not None and width is not None:
 | |
|             Widget.resize(self, height, width)
 | |
|             maxy, maxx = self.win().getmaxyx()
 | |
|             self.__column_widget.resize(maxy - self.__padding - 2, maxx - 2)
 | |
|         if height is None:
 | |
|             height = self.__column_widget.min_height() + self.__padding + 2
 | |
|             self.resize(height, width)
 | |
|         if width is None:
 | |
|             width = self.__column_widget.min_width() + 2
 | |
|             self.min_width(width)
 | |
|             self.resize(height, width)
 | |
| 
 | |
|     def move(self, y, x):
 | |
|         self.win().mvderwin(y, x)
 | |
|         self.__column_widget.win().mvderwin(self.__padding + 1, 1)
 | |
| 
 | |
|     def __set_padding(self, padding):
 | |
|         self.min_height(padding + 2 + 2)
 | |
|         maxy, maxx = self.win().getmaxyx()
 | |
|         self.__padding = padding
 | |
|         self.__column_widget.move(0, 0)
 | |
|         self.__column_widget.resize(maxy - self.__padding - 2, maxx - 2)
 | |
|         self.__column_widget.move(self.__padding + 1, 1)
 | |
| 
 | |
|     def update(self):
 | |
|         self.__column_widget.update()
 | |
| 
 | |
|     def host(self):
 | |
|         return self.__name.split(":")[0]
 | |
| 
 | |
|     def sql_port(self):
 | |
|         return self.__name.split(":")[1]
 | |
| 
 | |
|     def column_widget(self):
 | |
|         return self.__column_widget
 | |
| 
 | |
| 
 | |
| class StatusWidget(Widget):
 | |
|     def __init__(self, parent):
 | |
|         DEBUG(self.__init__, "StatusWidget.__init__(parent='%s') " % parent, "")
 | |
|         self.__parent = parent
 | |
|         maxy, maxx = parent.getmaxyx()
 | |
|         Widget.__init__(self, 2, maxx, parent)
 | |
| 
 | |
|         self.resize(2, maxx)
 | |
|         self.move(maxy - 2, 0)
 | |
|         self.win().bkgd(curses.color_pair(1))
 | |
| 
 | |
|     def redraw(self):
 | |
|         now = strftime("%Y-%m-%d %T")
 | |
|         maxy, maxx = self.win().getmaxyx()
 | |
| #       tps = self.__get_tps()
 | |
| #       qps = self.__get_qps()
 | |
|         svr_list = oceanbase.find_svr_list()["observer"]
 | |
|         statstr = "HOST: %s:%d " % (Options.host, Options.port)
 | |
|         statstr += "RUMC: %d" % (len(svr_list))
 | |
|         try:
 | |
|             self.win().addstr(1, maxx - len(now) - 2, now)
 | |
|             self.win().addstr(1, 2, statstr)
 | |
|             self.win().hline(0, 0, curses.ACS_HLINE, 1024)
 | |
|         except curses.error:
 | |
|             pass
 | |
| 
 | |
| 
 | |
| 
 | |
|     def __get_tps(self):
 | |
|         if oceanbase.stat_count() > 1:
 | |
|             last = oceanbase.now()
 | |
|             insert = sum([item["SQL_INSERT_COUNT"]
 | |
|                             for item in last[str(self.cur_tenant_id)].values()])
 | |
|             replace = sum([item["SQL_REPLACE_COUNT"]
 | |
|                             for item in last[str(self.cur_tenant_id)].values()])
 | |
|             delete = sum([item["SQL_DELETE_COUNT"]
 | |
|                             for item in last[str(self.cur_tenant_id)].values()])
 | |
|             update = sum([item["SQL_UPDATE_COUNT"]
 | |
|                             for item in last[str(self.cur_tenant_id)].values()])
 | |
|             tps = float(insert + replace + delete + update) / seconds(last['time_delta'])
 | |
|             return int(tps)
 | |
|         else:
 | |
|             return 0
 | |
| 
 | |
|     def __get_qps(self):
 | |
|         if oceanbase.stat_count() > 1:
 | |
|             last = oceanbase.now()
 | |
|             total = float(sum([item["SQL_SELECT_COUNT"]
 | |
|                                for item in last[oceanbase.__cur_tenant_id].values()]))
 | |
|             qps = total / seconds(last['time_delta'])
 | |
|             return int(qps)
 | |
|         else:
 | |
|             return 0
 | |
| 
 | |
| 
 | |
| class HeaderWidget(Widget):
 | |
|     def __init__(self, parent):
 | |
|         DEBUG(self.__init__, "HeaderWidget.__init__(parent='%s') " % parent, "")
 | |
|         maxy, maxx = parent.getmaxyx()
 | |
|         Widget.__init__(self, 2, maxx, parent)
 | |
|         self.__page = None
 | |
|         self.win().bkgd(curses.color_pair(1))
 | |
| 
 | |
|     def redraw(self):
 | |
|         DEBUG(self.redraw, "HeaderWidget.redraw ", "")
 | |
|         self.erase()
 | |
|         if self.__page is None:
 | |
|             try:
 | |
|                 self.win().addstr(0, 2, '1:Help 2:Gallery 3:SQL(ObServer) 4:History(30 minutes) 5:Bianque 6:Machine Stat 7-0:Blank', curses.A_BOLD)
 | |
|                 self.win().hline(1, 0, curses.ACS_HLINE, 1024, curses.A_BOLD)
 | |
|             except curses.error:
 | |
|                 pass
 | |
|         else:
 | |
|             maxy, maxx = self.win().getmaxyx()
 | |
|             shown_num = len(self.__page.shown_widgets())
 | |
|             valid_num = len(self.__page.valid_widgets())
 | |
|             all_num = len(self.__page.all_widgets())
 | |
|             shown_str = 'Shown: %d / Valid: %d / Total: %d' % (shown_num, valid_num, all_num)
 | |
|             try:
 | |
|                 self.win().addstr(0, 2, self.__page.title(), curses.A_BOLD)
 | |
|                 self.win().addstr(0, maxx - len(shown_str) - 4, shown_str, curses.A_BOLD)
 | |
|                 self.win().hline(1, 0, curses.ACS_HLINE, 1024, curses.A_BOLD)
 | |
|             except curses.error:
 | |
|                 pass
 | |
| 
 | |
|     def switch_page(self, page):
 | |
|         DEBUG(self.switch_page, "HeaderWidget.switch_page(page='%s' " % (page) , "")
 | |
|         self.__page = page
 | |
| 
 | |
| 
 | |
| class MessageBox(object):
 | |
|     def __init__(self, parent, msg):
 | |
|         self.msg = msg
 | |
|         self.parent = parent
 | |
|         maxy, maxx = parent.getmaxyx()
 | |
|         width = min(maxx - 20, len(msg)) + 10
 | |
|         height = 5
 | |
|         y = (maxy - height) / 2
 | |
|         x = (maxx - width) / 2
 | |
|         self.win = parent.derwin(height, width, y, x)
 | |
|         self.win.erase()
 | |
|         self.win.attron(curses.color_pair(1))
 | |
|         self.win.box()
 | |
|         self.win.attroff(curses.color_pair(1))
 | |
|         self.win.addstr(2, 4, self.msg, curses.color_pair(0))
 | |
| 
 | |
|     def run(self, anykey=False):
 | |
|         res = True
 | |
|         while (1):
 | |
|             c = self.win.getch()
 | |
|             if anykey:
 | |
|                 break
 | |
|             elif c == ord('y'):
 | |
|                 res = True
 | |
|                 break
 | |
|             elif c == ord('n'):
 | |
|                 res = False
 | |
|                 break
 | |
|             elif c == ord('q'):
 | |
|                 res = False
 | |
|                 break
 | |
|         self.win.erase()
 | |
|         self.win.refresh()
 | |
|         return res
 | |
| 
 | |
| class PopPad(Widget):
 | |
|     def __init__(self, name, items, parent, **args):
 | |
|         self.__offset_x = 0
 | |
|         self.__offset_y = 0
 | |
|         self.__name = name
 | |
| 
 | |
|         maxy, maxx = parent.getmaxyx()
 | |
|         width = maxx - 100
 | |
|         height = 10
 | |
|         Widget.__init__(self, height, width, parent)
 | |
|         self.resize(height, width)
 | |
|         y = (maxy - height - self.__offset_y) / 2
 | |
|         x = (maxx - width - self.__offset_x) / 2
 | |
|         self.mvwin(self.__offset_y + y, self.__offset_x + x)
 | |
|         self.move(self.__offset_y + y, self.__offset_x + x)
 | |
| 
 | |
|     def __do_key(self):
 | |
|         ch = self.win().getch()
 | |
|         stopFlg = False
 | |
|         if ch in (ord("q"), ord("Q")):
 | |
|             stopFlg = True
 | |
| 
 | |
|     def __redraw(self):
 | |
|         self.win().erase()
 | |
|         self.win().attron(curses.color_pair(1))
 | |
|         self.win().box()
 | |
|         self.win().attroff(curses.color_pair(1))
 | |
|         self.win().addstr(0, 2, ' %s ' % self.__name, curses.color_pair(3))
 | |
| 
 | |
|     def run(self):
 | |
|         self.__redraw()
 | |
|         while(True):
 | |
|             if self.__do_key():
 | |
|                 self.win().erase()
 | |
|                 self.win().refresh()
 | |
|                 return
 | |
|             self.__redraw()
 | |
|             self.win().refresh()
 | |
| 
 | |
| class SelectionBox(Widget):
 | |
|     __padding_left = 5
 | |
|     __padding_top = 0
 | |
|     __offset_y = 0
 | |
|     __offset_x = 0
 | |
|     __chr_list = 'abcdefghimorstuvwxyzABCDEFGHIMORSTUVWXYZ0123456789'
 | |
|     __hot_key = False
 | |
| 
 | |
|     def __init__(self, name, items, parent, **args):
 | |
|         self.__index = 0
 | |
|         self.__name = name
 | |
|         self.items = items
 | |
|         self.parent = parent
 | |
|         self.__start_idx = 0
 | |
|         self.__stop_idx = 0
 | |
|         s = list(self.__chr_list)
 | |
|         shuffle(s)
 | |
|         self.__chr_list = ''.join(s)
 | |
|         self.__offset_y = args.get('offset_y', self.__offset_y)
 | |
|         self.__offset_x = args.get('offset_x', self.__offset_x)
 | |
|         self.__hot_key = args.get('hot_key', self.__hot_key)
 | |
| 
 | |
|         maxy, maxx = parent.getmaxyx()
 | |
|         width = max(len(name) + 6, max([len(it) + 5 for it in items]))
 | |
|         height = min(len(items) + 2, maxy - self.__offset_y)
 | |
|         Widget.__init__(self, height, width, parent)
 | |
|         self.resize(height, width)
 | |
|         y = (maxy - height - self.__offset_y) / 2
 | |
|         x = (maxx - width - self.__offset_x) / 2
 | |
|         self.mvwin(self.__offset_y + y, self.__offset_x + x)
 | |
|         self.move(self.__offset_y + y, self.__offset_x + x)
 | |
|         self.win().nodelay(1)
 | |
|         self.win().timeout(0)
 | |
|         self.win().keypad(1)
 | |
|         self.__stop_idx = self.__start_idx + self.height() - 2
 | |
| 
 | |
|     def __do_key(self):
 | |
|         ch = self.win().getch()
 | |
|         stop = False
 | |
|         if self.__fm is not None and ch != -1:
 | |
|             self.__fm()
 | |
|             self.__fm = None
 | |
|         elif ch in [ord('s'), ord('S')]:
 | |
|             self.__index = -2
 | |
|             stop = True
 | |
|         if ch in [ ord('j'), ord('\t'), ord('n'), ord('J'), ord('N'), curses.KEY_DOWN ]:
 | |
|             if self.__index == len(self.items) - 1:
 | |
|                 self.__start_idx = 0
 | |
|                 self.__stop_idx = self.__start_idx + self.height() - 2
 | |
|                 self.__index = 0
 | |
|             elif self.__index == self.__stop_idx - 1:
 | |
|                 self.__start_idx = self.__start_idx + 1
 | |
|                 self.__stop_idx =  self.__stop_idx + 1
 | |
|                 self.__index = self.__index + 1
 | |
|             else:
 | |
|                 self.__index = self.__index + 1
 | |
|         elif ch in [ ord('k'), ord('K'), ord('p'), ord('P'), curses.KEY_UP ]:
 | |
|             if self.__index == 0:
 | |
|                 self.__start_idx = max(0, len(self.items) - self.height() + 2)
 | |
|                 self.__stop_idx = self.__start_idx + self.height() - 2
 | |
|                 self.__index = len(self.items) - 1
 | |
|             elif self.__index == self.__start_idx:
 | |
|                 self.__start_idx = self.__start_idx - 1
 | |
|                 self.__stop_idx =  self.__stop_idx - 1
 | |
|                 self.__index = self.__index - 1
 | |
|             else:
 | |
|                 self.__index = self.__index - 1
 | |
|         elif ch in [ ord('\n'), ord(' ') ]:
 | |
|             stop = True
 | |
|         elif ch in [ ord('q'), ord('Q') ]:
 | |
|             self.__index = -1
 | |
|             stop = True
 | |
|         elif not self.__hot_key:
 | |
|             pass
 | |
|         elif ch in [ ord(c) for c in self.__chr_list ]:
 | |
|             self.__index = [ ord(c) for c in self.__chr_list ].index(ch) + self.__start_idx
 | |
|             stop = True
 | |
|         return stop
 | |
| 
 | |
|     def __redraw(self):
 | |
|         self.win().erase()
 | |
|         self.win().attron(curses.color_pair(1))
 | |
|         self.win().box()
 | |
|         self.win().attroff(curses.color_pair(1))
 | |
|         self.win().addstr(0, 2, ' %s ' % self.__name, curses.color_pair(3))
 | |
|         for idx, item in enumerate(self.items):
 | |
|             if idx < self.__start_idx or idx >= self.__stop_idx:
 | |
|                 continue
 | |
| 
 | |
|             if not self.__hot_key:
 | |
|                 line = item.center(self.width() - 2)
 | |
|             elif idx - self.__start_idx < len(self.__chr_list):
 | |
|                 pref = ' %s)' % self.__chr_list[idx - self.__start_idx]
 | |
|                 line = pref + item.center(self.width() - 5)
 | |
|             else:
 | |
|                 pref = '   '
 | |
|                 line = pref + item.center(self.width() - 5)
 | |
|             flag = 0
 | |
|             if idx == self.__index:
 | |
|                 flag = curses.A_BOLD | curses.color_pair(5)
 | |
|             self.win().addstr(idx - self.__start_idx + self.__padding_top + 1, 1, item, flag)
 | |
| 
 | |
|     def run(self, first_movement=None):
 | |
|         self.__fm = first_movement
 | |
|         res = True
 | |
|         while (1):
 | |
|             if self.__do_key():
 | |
|                 self.win().erase()
 | |
|                 self.win().refresh()
 | |
|                 return self.__index
 | |
|             self.__redraw()
 | |
|             self.win().refresh()
 | |
| 
 | |
| class ColumnCheckBox(Widget):
 | |
|     __padding_left = 5
 | |
|     __padding_top = 0
 | |
|     __margin_top = 4
 | |
|     __margin_bottom = 4
 | |
|     __offset_y = 0
 | |
|     __offset_x = 0
 | |
| 
 | |
|     def __init__(self, name, items, parent, **args):
 | |
|         self.__index = 0
 | |
|         self.__name = name
 | |
|         self.items = items
 | |
|         self.parent = parent
 | |
|         self.__start_idx = 0
 | |
|         self.__stop_idx = 0
 | |
| 
 | |
|         self.__margin_top = args.get('marging_top', self.__margin_top)
 | |
|         self.__margin_bottom = args.get('marging_bottom', self.__margin_bottom)
 | |
|         self.__offset_y = args.get('offset_y', self.__offset_y)
 | |
|         self.__offset_x = args.get('offset_x', self.__offset_x)
 | |
|         maxy, maxx = parent.getmaxyx()
 | |
|         width = max(len(name) + 6, max([len(str(it)) + 9 for it in items]))
 | |
|         height = min(len(items) + 2, maxy - self.__offset_y - self.__margin_top - self.__margin_bottom)
 | |
|         Widget.__init__(self, height, width, parent)
 | |
|         self.resize(height, width)
 | |
|         y = (maxy - height - self.__offset_y) / 2
 | |
|         x = (maxx - width - self.__offset_x) / 2
 | |
|         self.mvwin(self.__offset_y + y, self.__offset_x + x)
 | |
|         self.move(self.__offset_y + y, self.__offset_x + x)
 | |
|         self.win().nodelay(1)
 | |
|         self.win().timeout(0)
 | |
|         self.win().keypad(1)
 | |
|         self.__stop_idx = self.__start_idx + self.height() - 2
 | |
| 
 | |
|     def __do_key(self):
 | |
|         ch = self.win().getch()
 | |
|         stop = False
 | |
|         if self.__fm is not None and ch != -1:
 | |
|             self.__fm()
 | |
|             self.__fm = None
 | |
|         if ch in [ ord('j'), ord('\t'), ord('n'), ord('J'), ord('N'), curses.KEY_DOWN ]:
 | |
|             if self.__index == len(self.items) - 1:
 | |
|                 self.__start_idx = 0
 | |
|                 self.__stop_idx = self.__start_idx + self.height() - 2
 | |
|                 self.__index = 0
 | |
|             elif self.__index == self.__stop_idx - 1:
 | |
|                 self.__start_idx = self.__start_idx + 1
 | |
|                 self.__stop_idx =  self.__stop_idx + 1
 | |
|                 self.__index = self.__index + 1
 | |
|             else:
 | |
|                 self.__index = self.__index + 1
 | |
|         elif ch in [ ord('k'), ord('K'), ord('p'), ord('P'), curses.KEY_UP ]:
 | |
|             if self.__index == 0:
 | |
|                 self.__start_idx = max(0, len(self.items) - self.height() + 2)
 | |
|                 self.__stop_idx = self.__start_idx + self.height() - 2
 | |
|                 self.__index = len(self.items) - 1
 | |
|             elif self.__index == self.__start_idx:
 | |
|                 self.__start_idx = self.__start_idx - 1
 | |
|                 self.__stop_idx =  self.__stop_idx - 1
 | |
|                 self.__index = self.__index - 1
 | |
|             else:
 | |
|                 self.__index = self.__index - 1
 | |
|         elif ch in [ ord(' ') ]:
 | |
|             self.items[self.__index].enable(not self.items[self.__index].enable())
 | |
|         elif ch in [ ord('\n') ]:
 | |
|             stop = True
 | |
|         elif ch in [ ord('q'), ord('Q') ]:
 | |
|             self.__index = -1
 | |
|             stop = True
 | |
|         return stop
 | |
| 
 | |
|     def __redraw(self):
 | |
|         self.win().erase()
 | |
|         self.win().attron(curses.color_pair(1))
 | |
|         self.win().box()
 | |
|         self.win().attroff(curses.color_pair(1))
 | |
|         self.win().addstr(0, 2, ' %s ' % self.__name, curses.color_pair(3))
 | |
|         for idx, item in enumerate(self.items):
 | |
|             if idx < self.__start_idx or idx >= self.__stop_idx:
 | |
|                 continue
 | |
|             pref = ' [%s]' % (item.enable() and 'X' or ' ')
 | |
|             line = pref + str(item).center(self.width() - 6)
 | |
|             flag = 0
 | |
|             if idx == self.__index:
 | |
|                 flag = curses.A_BOLD | curses.color_pair(5)
 | |
|             self.win().addstr(idx - self.__start_idx + self.__padding_top + 1, 1, line, flag)
 | |
| 
 | |
|     def run(self, first_movement=None):
 | |
|         self.__fm = first_movement
 | |
|         res = True
 | |
|         while (1):
 | |
|             if self.__do_key():
 | |
|                 self.win().erase()
 | |
|                 self.win().refresh()
 | |
|                 return self.__index
 | |
|             self.__redraw()
 | |
|             self.win().refresh()
 | |
|         if self.__index == -1:
 | |
|             return []
 | |
|         else:
 | |
|             return self.items
 | |
| 
 | |
| 
 | |
| class InputBox(Widget):
 | |
|     def __init__(self, parent, prompt="Password", password=False, width=30):
 | |
|         self.__index = 0
 | |
|         self.__name = "name"
 | |
|         self.__offset_x = 0
 | |
|         self.__offset_y = 0
 | |
|         self.__password = password
 | |
|         height = 3
 | |
|         win = curses.newwin(0, 0, 0, 0)
 | |
|         Widget.__init__(self, height, width, win, True)
 | |
|         self.resize(height, width)
 | |
|         maxy, maxx = parent.getmaxyx()
 | |
|         y = (maxy - height - self.__offset_y) / 2
 | |
|         x = (maxx - width - self.__offset_x) / 2
 | |
|         self.mvwin(y, x)
 | |
|         win.box()
 | |
|         win.refresh()
 | |
|         self.__prompt = prompt + ": "
 | |
|         win.addstr(1, 1, self.__prompt)
 | |
|         win.move(1, 1 + len(self.__prompt))
 | |
|         self.__textbox = curses.textpad.Textbox(win)
 | |
|         self.__result = ""
 | |
| 
 | |
|     def validator(self, ch):
 | |
|         y, x = self.win().getyx()
 | |
|         if ch == 127:
 | |
|             new_x = max(x - 1, len(self.__prompt) + 1)
 | |
|             self.win().delch(y, new_x)
 | |
|             self.win().insch(' ')
 | |
|             self.win().move(y, new_x)
 | |
|             self.__result = self.__result[:-1]
 | |
|             return 0
 | |
|         elif ch == 7 or ch == 10:                             # submit
 | |
|             return 7
 | |
|         elif x == self.width() - 2:
 | |
|             return 0
 | |
|         elif ch < 256:
 | |
|             self.__result += chr(ch)
 | |
|             if self.__password:
 | |
|                 return ord('*')
 | |
|             else:
 | |
|                 return ch
 | |
| 
 | |
|     def run(self):
 | |
|         curses.noecho()
 | |
|         curses.curs_set(1)
 | |
|         self.__textbox.edit(self.validator)
 | |
|         curses.curs_set(0)
 | |
|         return self.__result
 | |
| 
 | |
| 
 | |
| class GalleryPage(Page):
 | |
|     def __add_widgets(self):
 | |
|         DEBUG(self.__add_widgets, "GalleryPage.__add_widgets() tenant_id : ", self.cur_tenant_id)
 | |
| 
 | |
|         time_widget = ColumnWidget("TIME-TENANT", [
 | |
|             Column("time", lambda stat:stat["timestamp"].strftime("%H:%M:%S"), 8, False),
 | |
|             Column("tenant", lambda stat:str(stat["tenant"]),  6, False ),
 | |
|             ], self.win(), True, 3)
 | |
| 
 | |
|         sql_count_widget = ColumnWidget("SQL COUNT", [
 | |
|             Column("sel.", lambda stat:sum([item["sql select count"] for item in stat[str(self.cur_tenant_id)].values()]), 6, True),
 | |
|             Column("ins.", lambda stat:sum([ item["sql insert count"] for item in stat[str(self.cur_tenant_id)].values() ]), 6, True),
 | |
|             Column("upd.", lambda stat:sum([ item["sql update count"] for item in stat[str(self.cur_tenant_id)].values() ]), 6, True),
 | |
|             Column("del.", lambda stat:sum([ item["sql delete count"] for item in stat[str(self.cur_tenant_id)].values() ]), 6, True),
 | |
|             Column("rep.", lambda stat:sum([ item["sql replace count"] for item in stat[str(self.cur_tenant_id)].values() ]), 5, True),
 | |
|             Column("cmt.", lambda stat:sum([ item["trans commit count"] for item in stat[str(self.cur_tenant_id)].values() ]), 6, True),
 | |
|             Column("rol.", lambda stat:sum([ item["trans rollback count"] for item in stat[str(self.cur_tenant_id)].values() ]), 4, True),
 | |
|             ], self.win(), True, 6)
 | |
| 
 | |
|         sql_rt_widget = ColumnWidget("SQL RT", [
 | |
|             Column("sel.", lambda stat:
 | |
|                 (sum([ item["sql select time"] for item in stat[str(self.cur_tenant_id)].values() ])
 | |
|                  / float(sum([ item["sql select count"] for item in stat[str(self.cur_tenant_id)].values() ]) or 1) / 1000),
 | |
|                 6, False),
 | |
|             Column("ins.", lambda stat:
 | |
|                 (sum([ item["sql insert time"] for item in stat[str(self.cur_tenant_id)].values() ])
 | |
|                  / float(sum([ item["sql insert count"] for item in stat[str(self.cur_tenant_id)].values() ]) or 1) / 1000),
 | |
|                 6, False),
 | |
|             Column("upd.", lambda stat:
 | |
|                 (sum([ item["sql update time"] for item in stat[str(self.cur_tenant_id)].values() ])
 | |
|                  / float(sum([ item["sql update count"] for item in stat[str(self.cur_tenant_id)].values() ]) or 1) / 1000),
 | |
|                 6, False),
 | |
|             Column("del.", lambda stat:
 | |
|                 (sum([ item["sql delete time"] for item in stat[str(self.cur_tenant_id)].values() ])
 | |
|                  / float(sum([ item["sql delete count"] for item in stat[str(self.cur_tenant_id)].values() ]) or 1) / 1000),
 | |
|                 6, False),
 | |
|             Column("rep.", lambda stat:
 | |
|                 (sum([ item["sql replace time"] for item in stat[str(self.cur_tenant_id)].values() ])
 | |
|                  / float(sum([ item["sql replace count"] for item in stat[str(self.cur_tenant_id)].values() ]) or 1) / 1000),
 | |
|                 5, False),
 | |
|             Column("cmt.", lambda stat:
 | |
|                 (sum([ item["trans commit time"] for item in stat[str(self.cur_tenant_id)].values() ])
 | |
|                  / float(sum([ item["trans commit count"] for item in stat[str(self.cur_tenant_id)].values() ]) or 1) / 1000),
 | |
|                 6, False),
 | |
|             ], self.win(), True, 8)
 | |
| 
 | |
|         net_rt_widget = ColumnWidget("RPC", [
 | |
|             Column("fail", lambda stat:sum([item["rpc deliver fail"] for item in stat[str(self.cur_tenant_id)].values()]),
 | |
|                 4, True),
 | |
|             Column("net", lambda stat:sum([ item["rpc net delay"] for item in stat[str(self.cur_tenant_id)].values() ]) / float(sum([ item["rpc packet in"] for item in stat[str(self.cur_tenant_id)].values() ]) or 1) / 1000,
 | |
|                 4, False),
 | |
|             Column("frame", lambda stat:sum([ item["rpc net frame delay"] for item in stat[str(self.cur_tenant_id)].values() ]) / float(sum([ item["rpc packet in"] for item in stat[str(self.cur_tenant_id)].values() ]) or 1) / 1000,
 | |
|                 4, False),
 | |
|             ], self.win(), True, 0)
 | |
| 
 | |
|         memory_widget = ColumnWidget("MEMORY(T)", [
 | |
|             Column("⊿active", lambda stat:
 | |
|                     sum([item["active memstore used"] for item in stat[str(self.cur_tenant_id)].values()]),
 | |
|                 7, True),
 | |
|             Column("TOTAL", lambda stat:
 | |
|                     sum([item["total memstore used"] for item in stat[str(self.cur_tenant_id)].values()]),
 | |
|                 7, False),
 | |
|             Column("PCT.", lambda stat:
 | |
|                     sum([item["total memstore used"] for item in stat[str(self.cur_tenant_id)].values()])
 | |
|                     / float(sum([item["memstore limit"] for item in stat[str(self.cur_tenant_id)].values()]) or 1),
 | |
|                 6, False)
 | |
|             ], self.win(), True, 8)
 | |
| 
 | |
|         iops_widget = ColumnWidget("IOPS", [
 | |
|             Column("SES.", lambda stat:
 | |
|                    sum([item["active sessions"] for item in stat[str(self.cur_tenant_id)].values() ]),
 | |
|                 6, True),
 | |
|             Column("ior", lambda stat:
 | |
|                    sum([item["io read count"] for item in stat[str(self.cur_tenant_id)].values() ]),
 | |
|                 6, True),
 | |
|             Column("ior-sz", lambda stat:
 | |
|                    sum([item["io read bytes"] for item in stat[str(self.cur_tenant_id)].values() ]),
 | |
|                 7, True),
 | |
|             Column("iow", lambda stat:
 | |
|                    sum([item["io write count"] for item in stat[str(self.cur_tenant_id)].values() ]),
 | |
|                 5, True),
 | |
|             Column("iow-sz", lambda stat:
 | |
|                    sum([item["io write bytes"] for item in stat[str(self.cur_tenant_id)].values() ]),
 | |
|                 6, True),
 | |
|             ], self.win(), True, 6)
 | |
| 
 | |
|         self.add_widget(time_widget)
 | |
|         self.add_widget(sql_count_widget)
 | |
|         self.add_widget(sql_rt_widget)
 | |
|         self.add_widget(net_rt_widget)
 | |
|         self.add_widget(memory_widget)
 | |
|         self.add_widget(iops_widget)
 | |
| 
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
| 
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
| 
 | |
|         try:
 | |
|             self.__add_widgets()
 | |
|         except curses.error:
 | |
|             pass
 | |
| 
 | |
|     def title(self):
 | |
|         return "Gallery"
 | |
| 
 | |
|     def process_key(self, ch):
 | |
|         if ch == ord('j'):
 | |
|             pass
 | |
|         else:
 | |
|             Page.process_key(self, ch)
 | |
| 
 | |
| class BianquePage(Page):
 | |
|     def update_widgets(self):
 | |
|         pass
 | |
| 
 | |
|     def title(self):
 | |
|         return "Bianque"
 | |
| 
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
|         try:
 | |
|             self.update_widgets()
 | |
|         except curses.error:
 | |
|             pass
 | |
| 
 | |
| class HistoryPage(Page):
 | |
|     def update_widgets(self):
 | |
|         pass
 | |
| 
 | |
|     def title(self):
 | |
|         return "History"
 | |
| 
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
|         try:
 | |
|             self.update_widgets()
 | |
|         except curses.error:
 | |
|             pass
 | |
| 
 | |
| #DEV = file("/Users/mq/Downloads/dooba.log", "w")
 | |
| DEV = file("/dev/null","w")
 | |
| def DEBUG(*args):
 | |
|     global DEV
 | |
|     if Options.debug :
 | |
|         print >> DEV, "line %s :%s in [%s] %s %s" % (sys._getframe().f_lineno, time.asctime(), args[0].func_name, args[1], args[2])
 | |
| 
 | |
| 
 | |
| class TableApiPage(Page):
 | |
|     def __add_widgets(self):
 | |
|         tid = oceanbase.get_current_tenant()
 | |
|         DEBUG(self.__add_widgets, "cur_tenant_id", tid)
 | |
|         time_widget = ColumnWidget("TIME-TENANT", [
 | |
|             Column("timestamp", lambda stat:
 | |
|                 stat["timestamp"].strftime("%H:%m:%S"),
 | |
|                     10, True),
 | |
|             Column("tenant", lambda stat:
 | |
|                 tid,
 | |
|                 10, True
 | |
|                 ),
 | |
|             ], self.win())
 | |
|         
 | |
|         tableapi_widget = ColumnWidget("TABLE API ROWS", [
 | |
|             Column("get", lambda stat:(sum([ item["multi retrieve rows"] for item in stat[str(tid)].values() ])
 | |
|                     + sum([ item["single retrieve execute count"] for item in stat[str(tid)].values() ])), 6, True),
 | |
|             Column("put", lambda stat:(sum([ item["multi insert_or_update rows"] for item in stat[str(tid)].values()])
 | |
|                     + sum([ item["single insert_or_update execute count"] for item in stat[str(tid)].values() ])), 6, True),
 | |
|             Column("del", lambda stat:(sum([ item["multi delete rows"] for item in stat[str(tid)].values() ])
 | |
|                     + sum([ item["single delete execute count"] for item in stat[str(tid)].values() ])), 6, True),
 | |
|             Column("ins", lambda stat:(sum([ item["multi insert rows"] for item in stat[str(tid)].values() ])
 | |
|                     + sum([ item["single insert execute count"] for item in stat[str(tid)].values() ])), 6, True),
 | |
|             Column("upd", lambda stat:(sum([ item["multi update rows"] for item in stat[str(tid)].values() ])
 | |
|                     + sum([ item["single update execute count"] for item in stat[str(tid)].values() ])), 6, True),
 | |
|             Column("repl", lambda stat:(sum([ item["multi replace rows"] for item in stat[str(tid)].values() ])
 | |
|                     + sum([ item["single replace execute count"] for item in stat[str(tid)].values() ])), 6, True),
 | |
|             Column("query", lambda stat:(sum([ item["query row count"] for item in stat[str(tid)].values() ])), 6, True),
 | |
|             ], self.win())
 | |
| 
 | |
|         tableapi_widget2 = ColumnWidget("TABLE API OPS", [
 | |
|             Column("get", lambda stat:(sum([ item["multi retrieve execute count"] for item in stat[str(tid)].values()])),6, True),
 | |
|             Column("put", lambda stat:(sum([ item["multi insert_or_update execute count"] for item in stat[str(tid)].values()])),6, True),
 | |
|             Column("del", lambda stat:(sum([ item["multi delete execute count"] for item in stat[str(tid)].values()])),6, True),
 | |
|             Column("ins", lambda stat:(sum([ item["multi insert execute count"] for item in stat[str(tid)].values()])),6, True),
 | |
|             Column("upd", lambda stat:(sum([ item["multi update execute count"] for item in stat[str(tid)].values()])),6, True),
 | |
|             Column("repl", lambda stat:(sum([ item["multi replace execute count"] for item in stat[str(tid)].values()])),6, True),
 | |
|             Column("query", lambda stat:(sum([ item["query count"] for item in stat[str(tid)].values()])),6, True),
 | |
|             ], self.win())
 | |
| 
 | |
|         tableapi_widget3 = ColumnWidget("Table API RT", [
 | |
|             Column("get", lambda stat:(sum([ item["multi retrieve execute time"] for item in stat[str(tid)].values() ])
 | |
|                     / float(sum([ item["multi retrieve execute count"] for item in stat[str(tid)].values() ]) or 1) / 1000), 6),
 | |
|             Column("put", lambda stat:(sum([ item["multi insert_or_update execute time"] for item in stat[str(tid)].values() ])
 | |
|                     / float(sum([ item["multi insert_or_update execute count"] for item in stat[str(tid)].values() ]) or 1) / 1000), 6),
 | |
|             Column("del", lambda stat:(sum([ item["multi delete execute time"] for item in stat[str(tid)].values() ])
 | |
|                     / float(sum([ item["multi delete execute count"] for item in stat[str(tid)].values() ]) or 1) / 1000), 6),
 | |
|             Column("ins", lambda stat:(sum([ item["multi insert execute time"] for item in stat[str(tid)].values() ])
 | |
|                     / float(sum([ item["multi insert execute count"] for item in stat[str(tid)].values() ]) or 1) / 1000), 6),
 | |
|             Column("upd", lambda stat:(sum([ item["multi update execute time"] for item in stat[str(tid)].values() ])
 | |
|                     / float(sum([ item["multi update execute count"] for item in stat[str(tid)].values() ]) or 1) / 1000), 6),
 | |
|             Column("repl", lambda stat:(sum([ item["multi replace execute time"] for item in stat[str(tid)].values() ])
 | |
|                     / float(sum([ item["multi replace execute count"] for item in stat[str(tid)].values() ]) or 1) / 1000), 6),
 | |
|             Column("query", lambda stat:(sum([ item["query time"] for item in stat[str(tid)].values() ])
 | |
|                     / float(sum([ item["query count"] for item in stat[str(tid)].values() ]) or 1) / 1000), 6),
 | |
|         ], self.win())
 | |
| 
 | |
|         self.add_widget(time_widget)
 | |
|         self.add_widget(tableapi_widget2)
 | |
|         self.add_widget(tableapi_widget)
 | |
|         self.add_widget(tableapi_widget3)
 | |
| 
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
|         try:
 | |
|             self.__add_widgets()
 | |
|         except curses.error:
 | |
|             pass
 | |
| 
 | |
|     def title(self):
 | |
|         return "Table API"
 | |
| 
 | |
|     def process_key(self, ch):
 | |
|         if ch == ord('j'):
 | |
|             pass
 | |
|         else:
 | |
|             Page.process_key(self, ch)
 | |
| 
 | |
| 
 | |
| class SQLPage(Page):
 | |
|     def update_widgets(self):
 | |
|         DEBUG(self.update_widgets, "SQLPage.update_widgets() ", "")
 | |
| 
 | |
|         def observer_info(stat, ip):
 | |
|             def try_add(name, key, wrapper):
 | |
|                 try:
 | |
|                     if key in oceanbase.delta_key_list:
 | |
|                         result[name] = wrapper(int(stat[str(oceanbase.get_current_tenant())][ip][key] / seconds(stat['time_delta'])))
 | |
|                     else:
 | |
|                         result[name] = wrapper(stat[str(oceanbase.get_current_tenant())][ip][key])
 | |
| 
 | |
|                     DEBUG(try_add,"SQLPage.try_add(name='%s', key='%s', wrapper='%s', value='%s'" % (name, key, wrapper, result[name]), "")
 | |
|                 except Exception as e:
 | |
|                     DEBUG(try_add, "SQLPage.try_add(name='%s', key='%s', wrapper='%s' exception :" % (name, key, wrapper) , e)
 | |
| 
 | |
| 
 | |
|             def try_add2(name, key1, key2, wrapper):
 | |
|                 try:
 | |
|                     result[name] = wrapper(float(stat[str(oceanbase.get_current_tenant())][ip][key1] )/ float((stat[str(oceanbase.get_current_tenant())][ip][key1] + stat[str(oceanbase.get_current_tenant())][ip][key2]) or 1))
 | |
|                     DEBUG(try_add2, "wrapper %s" % (name) , (stat[str(oceanbase.get_current_tenant())][ip][key1] + stat[str(oceanbase.get_current_tenant())][ip][key2]))
 | |
|                     DEBUG(try_add2, "wrapper %s" % (name) , stat[str(oceanbase.get_current_tenant())][ip][key1])
 | |
|                     DEBUG(try_add2, "%s result " % (name) , result[name])
 | |
|                 except Exception as e:
 | |
|                     DEBUG(try_add2, "SQLPage.try_add2(name='%s', key1='%s', key2='%s' ) exception" % (name ,key1 ,key2), e)
 | |
|                     pass
 | |
| 
 | |
|             result = dict()
 | |
|             try_add("Active Sess", "active sessions", count_str)
 | |
|             try_add("IO-R Cnt", "io read count", mem_str)
 | |
|             try_add("IO-R Size", "io read bytes", mem_str)
 | |
|             try_add("IO-W Cnt", "io write count", mem_str)
 | |
|             try_add("IO-W Size", "io write bytes", mem_str)
 | |
|             try_add("CPU", "cpu usage", percent_str)
 | |
|             try_add2("Cache-Row Hit", "row cache hit", "row cache miss", percent_str)
 | |
|             try_add2("Cache-Loc Hit", "location cache hit", "location cache miss", percent_str)
 | |
|             try_add2("Cache-Blk Hit", "block cache hit", "block cache miss", percent_str)
 | |
|             try_add2("Cache-BI Hit", "block index cache hit", "block index cache miss", percent_str)
 | |
|             #try_add2("B-F-cache hit", "bloom filter cache hit", "bloom filter cache miss", percent_str)
 | |
| 
 | |
| 
 | |
|             return result
 | |
| 
 | |
|         svr = "observer"
 | |
|         self.clear_widgets()
 | |
|         DEBUG(self.update_widgets, "SQLPage.update_widgets svr_list :", oceanbase.get_tenant_svr())
 | |
| 
 | |
|         i = 0
 | |
|         ci = 0
 | |
|         for ms in oceanbase.get_tenant_svr()[svr]:
 | |
|             i = i+1
 | |
|             if i % 2 == 0 :
 | |
|                 ci = 6
 | |
|             else:
 | |
|                 ci = 8
 | |
| 
 | |
|             zone = ms['zone']
 | |
|             #ip = ms['ip']
 | |
|             #port = ms['port']
 | |
|             ip = '%s:%s' % (ms['ip'], ms['port'])
 | |
|             DEBUG(observer_info, "oceanbase.get_current_tenant()", oceanbase.get_current_tenant())
 | |
|             f = ColumnFactory(svr, ip)
 | |
|             DEBUG(self.update_widgets, "column factory:", f)
 | |
|             #widget = HeaderColumnWidget( '%s:%s:%d' % (zone,ip,int(port)), [
 | |
|             widget = HeaderColumnWidget( '%s:%s' % (zone,ip), [
 | |
|                 #default(SQL)
 | |
|                 f.count("Sql Select Count", "ssc", "sql select count", duration=True, enable=True),
 | |
|                 f.time("Sql Select Time", "ssrt", "sql select time","sql select count" , duration=False,enable=True),
 | |
|                 f.count("Sql Insert Count", "sic", "sql insert count", duration=True, enable=True),
 | |
|                 f.time("Sql Insert Time", "sirt", "sql insert time","sql insert count", duration=False, enable=True),
 | |
|                 f.count("Sql Update Count", "suc", "sql update count", duration=True, enable=True),
 | |
|                 f.time("Sql Update Time", "surt", "sql update time", "sql update count", duration=False, enable=True),
 | |
|                 f.count("Sql Delete Count", "sdc", "sql delete count", duration=True, enable=True),
 | |
|                 f.time("Sql Delete Time", "sdrt", "sql delete time", "sql delete count", duration=False, enable=True),
 | |
|                 f.count("Sql Replace Count", "src", "sql replace count", duration=True, enable=True),
 | |
|                 f.time("Sql Replace Time", "srrt", "sql replace time","sql replace count", duration=False, enable=True),
 | |
|                 f.count("Trans Commit Count", "tcc", "trans commit count", duration=True, enable=True),
 | |
|                 f.time("Trans Commit Time", "tcrt", "trans commit time","trans commit count", duration=False, enable=True),
 | |
|                 f.count("Sql Local Count", "slc", "sql local count", duration=True, enable=True),
 | |
|                 f.count("Sql Remote Count", "src", "sql remote count", duration=True, enable=True),
 | |
|                 #f.count("Sql Distributed Count", "sdc", "sql distributed count", duration=True,enable=True),
 | |
|                 #f.count("Inner SQL Connection Execute Count", "iscec", "inner sql connection execute count"),
 | |
|                 #f.time("Inner SQL Connection Execute Time", "iscet", "inner sql connection execute time"),
 | |
|                 #inner packet
 | |
|                 #f.count("RPC Packet In", "rpci", "rpc packet in"),
 | |
|                 #f.count("RPC Packet In Bytes", "rpci(B)", "rpc packet in bytes"),
 | |
|                 #f.count("RPC Packet Out", "rpco", "rpc packet out"),
 | |
|                 #f.count("RPC Packet Out Bytes", "rpco(B)", "rpc packet out bytes"),
 | |
|                 #f.count("RPC Deliver Fail", "rpc fail", "rpc deliver fail"),
 | |
|                 #f.time("RPC Net Delay", "rpc delay", "rpc net delay"),
 | |
|                 #f.count("RPC Net Frame Delay", "rpc frame delay", "rpc net frame delay"),
 | |
|                 #outer packet
 | |
|                 #f.count("MySQL Packet In", "mpci", "mysql packet in"),
 | |
|                 #f.count("MySQL Packet In Bytes", "mpci(B)", "mysql packet in bytes"),
 | |
|                 #f.count("MySQL Packet Out", "mpco", "mysql packet out"),
 | |
|                 #f.count("MySQL Packet Out Bytes", "mpco(B)", "mysql packet out bytes"),
 | |
|                 #f.count("MySQL Deliver Fail", "mdf", "mysql deliver fail"),
 | |
|                 #request queue
 | |
|                 #f.count("Request Enqueue Count", "enqueue", "request enqueue count"),
 | |
|                 #f.count("Request Dequeue Count", "dequeue", "request dequeue count"),
 | |
|                 #f.time("Request Queue Time", "QT", "request queue time"),
 | |
|                 #transmition
 | |
|                 #f.time("Trans Commit Log Time", "tclt", "trans commit log time"),
 | |
|                 #f.count("Trans Commit Log Sync Count", "tclsc(sync)", "trans commit log sync count"),
 | |
|                 #f.count("Trans Commit LOg Submit Count", "tclsc(submit)", "trans commit log submit count"),
 | |
|                 #f.count("Trans System Trans Count", "tstc", "trans system trans count"),
 | |
|                 #f.count("Trans User Trans Count", "tutc", "trans user trans count"),
 | |
|                 #f.count("Trans Start Count", "tsc", "trans start count"),
 | |
|                 #f.count("Trans Total Used Time", "ttut", "trans total used time"),
 | |
|                 #f.count("Trans Rollback Count", "trc", "trans rollback count"),
 | |
|                 #f.time("Trans Rollback Time", "trt", "trans rollback time"),
 | |
|                 #f.count("Trans Timeout Count", "ttc", "trans timeout count"),
 | |
|                 #f.count("Trans Single Partition Count", "tspc", "trans single partition count"),
 | |
|                 #cache
 | |
|                 #FIXME
 | |
|                 #f.count("Row Cache Hit", "rch", "row cache hit"),
 | |
|                 #f.count("Row Cache Miss", "rcm", "row cache miss"),
 | |
|                 #f.count("Block Index Cache Hit", "bich", "block index cache hit"),
 | |
|                 #f.count("Block Index Cache Miss", "bicm", "block index cache miss"),
 | |
|                 #f.count("Bloom Filter Cache Hit", "bfch", "bloom filter cache hit"),
 | |
|                 #f.count("Bloom Filter Cache Miss", "bfcm", "bloom filter cache miss"),
 | |
|                 #f.count("Bloom Filter Filts", "bff", "bloom filter filts"),
 | |
|                 #f.count("Bloom Filter Passes", "bfp", "bloom filter passes"),
 | |
|                 #f.count("Block Cache Hit", "bch", "block cache hit"),
 | |
|                 #f.count("Block Cache Miss", "bcm", "block cache miss"),
 | |
|                 #f.count("Location Cache Hit", "lch", "location cache hit"),
 | |
|                 #f.count("Location Cache Miss", "lcm", "location cache miss"),
 | |
|                 #resources
 | |
|                 #f.count("Active Sessions", "as", "active sessions"),
 | |
|                 #f.count("IO Read Count", "iorc", "io read count"),
 | |
|                 #f.count("IO Read Delay", "iord", "io read delay"),
 | |
|                 #f.count("IO Read Bytes", "ior(B)", "io read bytes"),
 | |
|                 #f.count("IO Write Count", "iowc", "io write count"),
 | |
|                 #f.count("IO Write Delay", "iowd", "io write delay"),
 | |
|                 #f.count("IO Write Bytes", "iow(B)", "io write bytes"),
 | |
|                 #f.count("Memstore Scan Count", "msc", "memstore scan count"),
 | |
|                 #f.count("Memstore Scan Succ Count", "mssc", "memstore scan succ count"),
 | |
|                 #f.count("Memstore Scan Fail Count", "msfc", "memstore scan fail count"),
 | |
|                 #f.count("Memstore Get Count", "mgc", "memstore get count"),
 | |
|                 #f.count("Memstore Get Succ Count", "mgsc", "memstore get succ count"),
 | |
|                 #f.count("Memstore Get Fail Count", "mgfc", "memstore get fail count"),
 | |
|                 #f.count("Memstore Apply Count", "mac", "memstore apply count"),
 | |
|                 #f.count("Memstore Apply Succ Count", "masc", "memstore apply succ count"),
 | |
|                 #f.count("Memstore Apply Fail Count", "mafc", "memstore apply fail count"),
 | |
|                 #f.count("Memstore Row Count", "mrc", "memstore row count"),
 | |
|                 #f.time("Memstore Get Time", "mgt", "memstore get time"),
 | |
|                 #f.time("Memstore Scan Time", "mst", "memstore scan time"),
 | |
|                 #f.time("Memstore Apply Time", "mat", "memstore apply time"),
 | |
|                 #f.count("Memstore Read Lock Succ Count", "mrlsc", "memstore read lock succ count"),
 | |
|                 #f.count("Memstore Read Lock Fail Count", "mrlfc", "memstore read lock fail count"),
 | |
|                 #f.count("Memstore Write Lock Succ Count", "mwlsc", "memstore write lock succ count"),
 | |
|                 #f.count("Memstore Write Lock Fail Count", "mwlfc", "memstore write lock fail count"),
 | |
|                 #f.time("Memstore Wait Write Lock Time", "mwwlt", "memstore wait write lock time"),
 | |
|                 #f.time("Memstore Wait Read Lock Time", "mwrlt", "memstore wait read lock time"),
 | |
|                 #f.count("IO Read Micro Index Count", "iormic", "io read micro index count"),
 | |
|                 #f.count("IO Read Micro Index Bytes", "iormib", "io read micro index bytes"),
 | |
|                 #f.count("IO Prefetch Micro Block Count", "iopmbc", "io prefetch micro block count"),
 | |
|                 #f.count("IO Prefetch Micro Block Bytes", "iopmbb", "io prefetch micro block bytes"),
 | |
|                 #f.count("IO Read Uncompress Micro Block Count", "iorumbc", "io read uncompress micro block count"),
 | |
|                 #f.count("IO Read Uncompress Micro Block Bytes", "iorumbb", "io read uncompress micro block bytes"),
 | |
|                 #f.count("Active Memstore Used", "amu", "active memstore used"),
 | |
|                 #f.count("Total Memstore Used", "tmu", "total memstore used"),
 | |
|                 #f.count("Major Freeze Trigger", "mft", "major freeze trigger"),
 | |
|                 #f.count("Memstore Limit", "ml", "memstore limit"),
 | |
|                 #f.count("Min Memory Size", "mms(min)", "min memory size"),
 | |
|                 #f.count("Max Memory Size", "mms(max)", "max memory size"),
 | |
|                 #f.count("Memory Usage", "mu", "memory usage"),
 | |
|                 #f.count("Min CPUS", "mc(min)", "min cpus"),
 | |
|                 #f.count("Max CPUS", "mc(max)", "max cpus"),
 | |
|                 #meta
 | |
|                 #f.count("Refresh Schema Count", "rsc", "refresh schema count"),
 | |
|                 #f.time("Refresh Schema Time", "rst", "refresh schema time"),
 | |
|                 #f.count("Partition Table Operator Get Count", "ptogc", "partition table operator get count"),
 | |
|                 #f.time("Partition Table Operator Get Time", "ptogt", "partition table operator get time"),
 | |
|                 #clog
 | |
|                 #f.count("Submitted To Sliding Window Log Count", "sswlc", "submitted to sliding window log count"),
 | |
|                 #f.count("Submitted To Sliding Window Log Size", "sswls", "submitted to sliding window log size"),
 | |
|                 #f.count("Index Log Flushed Count", "ilfc", "index log flushed count"),
 | |
|                 #f.count("Index Log Flushed Clog Size", "ilfcs", "index log flushed clog size"),
 | |
|                 #f.count("Clog Flushed Count", "cfc", "clog flushed count"),
 | |
|                 #f.count("Clog Flushed Size", "cfs", "clog flushed size"),
 | |
|                 #f.count("Clog Read Count", "crc(read)", "clog read count"),
 | |
|                 #f.count("Clog Read Size", "crs", "clog read size"),
 | |
|                 #f.count("Clog Disk Read Size", "cdrs", "clog disk read size"),
 | |
|                 #f.count("Clog Disk Read Count", "cdrc", "clog disk read count"),
 | |
|                 #f.time("Clog Disk Read Time", "cdrt", "clog disk read time"),
 | |
|                 #f.count("Clog Fetch Log Size", "cfls", "clog fetch log size"),
 | |
|                 #f.count("Clog Fetch Log Count", "cflc", "clog fetch log size"),
 | |
|                 #f.count("Clog Fetch Log By Location Size", "cflbls", "clog fetch log by location size"),
 | |
|                 #f.count("Clog Fetch Log By Location Count", "cflblc", "clog fetch log by location count"),
 | |
|                 #f.count("Clog Read Request Succ Size", "crrss", "clog read request succ size"),
 | |
|                 #f.count("Clog Read Request Succ Count", "crrsc", "clog read request succ count"),
 | |
|                 #f.count("Clog Read Request Fail Count", "crrfc", "clog read request fail count"),
 | |
|                 #f.time("Clog Confirm Delay Time", "ccdt", "clog confirm delay time"),
 | |
|                 #f.count("Clog Flush Task Generate Count", "cftgc", "clog flush task generate count"),
 | |
|                 #f.count("Clog Flush Task Release Count", "cftrc", "clog flush task release count"),
 | |
|                 #f.count("Clog RPC Delay Time", "crdt", "clog rpc delay time"),
 | |
|                 #f.count("Clog RPC Count", "crc(rpc)", "clog rpc count"),
 | |
|                 #f.count("Clog Non KV Cache Hit Count", "cnkchc", "clog non kv cache hit count"),
 | |
|                 #f.time("Clog RPC Request Handle Time", "crrht", "clog rpc request handle time"),
 | |
|                 #f.count("Clog RPC Request Count", "crrc", "clog rpc request count"),
 | |
|                 #f.count("Clog Cache Hit Count", "cchc", "clog cache hit count")
 | |
|                 ], self.win(), get_header=lambda stat,ip=ip: observer_info(stat,ip) , colorindex=ci)
 | |
|             self.add_widget(widget)
 | |
| 
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
|         try:
 | |
|             self.update_widgets()
 | |
|         except curses.error:
 | |
|             pass
 | |
|     def select_columns(self):
 | |
|         if len(self.all_widgets()) > 0:
 | |
|             all_widgets = [hc_widget.column_widget() for hc_widget in self.all_widgets()]
 | |
|             columns = all_widgets[0].valid_columns()
 | |
|             i = ColumnCheckBox("Select Columns", columns, self.parent()).run()
 | |
|             for w in all_widgets:
 | |
|                 w.valid_columns()[i].enable(enable=(not w.valid_columns()[i].enable()))
 | |
|                 w.update()
 | |
| #           for widget in all_widgets:
 | |
| #               for idx in range(0, len(columns)):
 | |
| #                   widget.valid_columns()[idx].enable(columns[idx].enable(enable=True))
 | |
| #               widget.update()
 | |
| #           [hc_widget.resize() for hc_widget in self.all_widgets()]
 | |
| #           self.rearrange()
 | |
| 
 | |
|     def process_key(self, ch):
 | |
|         w = self.selected_widget()
 | |
|         if ch == ord('m'):
 | |
|             curses.endwin()
 | |
|             oceanbase.mysql(host=w.host(), port=int(w.sql_port()))
 | |
|             curses.doupdate()
 | |
|         elif ch == ord('o'):
 | |
|             pass
 | |
|         elif ch == ord('O'):
 | |
|             like_str = InputBox(self.win(), prompt="LIKE STR").run()
 | |
|             oceanbase.show_sql_result("select name,value from __all_sys_config_stat where svr_ip='%s' and svr_type='mergeserver' and name like '%s' order by name" % (w.host(), like_str))
 | |
|         elif Options.env == 'online' and ch == ord('l'):
 | |
|             cmd = "ssh -t %s 'less oceanbase/log/mergeserver.log'" % w.host()
 | |
|             curses.endwin()
 | |
|             os.system(cmd)
 | |
|             curses.doupdate()
 | |
|         elif ch == ord("i"):
 | |
|             self.select_columns()
 | |
|         else:
 | |
|             Page.process_key(self, ch)
 | |
| 
 | |
|     def title(self):
 | |
|         return "SQLPage"
 | |
| 
 | |
| class EventPage(Page):
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
| 
 | |
|     def title(self):
 | |
|         return "EventPage"
 | |
| 
 | |
|     def update_widgets(self):
 | |
|         Page.update_widgets(self)
 | |
| 
 | |
| class MachineStatPage(Page):
 | |
|     def update_widgets(self):
 | |
|         pass
 | |
| 
 | |
|     def title(self):
 | |
|         return "Machine Stat"
 | |
| 
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
| 
 | |
| class HelpPage(Page):
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
|         self.win().bkgd(curses.color_pair(4))
 | |
| 
 | |
|     def redraw(self):
 | |
|         nline = [0]                       # hack mutating outer variables for python2
 | |
|         def addline(x, line, attr=0):
 | |
|             self.win().addstr(nline[0], x, line, attr)
 | |
|             nline[0] += 1
 | |
|         def addkeys(keys):
 | |
|             for key_item in keys:
 | |
|                 if 0 == len(key_item):
 | |
|                     string = ""
 | |
|                 else:
 | |
|                     string = "    %-14s: %s" % key_item
 | |
|                 addline(4, string)
 | |
|             nline[0] += 1
 | |
|         def addgroup(group_name, keys):
 | |
|             addline(4, group_name, curses.color_pair(4) | curses.A_BOLD)
 | |
|             addline(2, "----------------------------------------------", curses.color_pair(4) | curses.A_BOLD)
 | |
|             addkeys(keys)
 | |
|         try:
 | |
|             Page.redraw(self)
 | |
|             ob_keys = [('c', 'Switch between tenants'),
 | |
|                        ('w', 'write a screenshot file to current window')]
 | |
|             addgroup("Global Keys  -  oceanbase", ob_keys)
 | |
|             widget_keys = [('Tab','Select next widget'),
 | |
|                            ('m', 'Connect to oceanbase lms for this cluster using mysql'),
 | |
|                            ('j', 'ssh to selected host')]
 | |
|             addgroup("Global Keys  -  Widget", widget_keys)
 | |
|             pages_keys = [('1 F1', 'Help page'), ('2 F2', 'Gallery page'), ('3 F3', 'Observer page'), ('4 F4', 'History page'),
 | |
|                           ('d', 'Delete selected widget'), ('R', 'Restore deleted widgets'),
 | |
|                           ('=', 'Filter Columns for current page (ms,cs,ups page only)')]
 | |
|             addgroup("Global Keys  -  Page", pages_keys)
 | |
|             test_keys = [('p', 'Messsage box tooltips')]
 | |
|             addgroup("Global Keys  -  Test", test_keys)
 | |
|             select_keys = [('DOWN TAB J P', 'Next item'), ('UP K N', 'Previous item'),
 | |
|                            ('SPC ENTER', 'Select current item'),
 | |
|                            ('Q q', 'Quit selection box')]
 | |
|             addgroup("Global Keys  -  Selection Box", select_keys)
 | |
|             system_keys = [('q', 'quit dooba')]
 | |
|             addgroup("Global Keys  -  System", system_keys)
 | |
|             support = [
 | |
|                 ('Author', ''),
 | |
|                 ('Mail', ''),
 | |
|                 (),
 | |
|                 ('github page', 'https://github.com/oceanbase/oceanbase'),
 | |
|                 ('bug report', 'https://github.com/oceanbase/oceanbase/issues'),
 | |
|                 ('feature req', 'https://github.com/oceanbase/oceanbase/issues')
 | |
|                 ]
 | |
|             addgroup("Support", support)
 | |
|         except curses.error:
 | |
|             pass
 | |
| 
 | |
|     def title(self):
 | |
|         return 'Help'
 | |
| 
 | |
| 
 | |
| class BlankPage(Page):
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
| 
 | |
|     def title(self):
 | |
|         return 'Blank Page'
 | |
| 
 | |
| class FalloutPage(Page):
 | |
|     def __init__(self, y, x, h, w, parent):
 | |
|         Page.__init__(self, parent, Layout(), y, x, h, w)
 | |
|         self.c = 0
 | |
| 
 | |
|     def redraw(self):
 | |
|         if self.c < 9:
 | |
|             _____="""FFFFFFFFFFFFFFFFFFFFFF                lllllll lllllll                                           tttt\nF::::::::::::::::::::F                l:::::l l:::::l                                        ttt:::t\nF::::::::::::::::::::F                l:::::l l:::::l                                        t:::::t\nFF::::::FFFFFFFFF::::F                l:::::l l:::::l                                        t:::::t\n  F:::::F       FFFFFFaaaaaaaaaaaaa    l::::l  l::::l    ooooooooooo   uuuuuu    uuuuuuttttttt:::::ttttttt\n  F:::::F             a::::::::::::a   l::::l  l::::l  oo:::::::::::oo u::::u    u::::ut:::::::::::::::::t\n  F::::::FFFFFFFFFF   aaaaaaaaa:::::a  l::::l  l::::l o:::::::::::::::ou::::u    u::::ut:::::::::::::::::t\n  F:::::::::::::::F            a::::a  l::::l  l::::l o:::::ooooo:::::ou::::u    u::::utttttt:::::::tttttt\n  F:::::::::::::::F     aaaaaaa:::::a  l::::l  l::::l o::::o     o::::ou::::u    u::::u      t:::::t\n  F::::::FFFFFFFFFF   aa::::::::::::a  l::::l  l::::l o::::o     o::::ou::::u    u::::u      t:::::t\n  F:::::F            a::::aaaa::::::a  l::::l  l::::l o::::o     o::::ou::::u    u::::u      t:::::t\n  F:::::F            a::::aaaa::::::a  l::::l  l::::l o::::o     o::::ou::::u    u::::u      t:::::t\n  F:::::F           a::::a    a:::::a  l::::l  l::::l o::::o     o::::ou:::::uuuu:::::u      t:::::t    tttttt\nFF:::::::FF         a::::a    a:::::a l::::::ll::::::lo:::::ooooo:::::ou:::::::::::::::uu    t::::::tttt:::::t\nF::::::::FF         a:::::aaaa::::::a l::::::ll::::::lo:::::::::::::::o u:::::::::::::::u    tt::::::::::::::t\nF::::::::FF          a::::::::::aa:::al::::::ll::::::l oo:::::::::::oo   uu::::::::uu:::u      tt:::::::::::tt\nF::::::::FF          a::::::::::aa:::al::::::ll::::::l oo:::::::::::oo   uu::::::::uu:::u      tt:::::::::::tt\nFFFFFFFFFFF           aaaaaaaaaa  aaaallllllllllllllll   ooooooooooo       uuuuuuuu  uuuu        ttttttttttt\n\n\n                                             00000000000000000\n                                  00000000000000000000000000000000000000\n                      0000000000000000000000000000000000000000000000000000000000000\n               0000000000000000000000000000000000000000000000000000000000000000000000000000000\n          000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n        00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n     00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n    0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n     00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n           0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n                0000000000000000000000000000000000000000000000000000000000000000000000000000000\n                                 0000000000000000000000000000000000000000\n                                    000000000000000000000000000000000\n                                           0000000000000000000\n                                                 0000000\n                                                   000\n                                                   000\n                                                   000\n                                                  00000\n                    000000                      000000000                    00000\n                 000000000000                000000000000000              00000000000\n            000000000000000000000000000000000000000000000000000000000000000000000000000000000\n00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n__      ____ _ _ __  __      ____ _ _ __   _ __   _____   _____ _ __    ___| |__   __ _ _ __   __ _  ___  ___\n\ \ /\ / / _` | '__| \ \ /\ / / _` | '__| | '_ \ / _ \ \ / / _ \ '__|  / __| '_ \ / _` | '_ \ / _` |/ _ \/ __|\n \ V  V / (_| | | _   \ V  V / (_| | |    | | | |  __/\ V /  __/ |    | (__| | | | (_| | | | | (_| |  __/\__ \\\n  \_/\_/ \__,_|_|( )   \_/\_/ \__,_|_|    |_| |_|\___| \_/ \___|_|     \___|_| |_|\__,_|_| |_|\__, |\___||___/\n                 |/                                                                           |___/\n
 | |
|             """
 | |
|             self.win().addstr(2, 0, _____, curses.color_pair(0))
 | |
|         else:
 | |
|             return
 | |
| 
 | |
|     def title(self):
 | |
|         return "Fallout"
 | |
| 
 | |
| 
 | |
| class Dooba(object):
 | |
|     def build_oceanbase(self):
 | |
|         return '''
 | |
|   ___                       ____
 | |
|  / _ \  ___ ___  __ _ _ __ | __ )  __ _ ___  ___
 | |
| | | | |/ __/ _ \/ _` | \'_ \|  _ \ / _` / __|/ _ \\
 | |
| | |_| | (_|  __/ (_| | | | | |_) | (_| \__ \  __/
 | |
|  \___/ \___\___|\__,_|_| |_|____/ \__,_|___/\___|'''
 | |
| 
 | |
|     def build_dooba(self):
 | |
|         return '''
 | |
|      _             _
 | |
|   __| | ___   ___ | |__   __ _
 | |
|  / _` |/ _ \ / _ \| \'_ \ / _` |
 | |
| | (_| | (_) | (_) | |_) | (_| |
 | |
|  \__,_|\___/ \___/|_.__/ \__,_|'''
 | |
| 
 | |
|     def __init_curses(self, win):
 | |
|         self.stdscr = win
 | |
|         self.stdscr.keypad(1)
 | |
|         self.stdscr.nodelay(1)
 | |
|         self.stdscr.timeout(0)
 | |
|         self.maxy, self.maxx = self.stdscr.getmaxyx()
 | |
|         curses.curs_set(0)
 | |
|         curses.noecho()
 | |
|         self.__term = curses.termname()
 | |
|         self.__init_colors()
 | |
| 
 | |
|     def __init_colors(self):
 | |
|         if curses.has_colors():
 | |
|             curses.use_default_colors()
 | |
|             curses.init_pair(1, curses.COLOR_RED, -1)   # header widget and status widget
 | |
|             curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_GREEN) # column header
 | |
|             curses.init_pair(3, curses.COLOR_MAGENTA, -1) # widget title
 | |
|             curses.init_pair(4, curses.COLOR_YELLOW, -1) # help page color
 | |
|             curses.init_pair(5, curses.COLOR_RED, curses.COLOR_CYAN)
 | |
|             curses.init_pair(6, curses.COLOR_GREEN, -1) # column header
 | |
|             curses.init_pair(7, curses.COLOR_WHITE, -1) # machine stat header
 | |
|             curses.init_pair(8, curses.COLOR_BLUE, -1)
 | |
|             curses.init_pair(9, curses.COLOR_MAGENTA, -1)
 | |
|             curses.init_pair(10, curses.COLOR_WHITE, curses.COLOR_CYAN)
 | |
| 
 | |
| 
 | |
|     def __resize_term(self):
 | |
|         self.maxy, self.maxx = self.stdscr.getmaxyx()
 | |
|         try:
 | |
|             self.help_w.move(0, 0)
 | |
|             self.help_w.mvwin(0, 0)
 | |
|             self.help_w.resize(2, self.maxx)
 | |
|             self.stat_w.move(self.maxy - 2, 0)
 | |
|             self.stat_w.resize(2, self.maxx)
 | |
|             for page in self.__all_page:
 | |
|                 page.resize(self.maxy - 4, self.maxx)
 | |
|         except curses.error:
 | |
|             pass
 | |
|         self.stdscr.erase()
 | |
| 
 | |
|     def __do_key(self):
 | |
|         ch = self.__all_page[self.__page_index].getch()
 | |
|         if ch == ord('q'):
 | |
|             curses.endwin()
 | |
|             return True
 | |
|         elif ch >= ord('0') and ch <= ord('9'):
 | |
|             self.__page_index = ch - ord('0')
 | |
|             self.help_w.switch_page(self.__all_page[self.__page_index])
 | |
|         elif ch >= curses.KEY_F1 and ch <= curses.KEY_F9:
 | |
|             self.__page_index = ch - curses.KEY_F1
 | |
|             self.help_w.switch_page(self.__all_page[self.__page_index])
 | |
|         elif ch == ord('\t'):
 | |
|             self.__all_page[self.__page_index].select_next()
 | |
|         elif ch == ord('w'):
 | |
|             pagename = self.__all_page[self.__page_index].title()
 | |
|             appname = oceanbase.app
 | |
|             filename = "%s_%s.dooba.win.bz2" % (appname, pagename)
 | |
|             tmpf = tempfile.TemporaryFile()
 | |
|             self.stdscr.putwin(tmpf);
 | |
|             tmpf.seek(0)
 | |
|             f = bz2.BZ2File(filename, "w")
 | |
|             f.write(tmpf.read())
 | |
|             f.close()
 | |
|             tmpf.close()
 | |
|             MessageBox(self.stdscr, "[ INFO ] save screen to %s done!" % filename).run(anykey=True)
 | |
|         #what is this ?
 | |
|         elif ch == ord('p'):
 | |
|             MessageBox(self.stdscr, "[TEST] illegal").run()
 | |
|         elif ch == ord('z'):
 | |
|             items = [('check1  12344', False), ('check2 1', True), ('check3 124328432431', False)]
 | |
|             CheckBox('Test check box', items, self.stdscr).run()
 | |
| #       elif ch == ord('i'):
 | |
| #           result = InputBox(self.stdscr).run()
 | |
| #           MessageBox(self.stdscr, "[TEST] %s" % result).run(anykey=True)
 | |
|         elif ch == ord('C'):
 | |
|             pass
 | |
| 
 | |
|         elif ch == ord('c'):
 | |
|             self.__select_cluster()
 | |
|         elif ch == ord("t"):
 | |
|             PopPad("Abbreviation", [], self.stdscr).run()
 | |
|         self.__all_page[self.__page_index].process_key(ch)
 | |
| 
 | |
|     def __run(self):
 | |
|         while (1):
 | |
|             self.stdscr.erase()
 | |
| 
 | |
|             self.help_w.redraw()
 | |
| 
 | |
|             DEBUG(self.__run, "page __all_page[%s] redraw" % self.__page_index, self.__all_page[self.__page_index])
 | |
|             self.__all_page[self.__page_index].redraw()
 | |
|             self.stat_w.redraw()
 | |
| 
 | |
|             if (curses.is_term_resized(self.maxy, self.maxx)):
 | |
|                 self.__resize_term()
 | |
|             if self.__do_key():
 | |
|                 break
 | |
| 
 | |
|             self.stdscr.refresh()
 | |
|             sleep(0.05)
 | |
| 
 | |
|     def __select_cluster(self):
 | |
|         DEBUG(self.__select_cluster,"oceanbase.tenant: %s" % (len(oceanbase.tenant)),"")
 | |
|         if len(oceanbase.tenant) <= 1:
 | |
|             idx = 0
 | |
|         else:
 | |
|             DEBUG(self.__select_cluster, "tnt.selected", [tnt.selected for tnt in oceanbase.tenant])
 | |
|             idx = SelectionBox("Select Tenant", [ "[%s] %s " % ("*" if tnt.selected else " ", tnt.tenant_name) for tnt in oceanbase.tenant], self.stdscr).run()
 | |
|             if True == oceanbase.tenant[idx].selected:
 | |
|                 pass
 | |
|             else:
 | |
|                 tid = oceanbase.tenant[idx].tenant_id
 | |
|                 oceanbase.set_current_tenant(tid)
 | |
| 
 | |
|                 if f_data_log != '':
 | |
|                     if not check_datalog(Options.datalog, tid):
 | |
|                         print "fail to write datalog [%s]" % (Options.datalog)
 | |
| 
 | |
|                 oceanbase.switch_tenant(tid)
 | |
|                 DEBUG(self.__select_cluster, "global oceanbase", oceanbase)
 | |
|                 DEBUG(self.__select_cluster, "oceanbase.tenant", oceanbase.tenant[idx])
 | |
|                 DEBUG(self.__select_cluster, "oceanbase.tenant[idx]", oceanbase.tenant[idx].selected)
 | |
|                 DEBUG(self.__select_cluster, "oceanbase.get_current_tenant()", oceanbase.get_current_tenant())
 | |
|                 for page in self.__all_page:
 | |
|                     page.cur_tenant_id = tid
 | |
|                     page.update()
 | |
|                 DEBUG(self.__select_cluster, "page.cur_tenant_id", [" ".join([str(page.title()), page.cur_tenant_id]) for page in self.__all_page])
 | |
| 
 | |
|     def __show_logo(self):
 | |
|         self.stdscr.hline(7, 0, curses.ACS_HLINE, 1024, curses.A_BOLD | curses.color_pair(1))
 | |
|         self.stdscr.refresh()
 | |
|         oceanbase_width = max([len(line) for line in self.build_oceanbase().split('\n')])
 | |
|         oceanbase_height = len(self.build_oceanbase().split('\n'))
 | |
|         ob_win = curses.newwin(oceanbase_height + 1, oceanbase_width + 1, 0, 10)
 | |
|         ob_win.addstr(self.build_oceanbase(), curses.A_BOLD | curses.color_pair(1))
 | |
|         ob_win.refresh()
 | |
| 
 | |
|         dooba_width = max([len(line) for line in self.build_dooba().split('\n')])
 | |
|         dooba_height = len(self.build_dooba().split('\n'))
 | |
|         dooba_win = curses.newwin(dooba_height + 1, dooba_width + 1, 0, self.maxx - dooba_width - 10)
 | |
|         dooba_win.addstr(self.build_dooba(), curses.A_BOLD | curses.color_pair(6))
 | |
|         dooba_win.refresh()
 | |
| 
 | |
|     def __cowsay(self, saying):
 | |
|         cowsay = str(Cowsay(saying))
 | |
|         cowsay_width = max([len(line) for line in cowsay.split('\n')])
 | |
|         cowsay_height = len(cowsay.split('\n'))
 | |
|         try:
 | |
|             cowsay_win = curses.newwin(cowsay_height + 1, cowsay_width + 1,
 | |
|                                    self.maxy - cowsay_height - 2, self.maxx - cowsay_width - 10)
 | |
|             cowsay_win.addstr(cowsay, curses.color_pair(3))
 | |
|             cowsay_win.refresh()
 | |
|             self.__cowsay_win = cowsay_win
 | |
|         except curses.error:
 | |
|             pass
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
|     def __update_lms(self):
 | |
|         return oceanbase.check_lms(self.__cowsay)
 | |
| 
 | |
| 
 | |
| 
 | |
|     def __run_show_win_file(self):
 | |
|         self.stdscr.erase()
 | |
|         bzfh = bz2.BZ2File(Options.show_win_file)
 | |
|         fh = tempfile.TemporaryFile()
 | |
|         fh.write(bzfh.read())
 | |
|         fh.seek(0)
 | |
|         bzfh.close()
 | |
|         self.stdscr = curses.getwin(fh)
 | |
|         self.stdscr.nodelay(0)
 | |
|         self.stdscr.notimeout(1)
 | |
|         fh.close()
 | |
|         ch = self.stdscr.getch()
 | |
|         curses.endwin()
 | |
|         exit(0)
 | |
| 
 | |
|     def __init__(self, win):
 | |
|         DEBUG(self.__init__, "Dooba.__init__(win='%s') " % win, "")
 | |
|         self.__all_page = []
 | |
|         self.__page_index = 2
 | |
| 
 | |
|         self.__init_curses(win)
 | |
|         minx = 80
 | |
|         if self.maxx < minx or self.maxy < 20:
 | |
|             MessageBox(self.stdscr,
 | |
|                        "[ ERROR ] %dx%d is tooooo smalllll! %dx20 is at least..." % (self.maxx, self.maxy, minx)).run(anykey=True)
 | |
|             return
 | |
|         self.__select_cluster()
 | |
| 
 | |
|         oceanbase.set_current_tenant('1')
 | |
|         oceanbase.update_tenant_info()
 | |
|         oceanbase.start()
 | |
|         self.__show_logo()
 | |
| 
 | |
| 
 | |
|         self.stat_w = StatusWidget(self.stdscr)
 | |
|         self.help_w = HeaderWidget(self.stdscr)
 | |
| 
 | |
|         self.__all_page.append(FalloutPage(2, 0, self.maxy - 4, self.maxx, self.stdscr))      # 0
 | |
|         self.__all_page.append(HelpPage(2, 0, self.maxy - 4, self.maxx, self.stdscr))         # 1
 | |
|         self.__all_page.append(GalleryPage(2, 0, self.maxy - 4, self.maxx, self.stdscr))      # 2
 | |
|         self.__all_page.append(SQLPage(2, 0, self.maxy - 4, self.maxx, self.stdscr))          # 3
 | |
|         self.__all_page.append(TableApiPage(2, 0, self.maxy - 4, self.maxx, self.stdscr))     # 4
 | |
|         self.__all_page.append(HistoryPage(2, 0, self.maxy - 4, self.maxx, self.stdscr))      # 5
 | |
|         self.__all_page.append(BianquePage(2, 0, self.maxy - 4, self.maxx, self.stdscr))      # 6
 | |
|         self.__all_page.append(MachineStatPage(2, 0, self.maxy-4, self.maxx, self.stdscr))    # 7
 | |
|         self.__all_page.append(BlankPage(2, 0, self.maxy - 4, self.maxx, self.stdscr))        # 8
 | |
|         self.__all_page.append(BlankPage(2, 0, self.maxy - 4, self.maxx, self.stdscr))        # 9
 | |
|         self.__run()
 | |
| 
 | |
| 
 | |
| class DoobaMain(object):
 | |
|     '''NAME
 | |
|         dooba - A curses powerful tool for oceanbase admin, more than a monitor
 | |
| 
 | |
| SYNOPSIS
 | |
|         dooba [OPTIONS]
 | |
| 
 | |
| Options
 | |
| 
 | |
|     ·   --host=HOST, -h HOST
 | |
| 
 | |
|         Connect to oceanbase on the given host.
 | |
| 
 | |
|     ·   --port=PORT, -P PORT
 | |
| 
 | |
|         The TCP/IP port to use for connecting to oceanbase server.
 | |
| 
 | |
|     ·   --user=USER, -u USER
 | |
| 
 | |
|         The user to use for connecting to oceanbase server.
 | |
| 
 | |
|     ·   --password=PASSWORD, -p PASSWORD
 | |
| 
 | |
|         The password to use for connecting to oceanbase server.
 | |
|     '''
 | |
| 
 | |
|     def __usage(self):
 | |
|         print('Usage: dooba [-h|--host=HOST] [-P|--port=PORT]')
 | |
|         print('Usage: dooba [--dataid=DATAID]')
 | |
|         print('Usage: dooba --show dooba_win_file')
 | |
| 
 | |
| 
 | |
|     def __set_env(self):
 | |
|         setlocale(LC_ALL, "en_US.UTF-8")
 | |
|         environ['TERM'] = 'xterm'
 | |
| 
 | |
| 
 | |
| 
 | |
|     def __parse_options(self):
 | |
|         try:
 | |
|             opts, args = getopt(sys.argv[1:], '?dh:i:I:p:P:su:D',
 | |
|                                 ['debug', 'help', 'host=', 'interval=', 'port=',
 | |
|                                  'password=', 'supermode', 'user=', 'dataid=',
 | |
|                                  'online', 'offline', 'machine-interval=', 'degradation',
 | |
|                                  'show=', 'daemon', 'http', 'start', 'stop', 'restart',
 | |
|                                  'http-port=', 'database','datalog='])
 | |
|         except GetoptError as err:
 | |
|             print str(err) # will print something like "option -a not recognized"
 | |
|             self.__usage()
 | |
|             exit(2)
 | |
|         for o, v in opts:
 | |
|             if o in ('-?', '--help'):
 | |
|                 print self.__doc__
 | |
|                 exit(1)
 | |
|             if o in ('-d', '--debug'):
 | |
|                 Options.debug = True
 | |
|             elif o in ('-h', '--host'):
 | |
|                 Options.host = v
 | |
|                 Options.using_ip_port = True
 | |
|             elif o in ('-P', '--port'):
 | |
|                 Options.port = int(v)
 | |
|                 Options.using_ip_port = True
 | |
|             elif o in ('-u', '--user'):
 | |
|                 Options.user = v
 | |
|             elif o in ('-p', '--password'):
 | |
|                 Options.password = v
 | |
|             elif o in ('-s', '--supermode'):
 | |
|                 Options.supermode = True
 | |
|             elif o in ('-i', '--interval'):
 | |
|                 Options.interval = float(v)
 | |
|             elif o in ('-I', '--machine-interval'):
 | |
|                 Options.machine_interval = float(v)
 | |
|             elif o in ('--dataid'):
 | |
|                 Options.dataid = v
 | |
|             elif o in ('--online'):
 | |
|                 Options.env = 'online'
 | |
|             elif o in ('--offline'):
 | |
|                 Options.env = 'offline'
 | |
|             elif o in ('-D', '--degradation'):
 | |
|                 Options.degradation = True
 | |
|             elif o in ('--show'):
 | |
|                 Options.show_win_file = v
 | |
|             elif o in ('--http'):
 | |
|                 Options.http = True
 | |
|             elif o in ('--start'):
 | |
|                 Options.daemon_action = 'start'
 | |
|             elif o in ('--stop'):
 | |
|                 Options.daemon_action = 'stop'
 | |
|             elif o in ('--restart'):
 | |
|                 Options.daemon_action = 'restart'
 | |
|             elif o in ('--daemon'):
 | |
|                 Options.daemon = True
 | |
|             elif o in ('--http-port'):
 | |
|                 Options.http_port = int(v)
 | |
|             elif o in ('--database'):
 | |
|                 Options.database = v
 | |
|             elif o in ('--datalog'):
 | |
|                 if not check_datalog(v) :
 | |
|                     assert False, 'invalid datalog filename [%s]' % (v)
 | |
| 
 | |
|                 Options.datalog = v
 | |
|             else:
 | |
|                 assert False, 'unhandled option [%s]' % ( o )
 | |
|         return args
 | |
| 
 | |
|     def __ignore_signal(self):
 | |
|         def signal_handler(signal, frame):
 | |
|             pass
 | |
|         signal.signal(signal.SIGINT, signal_handler)
 | |
| 
 | |
|     def __myprint(self, info):
 | |
|         print info
 | |
|         print
 | |
|         self.__usage()
 | |
| 
 | |
|     def __init__(self):
 | |
|         global oceanbase
 | |
|         self.__set_env()
 | |
| 
 | |
|         if "print-config" in self.__parse_options():
 | |
|             print "".join(ObConfigHelper().get_config(Options.dataid))
 | |
|             ObConfigHelper().get_dataid_list()
 | |
|             exit(0)
 | |
| 
 | |
|         if not Options.show_win_file:
 | |
|             oceanbase = oceanbase(Options.dataid)
 | |
|             if Options.using_ip_port:
 | |
|                 oceanbase.test_alive(do_false=self.__myprint)
 | |
| 
 | |
|         if Options.http:
 | |
|             pid_file = '/tmp/dooba.%d.pid' % Options.http_port
 | |
|             if Options.daemon:
 | |
|                 if Options.daemon_action == 'start':
 | |
|                     HTTPServerDaemon(pid_file).start()
 | |
|                 elif Options.daemon_action == 'stop':
 | |
|                     HTTPServerDaemon(pid_file).stop()
 | |
|                 elif Options.daemon_action == 'restart':
 | |
|                     HTTPServerDaemon(pid_file).restart()
 | |
|             else:
 | |
|                 try:
 | |
|                     HTTPServerDaemon(pid_file).run()
 | |
|                 except KeyboardInterrupt:
 | |
|                     pass
 | |
|         else:
 | |
|             try:
 | |
|                 curses.wrapper(Dooba)
 | |
|             except KeyboardInterrupt:
 | |
|                 pass
 | |
| 
 | |
| 
 | |
| class HTTPServerDaemon(Daemon):
 | |
|     def run(self):
 | |
|         #oceanbase.update_cluster_info()
 | |
|         oceanbase.update_tenant_info()
 | |
|         oceanbase.start()
 | |
|         server = BaseHTTPServer.HTTPServer(('', Options.http_port), WebRequestHandler)
 | |
|         server.serve_forever()
 | |
| 
 | |
| 
 | |
| class JSONDateTimeEncoder(json.JSONEncoder):
 | |
|     def default(self, obj):
 | |
|         if isinstance(obj, (date, datetime)):
 | |
|             return obj.isoformat()
 | |
|         elif isinstance(obj, (timedelta)):
 | |
|             return 'NULL'
 | |
|         else:
 | |
|             return json.JSONEncoder.default(self, obj)
 | |
| 
 | |
| 
 | |
| class WebRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
 | |
|     def do_GET(self):
 | |
|         sample = oceanbase.now()
 | |
|         self.wfile.write('HTTP/1.1 200 OK\nContent-Type: text/html\n\n')
 | |
|         self.wfile.write(json.dumps(sample, cls=JSONDateTimeEncoder))
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     DoobaMain()
 | |
| #
 | |
| # dooba ends here
 | 
