def reset(cleartime, starttime, server): if check.nullCheck(cleartime): raise Exception("清档时间不能为空") if check.nullCheck(starttime): raise Exception("开服时间不能为空") if check.nullCheck(server): raise Exception("游戏服不能为空") if not check.checkDatetime(cleartime): raise Exception("清档时间格式不正确") if not check.checkDatetime(starttime): raise Exception("开服时间格式不正确") backstageIp = gameOption("backstage") backstageDb = gameOption("backstage_db") head_tag = gameOption("backstage_tag") ismobile = gameOption("is_mobile", type="bool") if ismobile: partnersType = 2 else: partnersType = 1 serverinfo = serverlist.serverInfo(backstageDb, head_tag, partnersType, "main", backstageIp, server) if not serverinfo["result"]: raise Exception("获取游戏服在后台的信息失败!msg:%s" % serverinfo["msg"]) ip = serverinfo["ip"] if not check.checkIp(ip): raise Exception("获取游戏服ip失败!ip:%s" % ip) global sshobj sshobj = ssh.ssh(ip) players = cmd( "pandora %s_%s -e 'select count(1) from player' | grep -v count" % (state.game, server)).strip() if players != "": if int(players) > 0: print "WARNNING: 当前角色数为%s" % players servertime = cmd("date +'%Y-%m-%d %H:%M:%S'").strip() print "servertime:", servertime servertime_datetime = datetime.datetime.strptime(servertime, "%Y-%m-%d %H:%M:%S") cleartime_datetime = datetime.datetime.strptime(cleartime, '%Y-%m-%d %H:%M:%S') if servertime_datetime + datetime.timedelta( minutes=1) > cleartime_datetime: raise Exception("服务器时间大于了清档时间,清档失败!服务器时间为:%s,清档时间提交为:%s" % (servertime, cleartime)) clearshell = gameOption("clear_script") print clearshell cmd("mkdir -p /app/opbin/%s/allinone/shell/" % state.game) sshobj.put("%s/../shell/%s" % (os.path.abspath(os.path.dirname(__file__)), clearshell), remote_path="/app/opbin/%s/allinone/shell/" % state.game) tmpfile = "/tmp/crontab_%s" % datetime.datetime.now().strftime( "%Y%m%d_%H%M%S") try: cmd("crontab -l > %s" % tmpfile) except Exception, e1: if str(e1).find("no crontab for astd") < 0: raise e1
def getUrl(self): #是否需要添加dns解析 try: if not self.bigmix: self.yx,self.quhao = self.servername.split("_") if check.nullCheck(self.server_url) or check.nullCheck(self.title): domainfile = self.curdir + "/../domain_list/all_game_domain_newserver" special_domainfile = self.curdir + "/../domain_list/special_list" urlinfo = os.popen("grep '^%s@%s_' %s %s"%(self.game,self.yx,special_domainfile,domainfile)).read() if urlinfo.strip() == "": if self.server_url == None: self.statusCheck(False,"gameurl没有指定,并且在模板中也不存在") if self.add_dns : if self.asturl == None: self.statusCheck(False,"asturl没有指定,并且在模板中也不存在") else: # gcmob@[email protected]@oversea@qianqi 1 # gcmob@[email protected]@s1.gcmob@飞流serverid服 # 如果域名在模板中存在,则使用模板中的域名进行替换,否则不替换,使用传过来的变量 urlinfoline = urlinfo.split("\n")[0].split("@") if len(urlinfoline) == 5: gameurl = urlinfoline[2] asturl = urlinfoline[3] title = urlinfoline[4] if gameurl.find("${serverid}") >= 0 : self.server_url = gameurl.replace("${serverid}",self.quhao) if asturl.find("${serverid}") >= 0 : self.asturl = asturl.replace("${serverid}",self.quhao) if title.find("${serverid}") >= 0: self.title = title.replace("${serverid}",self.quhao) if self.server_url == None or self.server_url.strip() == "": self.statusCheck(False,"获取游戏域名失败") if self.add_dns : if self.asturl == None or self.asturl.strip() == "": self.statusCheck(False,"获取ast域名失败") else: self.server_url_tag = self.asturl.replace(".aoshitang.com","") self.ast_full_url = self.server_url_tag + ".aoshitang.com" self.html.add("ast域名",self.ast_full_url) #游戏url if self.title == None or self.title.strip() == "": self.title = "%s %s"%(self.yx,self.quhao) self.html.add("游戏域名",self.server_url) self.html.add("游戏标题",self.title) self.web_url = self.web_url.replace("${server_url}",self.server_url) else: self.web_url = self.mainserver_web_url except Exception,e1: self.statusCheck(False,str(e1))
def getOption(config, language, option, type="str", default=None): '''检查配置文件的option是否存在''' if check.nullCheck(language): raise Exception("请初始化language!") checkSection(config, language) returnStr = "" if not config.has_option(language, option): #如果对应section中没有找到option则到通用的section中查找option if not config.has_option("common", option): if default != None: return default else: raise Exception("没有%s该option" % option) #return None else: if type == "bool": returnStr = config.getboolean("common", option) elif type == "int": returnStr = config.getint("common", option) elif type == "float": returnStr = config.getfloat("common", option) else: returnStr = config.get("common", option) else: if type == "bool": returnStr = config.getboolean(language, option) elif type == "int": returnStr = config.getint(language, option) elif type == "float": returnStr = config.getfloat(language, option) else: returnStr = config.get(language, option) #if re.match('.*_url',option) or option == 'title' or re.match(r'.*_url_tag',option): # returnStr = returnStr.replace("${id}",quhao) return returnStr
def getOption(config,language,option,type="str",default=None): '''检查配置文件的option是否存在''' if check.nullCheck(language): raise Exception("请初始化language!") checkSection(config,language) returnStr = "" if not config.has_option(language,option): #如果对应section中没有找到option则到通用的section中查找option if not config.has_option("common",option): if default != None: return default else: raise Exception("没有%s该option"%option) #return None else: if type == "bool": returnStr = config.getboolean("common",option) elif type == "int": returnStr = config.getint("common",option) elif type == "float": returnStr = config.getfloat("common",option) else: returnStr = config.get("common",option) else: if type == "bool": returnStr = config.getboolean(language,option) elif type == "int": returnStr = config.getint(language,option) elif type == "float": returnStr = config.getfloat(language,option) else: returnStr = config.get(language,option) #if re.match('.*_url',option) or option == 'title' or re.match(r'.*_url_tag',option): # returnStr = returnStr.replace("${id}",quhao) return returnStr
def reset(cleartime,starttime,server): if check.nullCheck(cleartime): raise Exception("清档时间不能为空") if check.nullCheck(starttime): raise Exception("开服时间不能为空") if check.nullCheck(server): raise Exception("游戏服不能为空") if not check.checkDatetime(cleartime): raise Exception("清档时间格式不正确") if not check.checkDatetime(starttime): raise Exception("开服时间格式不正确") backstageIp = gameOption("backstage") backstageDb = gameOption("backstage_db") head_tag = gameOption("backstage_tag") ismobile = gameOption("is_mobile",type="bool") if ismobile: partnersType = 2 else: partnersType = 1 serverinfo = serverlist.serverInfo(backstageDb,head_tag,partnersType,"main",backstageIp,server) if not serverinfo["result"]: raise Exception("获取游戏服在后台的信息失败!msg:%s"%serverinfo["msg"]) ip = serverinfo["ip"] if not check.checkIp(ip): raise Exception("获取游戏服ip失败!ip:%s"%ip) global sshobj sshobj = ssh.ssh(ip) players = cmd("pandora %s_%s -e 'select count(1) from player' | grep -v count"%(state.game,server)).strip() if players != "": if int(players) > 0: print "WARNNING: 当前角色数为%s"%players servertime = cmd("date +'%Y-%m-%d %H:%M:%S'").strip() print "servertime:",servertime servertime_datetime = datetime.datetime.strptime(servertime,"%Y-%m-%d %H:%M:%S") cleartime_datetime = datetime.datetime.strptime(cleartime,'%Y-%m-%d %H:%M:%S') if servertime_datetime + datetime.timedelta(minutes=1) > cleartime_datetime : raise Exception("服务器时间大于了清档时间,清档失败!服务器时间为:%s,清档时间提交为:%s"%(servertime,cleartime)) clearshell = gameOption("clear_script") print clearshell cmd("mkdir -p /app/opbin/%s/allinone/shell/"%state.game) sshobj.put("%s/../shell/%s"%(os.path.abspath(os.path.dirname(__file__)),clearshell),remote_path="/app/opbin/%s/allinone/shell/"%state.game) tmpfile = "/tmp/crontab_%s"%datetime.datetime.now().strftime("%Y%m%d_%H%M%S") try: cmd("crontab -l > %s"%tmpfile) except Exception,e1: if str(e1).find("no crontab for astd") < 0: raise e1
def getserverlist(ServerFile=None,ServerList=None,ExecludeServerList=None,StartDate=None,EndDate=None,UniqueServer=None): if ServerFile != None or ServerList != None or ExecludeServerList != None or StartDate != None or EndDate != None or UniqueServer != None: #print ServerFile,ServerList,ExecludeServerList,StartDate,EndDate,UniqueServer pass else: ServerFile = state.options.serverfile ServerList = state.options.serverlist ExecludeServerList = state.options.excludeServerlist StartDate = state.options.startdate EndDate = state.options.enddate UniqueServer = state.options.uniqserver slist = [] if not check.nullCheck(ServerFile): for i in open(ServerFile).readlines(): if i.strip() != "": if i.find("@") > 0: s = i.split("@") servername = s[0].strip() ip = s[1].strip() else: servername = i.strip() if check.checkIp(i.strip()): ip = i.strip() else: ip = state.game + "_" + i.strip() if not check.nullCheck( ServerList ): if not re.match(r"^%s$"%ServerList,servername): continue if not check.nullCheck(ExecludeServerList): if re.match("^%s$"%ExecludeServerList,servername): continue slist.append([servername,ip]) else: if gameOption("is_mobile",type="bool"): partnersType = 2 else: partnersType = 1 slist = serverlist.serverRange(gameOption("backstage_db"),gameOption("backstage_tag"),partnersType,"main",gameOption("backstage"),StartDate,EndDate,ServerList,ExecludeServerList) #print StartDate,EndDate,ServerList,ExecludeServerList serverlist_tag = [ i.strip() for i in gameOption("serverlist_tag",default="").split(",") if i.strip() != "" ] for tag in serverlist_tag: slist += serverlist.serverRange(gameOption("backstage_db"), tag, partnersType,"main",gameOption("backstage"),StartDate,EndDate,ServerList,ExecludeServerList) if UniqueServer: return list(set(i[1].strip() for i in slist)) else: return slist
def hotswap(type, keyword, backendVersion=None): global succList, errorDict succList = [] errorDict = {} game = state.game language = state.language www_ip = gameOption("www_ip") www_ssh_ip = gameOption("www_ssh_ip") www_port = gameOption("www_port", default="80") www_header = gameOption("www_header") www_root = gameOption("www_root") www_ssh = ssh.ssh(www_ssh_ip) www_hotswap_dir = "%s/%s/hotswap" % (www_root, game) www_ssh.cmd("mkdir -p " + www_hotswap_dir) if type != "update" and type != "remote": print "ERROR: 动更类型必须为update或者remote!" sys.exit(1) www_ssh.put("/app/online/%s/hotswap/%s/hotswap.zip" % (game, language), remote_path=www_hotswap_dir) ##动更包上传资源目录后删除ftp上的动更包 os.popen("rm -f /app/online/%s/hotswap/%s/hotswap.zip" % (game, language)) serverlist = getserverlist() state.servers = serverlist #state.servers = [["feiliu_10010","10.6.197.215"]] state.ignoreErrorHost = True ccthread.run(execute, type, keyword, www_ip, www_port, www_header) resultStatus = True if len(state.errorHost) > 0: print "-" * 40 + "连接失败主机" + "-" * 30 print state.errorHost resultStatus = False if len(errorDict) > 0: print "-" * 40 + "命令执行失败服务器" + "-" * 24 for i in errorDict: print "[%s] Error:%s" % (i, errorDict[i]) print "-" * 40 + "更新失败服务器汇总为" + "-" * 22 print getSpecialServerIp(state.servers, errorDict.keys()) resultStatus = False print "-" * 40 + "汇总" + "-" * 38 print "更新服务器总数: %d" % len(state.servers) print "更新失败服务器数: %d" % len(errorDict) print "更新成功服务器数: %d" % len(succList) sys.stdout.flush() if not check.nullCheck(backendVersion): print "*" * 40 + "开始上传后端..." status, out = commands.getstatusoutput( "sh /app/opbin/rundeck/online.backend -t '%s' -g '%s'" % (backendVersion, game)) print out if status != 0: print "ERROR: 后端%s上传失败!" % backendVersion resultStatus = False if not resultStatus: sys.exit(1)
def getConfig(game): if check.nullCheck(game): raise Exception("请初始化game!") config = ConfigParser.ConfigParser() dir = os.path.dirname(os.path.abspath(__file__)) path = "%s/../conf/" %dir filepath = path + game + ".conf" if not os.path.exists(filepath): raise Exception("ERROR: %s该配置文件不存在!"%game) config.read(filepath) return config
def getConfig(game): if check.nullCheck(game): raise Exception("请初始化game!") config = ConfigParser.ConfigParser() dir = os.path.dirname(os.path.abspath(__file__)) path = "%s/../conf/" % dir filepath = path + game + ".conf" if not os.path.exists(filepath): raise Exception("ERROR: %s该配置文件不存在!" % game) config.read(filepath) return config
def hotswap(type,keyword,backendVersion=None): global succList,errorDict succList = [] errorDict = {} game = state.game language = state.language www_ip = gameOption("www_ip") www_ssh_ip = gameOption("www_ssh_ip") www_port = gameOption("www_port",default="80") www_header = gameOption("www_header") www_root = gameOption("www_root") www_ssh = ssh.ssh(www_ssh_ip) www_hotswap_dir = "%s/%s/hotswap"%(www_root,game) www_ssh.cmd("mkdir -p " + www_hotswap_dir) if type != "update" and type != "remote": print "ERROR: 动更类型必须为update或者remote!" sys.exit(1) www_ssh.put("/app/online/%s/hotswap/%s/hotswap.zip"%(game,language),remote_path=www_hotswap_dir) ##动更包上传资源目录后删除ftp上的动更包 os.popen("rm -f /app/online/%s/hotswap/%s/hotswap.zip"%(game,language)) serverlist = getserverlist() state.servers = serverlist #state.servers = [["feiliu_10010","10.6.197.215"]] state.ignoreErrorHost = True ccthread.run(execute,type,keyword,www_ip,www_port,www_header) resultStatus = True if len(state.errorHost) > 0: print "-"*40 + "连接失败主机" + "-"*30 print state.errorHost resultStatus = False if len(errorDict) > 0: print "-"*40 + "命令执行失败服务器" + "-"*24 for i in errorDict: print "[%s] Error:%s"%(i,errorDict[i]) print "-"*40 + "更新失败服务器汇总为" + "-"*22 print getSpecialServerIp(state.servers,errorDict.keys()) resultStatus = False print "-"*40 + "汇总" + "-"*38 print "更新服务器总数: %d"%len(state.servers) print "更新失败服务器数: %d" %len(errorDict) print "更新成功服务器数: %d" %len(succList) sys.stdout.flush() if not check.nullCheck(backendVersion): print "*" * 40 + "开始上传后端..." status,out = commands.getstatusoutput("sh /app/opbin/rundeck/online.backend -t '%s' -g '%s'"%(backendVersion,game)) print out if status != 0: print "ERROR: 后端%s上传失败!"%backendVersion resultStatus = False if not resultStatus: sys.exit(1)
def __init__(self,game,language,servername,ip=None,port=22,mainServername=None): #logging.basicConfig(level=logging.INFO, # format='%(asctime)s %(levelname)s %(message)s', # datefmt='%Y-%m-%d %H:%M:%S', # ) self.game = game self.language = language self.servername = servername self.ip = ip self.rootDir = mainOption("rootdir").replace("${game}",game) self.commonPath = "newserver/%s/common"%language self.templatePath = "newserver/%s/template"%language self.propertiesPath = "newserver/%s/properties"%language self.wwwPath = "newserver/%s/www"%language self.yx,self.quhao = getYxNum(servername) if not check.nullCheck(mainServername): self.mainServer = game + "_" + mainServername else: self.mainServer = None if not check.checkServer(str(servername)): print "请输入正确的游戏服名称" #logging.error("请输入正确的游戏服名称") sys.exit(1) #if not check.checkIp(str(ip)): if ip == None: backstage_db = gameOption("backstage_db") backstage_tag = gameOption("backstage_tag") is_mobile = gameOption("is_mobile",type="bool") if is_mobile: partnersType = 2 else: partnersType = 1 backstage_ip = gameOption("backstage") print backstage_db,backstage_tag,partnersType,"mix",backstage_ip,servername serverList = serverlist.serverRange(backstage_db,backstage_tag,partnersType,"mix",backstage_ip,serverlist=servername) if len(serverList) != 1: print "ERROR: 获取服务器ip失败或者不唯一",serverList sys.exit(1) else: self.ip = serverList[0][1] self.ssh = ssh.ssh(self.ip,port=port) self.www_dir_type = gameOption("www_dir_type") www_ip = gameOption("www_ip") www_ssh_ip = gameOption("www_ssh_ip") www_port = gameOption("www_port",default="80") www_ssh_port = gameOption("www_ssh_port",default="22") self.www_root = gameOption("www_root") self.template_tar_dir = gameOption("template_tar_dir").replace(" ","").split(",") self.template_exclude_dir = gameOption("template_exclude_dir").replace(" ","").split(",") self.www_ssh = ssh.ssh(www_ssh_ip,port=int(www_ssh_port))
def init(self): self.mainserverYx,self.mainserverQuhao = self.mainserver.split("_") self.htmlStatus = True curdir = os.path.dirname(os.path.abspath(__file__)) self.curdir = curdir logdir = curdir +"/../logs" if not os.path.exists(logdir): os.makedirs(logdir) game = self.game servername = self.servername language = self.language nowstring = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S', #filename='%s/mix_%s_%s.log'%(os.path.abspath(logdir),game,self.mainserver), #filemode='a' ) logging.info("开始部署游戏...") self.html = mailhtml.mailhtml("mix_%s_%s_%s_deploy.html"%(game,self.mainserver,nowstring),"%s_%s游戏混服部署"%(game,self.mainserver)) self.rootDir = mainOption("rootdir").replace("${game}",game) self.email_address = gameOption("email_address") self.mail_title = "[%s][%s]游戏服部署"%(game,servername) if len(self.mail_title) > 50: self.mail_title = self.mail_title[0:47] + "..." self.html.add("游戏混服名称",servername.replace(",","<br>")) self.htmlStatus = True try: self.clientrootdir = mainOption("clientrootdir").replace("${game}",game) self.rootdir = mainOption("rootdir").replace("${game}",game) #是否为大混服 self.bigmix = gameOption("big_mix_server",type = "bool") if self.bigmix: self.html.add("混服类型","大混服") else: self.html.add("混服类型","混服") #参数校验 self.sList = [ i.strip() for i in self.servername.split(",") if i.strip() != "" ] if self.bigmix: for i in self.sList: self.statusCheck(check.checkServer(i),"游戏名称:%s 不合法"%i) else: self.statusCheck(check.checkServer(self.servername),"游戏名称:%s 不合法"%self.servername) #后台相关信息 self.backstage = gameOption("backstage") self.backstage_db = gameOption("backstage_db") self.backstage_tag = gameOption("backstage_tag") self.backstage_interface_url = gameOption("backstage_interface_url") self.backstage_header = gameOption("backstage_header") self.have_backstage_interface = gameOption("have_backstage_interface",type="bool") #游戏服务器需要下载资源的地址信息 self.www_ip = gameOption("www_ip") self.www_port = gameOption("www_port",default="80") self.www_header = gameOption("www_header") #是否为海外 self.is_oversea = gameOption("is_oversea",type="bool") #是否为手游 if gameOption("is_mobile",type="bool"): self.partnersType = 2 self.is_mobile = "mobile" else: self.is_mobile = "web" self.partnersType = 1 if self.skipcheck: serverExistsJson = json.loads(serverlist.serverListExists(self.backstage_db,self.backstage_tag,self.partnersType,servername,self.backstage)) if serverExistsJson["result"]: self.statusCheck(False,"游戏已经存在,请确认") #获取主服的信息 #print self.backstage_db,self.backstage_tag,self.partnersType,"main",self.backstage,self.mainserver serverinfo = serverlist.serverInfo(self.backstage_db,self.backstage_tag,self.partnersType,"main",self.backstage,self.mainserver) logging.info(serverinfo) if not serverinfo["result"]: self.statusCheck(False,"主服信息获取失败,err:%s"%serverinfo["msg"]) self.ip = serverinfo["ip"] self.statusCheck(check.checkIp(self.ip),"ip:%s不合法"%self.ip) if check.nullCheck(self.starttime): self.starttime = serverinfo["starttime"] self.statusCheck(check.checkDatetime(self.starttime),"开服时间:%s 不合法"%self.starttime) self.mainserver_web_url = serverinfo["web_url"] self.html.add("服务器ip",self.ip) logging.info("%s建立ssh连接..."%self.ip) self.ssh = ssh.ssh(self.ip) logging.info("%s建立ssh连接完毕!"%self.ip) self.time_zone = gameOption("time_zone","+8") delta_hours = 8 - int(self.time_zone) self.cleartime = (datetime.datetime.strptime(self.starttime,"%Y-%m-%d %H:%M:%S") - datetime.timedelta(hours=delta_hours) - datetime.timedelta(minutes=30)).strftime("%Y-%m-%d %H:%M:%S") self.html.add("开服时间(北京+8区)",self.starttime) self.html.add("清档时间(服务器%s区)"%self.time_zone,self.cleartime) #www是老模式(www)还是新模式(www_ly_id) self.www_dir_type = gameOption("www_dir_type") #是否添加ast域名解析 self.add_dns = gameOption("add_dns",type="bool") #是否需要联运解析域名 self.lianyun_add_dns = gameOption("lianyun_add_dns",type="bool") #后台游戏域名,后续会替换server_url self.web_url = gameOption("web_url") #混服部署脚本 self.mix_deploy_script = gameOption("mix_deploy_script") #特殊联运修改脚本 self.special_script = gameOption("deploy_special_script",default="") #特殊联运修改脚本(local) self.special_script_local = gameOption("deploy_special_script_local",default="") #dns game self.dns_game = gameOption("dns_game",default=self.game) logging.info("变量初始化完毕") except Exception,e1: self.statusCheck(False,str(e1))
def checkArg(str,info): '''检查参数是否为空''' if check.nullCheck(str) : raise Exception(info)
def getserverlist(ServerFile=None, ServerList=None, ExecludeServerList=None, StartDate=None, EndDate=None, UniqueServer=None): if ServerFile != None or ServerList != None or ExecludeServerList != None or StartDate != None or EndDate != None or UniqueServer != None: #print ServerFile,ServerList,ExecludeServerList,StartDate,EndDate,UniqueServer pass else: ServerFile = state.options.serverfile ServerList = state.options.serverlist ExecludeServerList = state.options.excludeServerlist StartDate = state.options.startdate EndDate = state.options.enddate UniqueServer = state.options.uniqserver slist = [] if not check.nullCheck(ServerFile): for i in open(ServerFile).readlines(): if i.strip() != "": if i.find("@") > 0: s = i.split("@") servername = s[0].strip() ip = s[1].strip() else: servername = i.strip() if check.checkIp(i.strip()): ip = i.strip() else: ip = state.game + "_" + i.strip() if not check.nullCheck(ServerList): if not re.match(r"^%s$" % ServerList, servername): continue if not check.nullCheck(ExecludeServerList): if re.match("^%s$" % ExecludeServerList, servername): continue slist.append([servername, ip]) else: if gameOption("is_mobile", type="bool"): partnersType = 2 else: partnersType = 1 slist = serverlist.serverRange(gameOption("backstage_db"), gameOption("backstage_tag"), partnersType, "main", gameOption("backstage"), StartDate, EndDate, ServerList, ExecludeServerList) #print StartDate,EndDate,ServerList,ExecludeServerList serverlist_tag = [ i.strip() for i in gameOption("serverlist_tag", default="").split(",") if i.strip() != "" ] for tag in serverlist_tag: slist += serverlist.serverRange(gameOption("backstage_db"), tag, partnersType, "main", gameOption("backstage"), StartDate, EndDate, ServerList, ExecludeServerList) if UniqueServer: return list(set(i[1].strip() for i in slist)) else: return slist
def checkArg(str, info): '''检查参数是否为空''' if check.nullCheck(str): raise Exception(info)