#!/usr/bin/python # -*- coding:utf-8 _*- # python wjtx.py createconfig -f game1130.xlsx # python wjtx.py addproject -f game1130.xlsx # python wjtx.py initdb -s 310-315 # python wjtx.py changestatus -m maintain -o remove -s 295-300 # python wjtx.py autoload import click import json import redis import xlrd from ops.mmysql import MysqlBase import logging import datetime from ops.common import run_cmd from ops.plog import define_logger from ops.mansible import AnsiInterface, write_host import time import uuid import os Global_redis_1009 = {"host": "10.10.6.4", "port": "6379", "db": 0} Global_redis_1012 = {"host": "10.10.6.6", "port": "6379", "db": 0} Ywplatform_db = {"host": '10.10.3.5', "user": "root", "pswd": "0usmUwROtWjf", "port": 3306} Legend_db = {"host": '10.10.6.2', "user": "wjtx", "pswd": "mMWA4DKCfeOL", "port": 3306} rule = {"union": 1000, "huawei": 2000, "xiaomi": 3000, "oppo": 4000} Methods_values = {"hide": 3, "new": 1, "hot": 2, "maintain": 0} define_logger(filename="/data/logs/wjtx_tools.log") log = logging.getLogger(__name__) @click.group() def main(): pass @main.command() @click.option('-g', '--gameid', type=click.Choice(['1009', '1012']), default='1009', help='gameid', required=True) @click.option('-s', '--serverid', type=int, help='serverid', required=True) @click.option('-t', '--times', type=str, help='重置开服的时间', required=True) def changeservertime(times, gameid, serverid): wjtx = Wjtx_tools(gameid) wjtx.change_server_opentime(serverid, times) @main.command() @click.option('-g', '--gameid', type=click.Choice(['1009', '1012']), default='1009', help='gameid') @click.option('-s', '--serverid', type=str, help='serverid', required=True) def initdb(gameid, serverid): wjtx = Wjtx_tools(gameid) wjtx.init_wjtx_mysql(serverid) @main.command() @click.option('-g', '--gameid', type=click.Choice(['1009', '1012']), default='1009', help='gameid', required=True) def createhostlist(gameid): wjtx = Wjtx_tools(gameid) wjtx.create_alive_host() @main.command() @click.option('-g', '--gameid', type=click.Choice(['1009', '1012']), default='1009', help='gameid', required=True) def autoload(gameid): wjtx = Wjtx_tools(gameid) wjtx.ops_autoload() @main.command() @click.option('-g', '--gameid', type=click.Choice(['1009', '1012']), default='1009', help='gameid', required=True) @click.option('-f', '--filename', type=str, help='脚本路径', required=True) def addproject(gameid, filename): wjtx = Wjtx_tools(gameid) wjtx.add_ops_projectmanage(filename) @main.command() @click.option('-g', '--gameid', type=click.Choice(['1009', '1012']), default='1009', help='gameid', required=True) @click.option('-f', '--filename', type=str, help='脚本路径', required=True) def createconfig(gameid, filename): wjtx = Wjtx_tools(gameid) wjtx.create_config(filename) @main.command() @click.option('-g', '--gameid', type=click.Choice(['1009', '1012']), default='1009', help='gameid', required=True) @click.option('-s', '--serverid', type=str, help='操作的serverids', required=True) @click.option('-m', '--method', default='maintain', required=True, type=click.Choice(['maintain', 'hide', 'new', 'hot']), help='维护、隐藏、新服、热点') @click.option('-o', '--operate', help='操作方法 add/remove', default='add', required=True, type=click.Choice(['add', 'remove'])) def changestatus(gameid, method, operate, serverid): wjtx = Wjtx_tools(gameid) wjtx.change_server_status(serverid, method, operate) class Wjtx_tools: def __init__(self, gameid): self.gameid = gameid if self.gameid == '1009': self.redis_conn = redis.Redis(host=Global_redis_1009['host'], port=Global_redis_1009['port'], charset='utf8', db=Global_redis_1009.get('db') or 0, decode_responses=True) elif self.gameid == '1012': self.redis_conn = redis.Redis(host=Global_redis_1012['host'], port=Global_redis_1012['port'], charset='utf8', db=Global_redis_1012.get('db') or 0, decode_responses=True) else: log.error(f"gameid={self.gameid} not in define!") raise Exception(f"gameid={self.gameid} not in define!") def create_alive_host(self): hosts = list() data = self.redis_conn.hgetall('game_info') for line in data.values(): recode = json.loads(line) if (int(recode['areaId']) % 100 + 9000) == int(recode['tcpPort']) and recode['status'] == 1: hosts.append(recode['externalIp']) hosts = list(set(hosts)) hosts.sort() filename = "" if self.gameid == "1009": filename = "wjtx_1009.host" elif self.gameid == "1012": filename = "wjtx_1012.host" if hosts: log.info(f"write hosts with {filename}") with open(filename, 'w') as f: f.write('\n'.join(hosts)) else: log.error("get host from wjtx redis failed!") def create_config(self, filename): n_cols = ["ptname", "serverid", "ip", "port", "port_2", "redis_port", "servername"] cols_str = ["serverid", "port", "port_2", "redis_port"] cols_unicode = ["servername"] data = self._read_excel(filename) for i in range(0, len(data)): if data[i][0]: temp = {} for j in range(0, len(n_cols)): if n_cols[j] in cols_unicode: temp[n_cols[j]] = json.dumps(data[i][j])[1:-1] elif n_cols[j] in cols_str: temp[n_cols[j]] = str(int(data[i][j])) else: temp[n_cols[j]] = data[i][j] self._build_wjtx_config(temp) def _build_wjtx_config(self, data): for server_type in ['game', 'stage']: if server_type == "stage": data['port'] = str(int(data['port']) - 2000) template_file = f"{server_type}_{self.gameid}.sample" with open(template_file, 'r') as f: templates = f.read() try: new = templates.format(**data) except Exception: raise Exception(f"fill {data} failed!") # config_path=fr"D:\ops\SVN\prod\{server_type}{self.gameid}" # filename = f"{config_path}\{server_type}server\config\conf/application-{data['serverid']}.properties" config_paths = os.sep.join( ['', 'data', 'publish', 'prod', "game" + self.gameid, server_type + 'server', 'config', 'conf']) full_name = config_paths + os.sep + \ f"application-{data['serverid']}.properties" log.info(f"write config with {full_name}") if not os.path.isdir(config_paths): os.makedirs(config_paths) with open(full_name, 'w') as f: f.write(new) def change_server_status(self, serverid, method, operate): serverlist = list() if len(serverid.split('-')) == 2: begin = int(serverid.split('-')[0]) end = int(serverid.split('-')[1]) + 1 for i in range(begin, end): serverlist.append(i) else: serverlist = serverid.split(",") key = "server_state" for serverid in serverlist: old = self.redis_conn.hget(key, serverid) if old == "": raise Exception(f"get serverid failed ,{serverid},{old}") if operate == 'remove': new = self._unSetBitFlag(old, Methods_values.get(method)) else: new = self._setBitFlag(old, Methods_values.get(method)) values = f"{serverid}-{new}" log.info( f"serverid={serverid} {old} {method} {operate} set to {values}") self.redis_conn.hset(key, serverid, new) self.redis_conn.publish("server_state_web_publish", values) def ops_autoload(self): alive_server = list() alive_server = self._get_alive_server() game_recode = self._get_server_info(alive_server, 'game') project_name = f'game{self.gameid}game' self._add_recode2mysql(project_name, game_recode) stage_recode = self._get_server_info(alive_server, 'stage') project_name = f'game{self.gameid}stage' self._add_recode2mysql(project_name, stage_recode) def add_ops_projectmanage(self, filename): data = self._build_excel_data(self._read_excel(filename)) ip_serverid, ip_redis = self._format_servcice_info(data) assert self._check_host(ip_serverid.keys()) assert self._check_redis(ip_redis) self._change_ops_projectmanage(ip_serverid) def change_server_opentime(self, serverid, times): Legend_db['db'] = f"legend_{serverid}" mysql_conn = MysqlBase(**Legend_db) tablename = "server_info" u_data = {'start_time': times} mysql_conn.update(tablename, u_data, True) host_info = json.loads(self.redis_conn.hget('game_info', serverid)) hostip = host_info.get('innerIp', None) assert hostip restart_cmd = f"su - kingsome -c 'cd /data/apps/game{self.gameid}game && sh restart.sh {serverid}'" hostfilename = write_host(hostip) time.sleep(10) myansible = AnsiInterface(hostfilename) resule = myansible.exec_command(restart_cmd) if not (resule['failed'] or resule['unreachable']): log.info(f"restart {serverid} success!") else: log.error(f"restart {serverid} failed,output was {resule}") def init_wjtx_mysql(self, serverid): sids = list() if len(str(serverid).split("-")) == 2: begin = serverid.split('-')[0] end = int(serverid.split('-')[1]) + 1 assert begin, end for i in range(int(begin), int(end)): sids.append(i) else: sids = serverid.split(",") for sid in sids: mysql_conn = f"mysql -u{Legend_db['user']} -p{Legend_db['pswd']} -h{Legend_db['host']}" create_sql = f"create database legend_{sid} default character set utf8mb4 collate utf8mb4_unicode_ci;create database logger_{sid} default character set utf8mb4 collate utf8mb4_unicode_ci;" create_db_cmd = f"{mysql_conn} -e'{create_sql}'" status, out = run_cmd(create_db_cmd) if not status: log.error(f"create db error {out}") raise Exception(out) else: log.info(f"create db=legend_{sid},logger_{sid}") create_table_sql = f"{mysql_conn} legend_{sid} -e'source sql/wjtx_game.sql'" status, out = run_cmd(create_table_sql) if not status: log.error(f"init db error {out}") raise Exception(out) self.redis_conn.hset('game_stage', sid, sid) log.info(f"add {sid} to redis key=game_stage!") def _change_ops_projectmanage(self, ip_serverid): Ywplatform_db['db'] = 'ywplatform' ywplatform = MysqlBase(**Ywplatform_db) condition = "" services = list() if self.gameid == "1009": condition = f"env='prod' and project_name in ('game1009game','game1009stage','game1009conf')" services = ['game1009game', 'game1009stage', 'game1009conf'] elif self.gameid == "1012": condition = f"env='prod' and project_name in ('game1012game','game1012stage','game1012conf')" services = ['game1012game', 'game1012stage', 'game1012conf'] remark = {"remark": 1} ywplatform.update('deploy_projectmanage', remark, condition) for service in services: get_service_conf_sql = f"""SELECT project_address, config_address FROM deploy_projectmanage WHERE project_name = '{service}' AND env = 'prod' LIMIT 1;""" service_conf = ywplatform.query(get_service_conf_sql) if not service_conf: log.error( f"get service={service} from deploy_projectmanage failed!") raise Exception( f"get service={service} from deploy_projectmanage failed!") project_address, config_address = service_conf[0] for ip in ip_serverid.keys(): check_sql = f"""SELECT run_server, run_script FROM `deploy_projectmanage` WHERE project_name = '{service}' AND env = 'prod' AND run_server = '{ip}';""" data = ywplatform.query(check_sql) if not data: temp = {} temp['sid'] = uuid.uuid4().hex temp['project_name'] = service temp['compile_script'] = 'boundle.sh' temp['run_script'] = f'sh restart.sh {ip_serverid[ip]}' temp['env'] = 'prod' temp['run_server'] = f'{ip}' temp['remark'] = '0' temp['update_time'] = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S") temp['create_time'] = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S") temp['user_id'] = '4' temp['port'] = 7000 temp['reload_script'] = 'sh reload.sh' temp['res_address'] = '' temp['res_reload_script'] = 'sh reloadres.sh' temp['is_monitor'] = '1' temp['is_tmp'] = '0' temp['region'] = '' temp['is_scaling'] = '0' temp['project_address'] = project_address temp['config_address'] = config_address log.info(f"add recode with {service} {temp['run_server']}") ywplatform.insert('deploy_projectmanage', temp) else: log.error(f"{ip} {service} was in db!") def _check_host(self, ips): for key in ips: cmd = f"ping {key} -c 1 -s 1 -W 1 | grep '100% packet loss'|wc -l" status, out = run_cmd(cmd) if status and out.decode().strip() == '0': pass else: return False print(f"check ip with {ips} success!") return True def _check_redis(self, ip_redis): for key in ip_redis: for port in ip_redis[key].split(','): try: _ = redis.Redis(host=key, port=port, charset='utf8') except: return False print(f"check redis {ip_redis} success!") return True def _format_servcice_info(self, data): ip_serverid = dict() ip_redis = dict() for line in data: if ip_serverid.get(line['ip'], None): ip_serverid[line['ip'] ] = f"{ip_serverid[line['ip']]},{line['serverid']}" else: ip_serverid[line['ip']] = line['serverid'] if ip_redis.get(line['ip'], None): ip_redis[line['ip'] ] = f"{ip_redis[line['ip']]},{line['redis_port']}" else: ip_redis[line['ip']] = line['redis_port'] return ip_serverid, ip_redis def _build_excel_data(self, data): out_data = list() n_cols = ["ptname", "serverid", "ip", "port", "port_2", "redis_port", "servername"] cols_unicode = ["servername"] cols_str = ["serverid", "port", "port_2", "redis_port"] for i in range(0, len(data)): if data[i][0]: temp = {} for j in range(0, len(n_cols)): if n_cols[j] in cols_unicode: temp[n_cols[j]] = json.dumps(data[i][j])[1:-1] elif n_cols[j] in cols_str: temp[n_cols[j]] = str(int(data[i][j])) else: temp[n_cols[j]] = data[i][j] out_data.append(temp) return out_data # def _hasBitFlag(self, flags, bit): # return (flags & (1 << bit)) != 0 def _setBitFlag(self, flags, bit): return int(flags) | (1 << int(bit)) def _unSetBitFlag(self, flags, bit): return int(flags) & (~(1 << int(bit))) def _read_excel(self, file): try: data = xlrd.open_workbook(file) table = data.sheet_by_index(0) nrows = table.nrows ncols = table.ncols all = list() for row in range(1, nrows): excel_list = [] for col in range(ncols): cell_value = table.cell(row, col).value excel_list.append(cell_value) all.append(excel_list) return all except Exception: pass def _get_alive_server(self): alive_server = list() data = self.redis_conn.hgetall('game_info') for line in data.values(): recode = json.loads(line) if (int(recode['areaId']) % 100 + 9000) == int(recode['tcpPort']) and recode['status'] == 1: alive_server.append(recode['areaId']) servers = list(set(alive_server)) return servers def _get_server_info(self, alive_server, server_type): out_data = list() key = f"{server_type}_info" data = self.redis_conn.hgetall(key) for line in data.values(): recode = json.loads(line) if recode['areaId'] in alive_server: # if (int(recode['areaId']) % 100 + 9000) == int(recode['tcpPort']) and recode['status'] == 1: item = {} item['serverid'] = recode['areaId'] item['ip'] = recode['innerIp'] item['port'] = recode['tcpPort'] out_data.append(item) return out_data def _add_recode2mysql(self, project, data): mysql_conf = Ywplatform_db mysql_conf['db'] = 'ywplatform' mysql_conn = MysqlBase(**mysql_conf) autoload_table = 'ops_servicemonitor' int_list = ['port', 'check_item', 'match_values', 'in_use'] for line in data: temp = {} temp['project_name'] = project temp['check_type'] = 'port' temp['method'] = 'get' temp['check_item'] = 1 temp['check_data'] = "" temp['match_values'] = 1 temp['start_cmd'] = f"sh restart.sh {line['serverid']}" temp['base_dir'] = '/data/apps' temp['user'] = 'kingsome' temp['in_use'] = 1 temp['up_addr'] = line['ip'] temp['port'] = line['port'] for key in list(temp.keys()): if key in int_list: temp[key] = str(int(temp[key])) temp['serviceid'] = uuid.uuid4().hex temp['remark'] = 0 temp['region'] = "" temp['update_time'] = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S") temp['create_time'] = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S") condition = f"project_name='{temp['project_name']}' and up_addr='{temp['up_addr']}' and port='{temp['port']}'" recode_status = f"select * from {autoload_table} where {condition}" check_s = mysql_conn.query(recode_status) if not check_s: mysql_conn.insert('ops_servicemonitor', temp) log.info(f"insert {temp}") else: u_data = {'in_use': temp['in_use']} mysql_conn.update(autoload_table, u_data, condition) log.info(f"update {u_data} where {condition}") if __name__ == "__main__": main()