├── README.md ├── config ├── __init__.py └── games.py ├── config_an ├── common.yml ├── shujian_tengxun.yml ├── template.yml └── ytsy_gn.yml ├── game.py ├── game.yml ├── lib ├── ansibleapi │ ├── YunweiCallbacks.py │ ├── YunweiInventory.py │ ├── YunweiPlayBook.py │ ├── YunweiScript.py │ ├── __init__.py │ └── do.py ├── cmdbinfo │ ├── __init__.py │ └── tools.py └── public.py ├── logs └── ansiblework.log └── tasks └── setup_game ├── project └── shujian.py ├── roles └── 3_setup │ └── tasks │ ├── main.yml │ └── shujian_main.yml ├── run.py ├── site.yml └── zone.py /README.md: -------------------------------------------------------------------------------- 1 | # 游戏更新系统:opersible 2 | 3 | #### 背景(2014年) 4 | 起初的技术主要是使用shell,其实也实现了shell下的并发需求. 但是shell写起来比较费劲,很多都需要自己去实现,太复杂. 5 | 后来开始寻求运维管理系统,这才开始了踏上了ansible之路 6 | 7 | 当时有一个php的web管理后台, 不过这个后台只能用于维护游戏区服的信息(该信息保存在mysql中); 8 | 我们通过这个后台能去配置区服,查看区服列表和区服的详细信息等; 9 | 该后台没有实际的游戏更新部署能力,更新管理的事情由编写的的一些shell脚本去完成,shell脚本读取mysql拿到区服信息进行操作. 10 | 这个`mysql`库就被我们当成cmdb来使用. 11 | 12 | #### 开发与上线 13 | 开发工作是由本人这边完成的 14 | 内容有: 15 | ``` 16 | 1.重写ansible的api 17 | 2.封装读取mysql中区服信息的代码 18 | 3.编写playbook 19 | 4.结构的设计: 代码结构和实施方案 20 | ``` 21 | 22 | 这里是写成python脚本的形式, run.py是每个task的入口,只需执行run.py即可. 23 | 24 | #### 架构 25 | php后台 ---> mysql <--- opersible ---> playbook 26 | 27 | #### 系统上线情况 28 | 当前运营了十多款游戏(按平台分),也都完全成功进行了接入; 29 | 每一款游戏只需要根据模板添加对应的参数,对应的执行脚本,和对应的playbook即可. 30 | 所有的游戏也只是维护这一套系统,没有维护多套的烦恼,而且各个项目互不影响:A项目的改动不会影响到B系统. 31 | 该系统更像是一个框架一样, 我们只需要做的只是简单添加一些血肉就能完成 32 | 33 | 34 | #### 实现的功能(tasks) 35 | ``` 36 | 1. 制作后端更新的模板包 37 | 2. 部署游戏后端:支持迁移和部署新区 38 | 3. 全服更新后端,包含指定区服的更新、区服分段更新 39 | 4. 后端批量控制(start/stop) 40 | ``` 41 | 42 | #### 目录结构 43 | ```shell 44 | ├─config *#该系统需要用到的一些配置,如cmdb连接信息等, 所有的游戏都放在这里* 45 | ├─config_an *#ansible-playbook的一些配置文件* 46 | ├─lib *#库:读取cmdb 、 调用ansible api* 47 | ├─logs 48 | └─tasks *#该目录下以目录存放着每个task。每个task是建立在ansible程序之上* 49 | └─setup_game *#setup_game task, 用于部署游戏服,* 50 | ├─project 51 | └─roles *#ansible-playbook的roles* 52 | 53 | # ** ps: tasks目录下本身是有很多个task的,现在进行了隐去. ** 54 | ``` 55 | 56 | #### 使用 57 | ```bash 58 | # 所有的task放在tasks目录下,修改zone.py,执行run.py即可 59 | cd tasks/task_one #task_one,task的名字,这里只是举例 60 | vim zone.py #根据实际要操作的目标区服修改 61 | python run.py #直接执行即可,有做区服信息提示、检查,避免一些人为错误 62 | ``` 63 | 64 | #### 后记 65 | 今年(2020年)年后,去一家游戏公司面试,和面试官聊到现在很多游戏公司采用了这个设思想计来维护游戏. 66 | 想来不会是从我这来的设计思路吧? 想想还有点小激动呀 有木有? 如果是,希望可以发扬光大, 我就当抛砖引玉吧 哈哈 67 | 该系统完成于2014年, 当时就职于星辉天拓,整理提交到github是4年前, 开始写的时候, 也并无借鉴也没想到哪里有的借鉴,只是凭自己的想法设计的. 68 | 现在已离职多年, 去年18年时, 和之前的同事闲聊,了解到目前还依然在使用该套系统,没想到走了这么久, 再一次小激动,深藏功与名,低调低调. 69 | 70 | 整体上,这个系统的思路不错,让运维不用忙于各种机器,各种零散,来回折腾,一套系统就控制了所有的游戏,岂不快哉? 71 | 当然,话说回来,目前这个系统也只是个雏形, 也有很多地方需要改善和扩展,比如cmdb并不是个标准意义上的cmdb. 72 | 另外也不是以个开箱即用的系统,需要本身有一些系统的支撑,比如维护cmdb中信息的管理后台等. 73 | 74 | 最后说明下`由于考虑了敏感性, 有些完成的task进行了清理, 但不影响整体示意说明.` 75 | -------------------------------------------------------------------------------- /config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo515/opersible/733f25cad9c436c2928d91b7b03b602b3913d9e0/config/__init__.py -------------------------------------------------------------------------------- /config/games.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | HouTais={ 4 | 'ytyytengxun':{ # 名字格式: GAME_NAME+PLATFORM 5 | 'comment':'英雄联盟', 6 | 'CMDB_IP':'1.2.3.4', # cmdb数据库信息 7 | 'CMDB_PORT':'12345', 8 | 'CMDB_NAME':'gameweb', 9 | 'CMDB_USER':'game', 10 | 'CMDB_PASSWD':'nihao_20120926', 11 | 'VMTABLE':'gsys_admin_vm', 12 | 'ROLETABLE':'gsys_admin_role', 13 | 'GAMETABLE':'gsys_admin_db', 14 | 'PORTTABLE':'gsys_admin_port', 15 | 'sqls': [ 16 | #'some sqls;' 17 | ], 18 | 'no_update_zone':set([99999,2000,2001]), #全服更新时跳过这些服 19 | 'separate_zone':'16', #分批更新分界点: 目前来说英雄联盟为16, 王者荣耀为11, 不分批更新为空值 20 | 'autoid_suffix_lenght':11 #除去前缀的autoid之后的位数, 如autoid为1001, 则实际是100100000000001 21 | } 22 | } 23 | 24 | 25 | LOGFILE='/data/work/logs/ansiblework.log' 26 | 27 | -------------------------------------------------------------------------------- /config_an/common.yml: -------------------------------------------------------------------------------- 1 | BACKEND_UP: '{{REAL_NAME}}_up.tar.gz' 2 | # BACKEND_UP_PATH: '/data/htdocs/www/resource/houduan/{{BACKEND_UP}}' 3 | BACKEND_UP_PATH: '/data/work/tasks/moban/houduan/{{BACKEND_UP}}' 4 | 5 | BACKEND: '{{REAL_NAME}}.tar.gz' 6 | # BACKEND_PATH: '/data/htdocs/www/resource/houduan/{{BACKEND}}' 7 | BACKEND_PATH: '/data/work/tasks/moban/houduan/{{BACKEND}}' 8 | 9 | 10 | # DB_MoBan_PATH: "/data/shell/setup_gamedb/{{REAL_NAME}}_mb.sql" 11 | DB_MoBan_PATH: "{{REAL_NAME}}_mb.sql" 12 | 13 | 14 | #定义放置脚本或rpm包等的路径 15 | pub_path: '/data/work/software' 16 | 17 | #脚本的路径 18 | cutlog_sh_path: '{{pub_path}}/cutlog.sh' 19 | check_clean_mysql_disk_sh_path: '{{pub_path}}/check_clean_mysql_disk.sh' 20 | 21 | #rpm包名,不包含'.rpm' 22 | jdk_rpm: jdk-1.7.0-1.x86_64 23 | nginx_rpm: nginx-1.4.4-1.x86_64 24 | php_rpm: php-5.3.10-1.x86_64 25 | mysql_rpm: mysql-5.5.24-1.x86_64 26 | 27 | erlang_rpm: erlang-5.10.4-1.x86_64 28 | 29 | #rpm的路径. mysql、erlang可能未统一.根据实际情况填写 30 | jdk_rpm_path: '{{pub_path}}/{{ansible_distribution}}/{{jdk_rpm}}.rpm' 31 | nginx_rpm_path: '{{pub_path}}/{{ansible_distribution}}/{{nginx_rpm}}.rpm' 32 | php_rpm_path: '{{pub_path}}/{{ansible_distribution}}/{{php_rpm}}.rpm' 33 | mysql_rpm_path: '{{pub_path}}/{{ansible_distribution}}/{{mysql_rpm}}.rpm' 34 | erlang_rpm_path: '{{pub_path}}/{{ansible_distribution}}/{{erlang_rpm}}.rpm' 35 | 36 | path_843: '{{pub_path}}/843.tar.gz' 37 | 38 | -------------------------------------------------------------------------------- /config_an/shujian_tengxun.yml: -------------------------------------------------------------------------------- 1 | CheckPartion: yes 2 | 3 | 4 | 5 | #设置内网ip的ip段,格式x.x.x.,注意定义的是网段 6 | ConfigIP: no 7 | local_network: 192.168.100. 8 | 9 | BIN_PATH: ebin 10 | 11 | ChangePass: no 12 | passwordroot: 'xxxx' 13 | 14 | ConfigFirewall: yes 15 | 16 | Db_moban: yes 17 | 18 | REAL_NAME: txshujian 19 | 20 | 21 | #设置 zabbix 22 | Project_name: "shujian_tengxun" 23 | Proxy_Passive: "110.251.82.243" 24 | Proxy_Active: "110.251.82.243" 25 | 26 | -------------------------------------------------------------------------------- /config_an/template.yml: -------------------------------------------------------------------------------- 1 | #是否检查data分区挂载, 针对腾讯云服务器 2 | CheckPartion: no 3 | 4 | 5 | #设置内网ip的ip段,格式x.x.x.,注意定义的是网段 6 | ConfigIP: no 7 | local_network: 192.168.100. 8 | 9 | #bin ebin 10 | BIN_PATH: bin 11 | 12 | #是否更改root密码 13 | ChangePass: no 14 | passwordroot: 'xxxx' 15 | 16 | ConfigFirewall: yes 17 | 18 | #搭服是否需要导入数据库模板, 一般不用更新数据库的项目这里为no 19 | Db_moban: no 20 | 21 | #游戏后端目录前缀 即/data/gameserver/xxxx_9999/ 22 | REAL_NAME: yxzg 23 | 24 | #战报地址,战歌才需要 25 | reportUrl: 'http://myth-de-web.r2games.com/battle.php' 26 | 27 | #Zabbix 设置 28 | Project_name: "yxzg_R2de" # 新项目的话设定为 GAME_NAME_PLATFORM, 老项目不必更改 29 | Proxy_Passive: "192.168.22.250" 管理机ip 30 | Proxy_Active: "192.168.22.250" 管理机ip 31 | 32 | 33 | #战报信息, 战歌才要设定 34 | zhengbainfo: 35 | '+1': {zhengbaServerIp: 192.168.20.198, zhengbaVideoIp: London.zsxy.myth.r2games.com } 36 | 37 | 38 | -------------------------------------------------------------------------------- /config_an/ytsy_gn.yml: -------------------------------------------------------------------------------- 1 | CheckPartion: yes 2 | 3 | 4 | #设置内网ip的ip段,格式x.x.x.,注意定义的是网段 5 | ConfigIP: no 6 | local_network: 192.168.100. 7 | 8 | BIN_PATH: bin 9 | 10 | ChangePass: no 11 | passwordroot: 'xxxx' 12 | 13 | ConfigFirewall: yes 14 | 15 | Db_moban: no 16 | 17 | REAL_NAME: ytios 18 | reportUrl: 'yxzg-1235121013.eu-west-1.elb.amazonaws.com/battle.php' 19 | 20 | #设置 zabbix 21 | Project_name: "gnytsy" 22 | Proxy_Passive: "110.232.60.124" 23 | Proxy_Active: "110.232.60.124" 24 | 25 | -------------------------------------------------------------------------------- /game.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | 4 | GAME_NAME="yxzg" 5 | PLATFORM='R2de' 6 | -------------------------------------------------------------------------------- /game.yml: -------------------------------------------------------------------------------- 1 | GAME_NAME: yxzg 2 | 3 | PLATFORM: R2de 4 | 5 | -------------------------------------------------------------------------------- /lib/ansibleapi/YunweiCallbacks.py: -------------------------------------------------------------------------------- 1 | from ansible.callbacks import PlaybookCallbacks,PlaybookRunnerCallbacks 2 | 3 | class MyPlaybookCallbacks(PlaybookCallbacks): 4 | ''' playbook.py callbacks used by /usr/bin/ansible-playbook ''' 5 | # def __init__(self, verbose=False): 6 | # super(MyPlaybookCallbacks,self).__init(self,verbose=False) 7 | def on_start(self): 8 | pass 9 | def on_notify(self, host, handler): 10 | pass 11 | def on_no_hosts_matched(self): 12 | pass 13 | def on_no_hosts_remaining(self): 14 | pass 15 | def on_task_start(self, name, is_conditional): 16 | pass 17 | def on_vars_prompt(self, varname, pr): 18 | pass 19 | def on_setup(self): 20 | pass 21 | def on_import_for_host(self, host, imported_file): 22 | pass 23 | def on_not_import_for_host(self, host, missing_file): 24 | pass 25 | def on_play_start(self, pattern): 26 | pass 27 | def on_stats(self, stats): 28 | pass 29 | 30 | 31 | 32 | class MyPlaybookRunnerCallbacks(PlaybookRunnerCallbacks): 33 | def on_ok(self, host, host_result): 34 | pass 35 | -------------------------------------------------------------------------------- /lib/ansibleapi/YunweiInventory.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from ansible.inventory import Inventory 3 | from YunweiScript import YwScript 4 | from ansible import utils 5 | import os 6 | 7 | class YunweiInventory(Inventory): 8 | 9 | def __init__(self, adict): 10 | '''重写,传入自定义的字典''' 11 | 12 | # the host file file, or script path, or list of hosts 13 | # if a list, inventory data will NOT be loaded 14 | self.host_list = '' 15 | self.adict=adict 16 | 17 | # caching to avoid repeated calculations, particularly with 18 | # external inventory scripts. 19 | 20 | self._vars_per_host = {} 21 | self._vars_per_group = {} 22 | self._hosts_cache = {} 23 | self._groups_list = {} 24 | self._pattern_cache = {} 25 | 26 | # to be set by calling set_playbook_basedir by ansible-playbook 27 | self._playbook_basedir = None 28 | 29 | # the inventory object holds a list of groups 30 | self.groups = [] 31 | 32 | # a list of host(names) to contain current inquiries to 33 | self._restriction = None 34 | self._also_restriction = None 35 | self._subset = None 36 | 37 | self.parser = YwScript(adict) 38 | 39 | self.groups = self.parser.groups.values() 40 | 41 | utils.plugins.vars_loader.add_directory(self.basedir(), with_subdir=True) 42 | self._vars_plugins = [ x for x in utils.plugins.vars_loader.all(self) ] 43 | def basedir(self): 44 | cwd = '.' 45 | return os.path.abspath(cwd) -------------------------------------------------------------------------------- /lib/ansibleapi/YunweiPlayBook.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | # from ansible.playbook.play import Play 3 | from ansible.playbook import PlayBook 4 | from ansible.utils.template import template 5 | 6 | from ansible import callbacks 7 | import pprint 8 | import ansible 9 | import json 10 | 11 | class YunweiPlayBook(PlayBook): 12 | """ 自定义PlayBook class""" 13 | def __init__(self, *args, **kwargs): 14 | self.rsfile = kwargs.pop('rsfile', None) 15 | super(YunweiPlayBook, self).__init__(*args, **kwargs) 16 | 17 | def _save_task_results(self, task_results): 18 | #对task_results做一个判断,看是success_output还是error_output 19 | # if task_results['dark']: 20 | # AnsibleTask.objects.create(error_output=json.dumps(task_results)) 21 | # else: 22 | # AnsibleTask.objects.create(success_output=json.dumps(task_results)) 23 | 24 | # {'dark': {}, 'contacted': {u'moban_upjava_10': {'msg': u'hehe', 'verbose_always': True, 'invocation': {'module_name': 'debug', 'module_args': "msg='hehe'"}}}} 25 | 26 | # print 'result: ',task_results 27 | # pprint.pprint(task_results) 28 | logfile=open(self.rsfile,'a+') 29 | print >>logfile,task_results 30 | # print >>logfile, "%s \t %s " 31 | logfile.close() 32 | 33 | def _run_task(self, play, task, is_handler): 34 | ''' run a single task in the playbook and recursively run any subtasks. ''' 35 | 36 | ansible.callbacks.set_task(self.callbacks, task) 37 | ansible.callbacks.set_task(self.runner_callbacks, task) 38 | 39 | if task.role_name: 40 | name = '%s | %s' % (task.role_name, task.name) 41 | else: 42 | name = task.name 43 | 44 | self.callbacks.on_task_start(template(play.basedir, name, task.module_vars, lookup_fatal=False, filter_fatal=False), is_handler) 45 | if hasattr(self.callbacks, 'skip_task') and self.callbacks.skip_task: 46 | ansible.callbacks.set_task(self.callbacks, None) 47 | ansible.callbacks.set_task(self.runner_callbacks, None) 48 | return True 49 | 50 | # load up an appropriate ansible runner to run the task in parallel 51 | results = self._run_task_internal(task) 52 | #在这里直接把结果存进数据库 53 | self._save_task_results(results) 54 | 55 | # if no hosts are matched, carry on 56 | hosts_remaining = True 57 | if results is None: 58 | hosts_remaining = False 59 | results = {} 60 | 61 | contacted = results.get('contacted', {}) 62 | self.stats.compute(results, ignore_errors=task.ignore_errors) 63 | 64 | # add facts to the global setup cache 65 | for host, result in contacted.iteritems(): 66 | if 'results' in result: 67 | # task ran with_ lookup plugin, so facts are encapsulated in 68 | # multiple list items in the results key 69 | for res in result['results']: 70 | if type(res) == dict: 71 | facts = res.get('ansible_facts', {}) 72 | self.SETUP_CACHE[host].update(facts) 73 | else: 74 | facts = result.get('ansible_facts', {}) 75 | self.SETUP_CACHE[host].update(facts) 76 | # extra vars need to always trump - so update again following the facts 77 | self.SETUP_CACHE[host].update(self.extra_vars) 78 | if task.register: 79 | if 'stdout' in result and 'stdout_lines' not in result: 80 | result['stdout_lines'] = result['stdout'].splitlines() 81 | self.SETUP_CACHE[host][task.register] = result 82 | 83 | # also have to register some failed, but ignored, tasks 84 | if task.ignore_errors and task.register: 85 | failed = results.get('failed', {}) 86 | for host, result in failed.iteritems(): 87 | if 'stdout' in result and 'stdout_lines' not in result: 88 | result['stdout_lines'] = result['stdout'].splitlines() 89 | self.SETUP_CACHE[host][task.register] = result 90 | 91 | # flag which notify handlers need to be run 92 | if len(task.notify) > 0: 93 | for host, results in results.get('contacted',{}).iteritems(): 94 | if results.get('changed', False): 95 | for handler_name in task.notify: 96 | self._flag_handler(play, template(play.basedir, handler_name, task.module_vars), host) 97 | 98 | ansible.callbacks.set_task(self.callbacks, None) 99 | ansible.callbacks.set_task(self.runner_callbacks, None) 100 | return hosts_remaining 101 | -------------------------------------------------------------------------------- /lib/ansibleapi/YunweiScript.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from ansible.inventory.script import InventoryScript 3 | 4 | class YwScript(InventoryScript): 5 | '''重写了类的方法''' 6 | def __init__(self,adict): 7 | self.data = adict 8 | # see comment about _meta below 9 | self.host_vars_from_top = None 10 | self.groups = self._parse('') 11 | 12 | def get_host_variables(self, host): 13 | if self.host_vars_from_top is not None: 14 | got = self.host_vars_from_top.get(host.name, {}) 15 | return got 16 | 17 | -------------------------------------------------------------------------------- /lib/ansibleapi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo515/opersible/733f25cad9c436c2928d91b7b03b602b3913d9e0/lib/ansibleapi/__init__.py -------------------------------------------------------------------------------- /lib/ansibleapi/do.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | ####### 具体请参考ansible-playbook文件 ####### 4 | from ansible import utils # 5 | from ansible import errors # 6 | from ansible import callbacks 7 | from YunweiCallbacks import MyPlaybookCallbacks,MyPlaybookRunnerCallbacks 8 | import os,sys,traceback,time 9 | 10 | from ansible.callbacks import display 11 | from ansible.color import ANSIBLE_COLOR, stringc 12 | 13 | 14 | from YunweiPlayBook import YunweiPlayBook 15 | # from ansible.playbook import PlayBook 16 | 17 | 18 | # from ansible.inventory import Inventory 19 | 20 | from YunweiInventory import YunweiInventory 21 | 22 | 23 | def errinfo(): 24 | time.sleep(0.2) 25 | aaa=sys.exc_info() 26 | traceback.print_exception(aaa[0],aaa[1],aaa[2]) 27 | 28 | def get_inventory(adict):#,yunwei_vars) 29 | # Inventory默认使用 ``ANSIBLE_HOSTS`` 30 | inventory = YunweiInventory(adict) #, yunwei_vars=yunwei_vars) 31 | if len(inventory.list_hosts()) == 0: 32 | raise errors.AnsibleError("provided hosts list is empty") 33 | return inventory 34 | 35 | def get_playbook(ymlfile): 36 | '''返回一个yml文件路径''' 37 | #return settings.TEMP_PLAYBOOK_PATH 38 | return ymlfile 39 | 40 | def get_sudo(): 41 | return False 42 | 43 | def get_sudo_user(): 44 | return 'root' 45 | 46 | # 全局变量 47 | stats = callbacks.AggregateStats() 48 | 49 | # ``PlaybookCallbacks`` 是用来写结果到console的, ``PlaybookRunnerCallbacks``也是用来写结果到console。 50 | # playbook_cb = MyPlaybookCallbacks(verbose=True) #verbose=utils.VERBOSITY) 51 | # runner_cb = callbacks.DefaultRunnerCallbacks() #(stats, verbose=utils.VERBOSITY) 52 | 53 | ################ 54 | #开启调试信息输出 55 | playbook_cb = callbacks.PlaybookCallbacks(verbose=True) 56 | runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=True) #两个参数,不同于DefaultRunnerCallbacks 57 | # runner_cb = MyPlaybookRunnerCallbacks(stats, verbose=True) #两个参数,不同于DefaultRunnerCallbacks 58 | ################ 59 | 60 | def hostcolor(host, stats, color=True): 61 | if ANSIBLE_COLOR and color: 62 | if stats['failures'] != 0 or stats['unreachable'] != 0: 63 | return "%-37s" % stringc(host, 'red') 64 | elif stats['changed'] != 0: 65 | return "%-37s" % stringc(host, 'yellow') 66 | else: 67 | return "%-37s" % stringc(host, 'green') 68 | return "%-26s" % host 69 | 70 | def colorize(lead, num, color): 71 | """ Print 'lead' = 'num' in 'color' """ 72 | if num != 0 and ANSIBLE_COLOR and color is not None: 73 | return "%s%s%-15s" % (stringc(lead, color), stringc("=", color), stringc(str(num), color)) 74 | else: 75 | return "%s=%-4s" % (lead, str(num)) 76 | 77 | def job(ymlfile,adict,rsfile): #data_dict 78 | playbook_path = get_playbook(ymlfile) 79 | # 设置playbook目录 80 | inventory = get_inventory(adict )#,data_dict) 81 | inventory.set_playbook_basedir(os.path.dirname(playbook_path)) 82 | ''' 83 | print 'remote_user:',type(options.remote_user),repr(options.remote_user) #远程用户 84 | print 'remote_pass:',type(sshpass),repr(sshpass) #远程用户密码 85 | print 'sudo:',type(options.sudo),repr(options.sudo) #是否使用sudo 86 | print 'sudo_user:',type(options.sudo_user),repr(options.sudo_user) #sudo用户 87 | print 'sudo_pass:',type(sudopass),repr(sudopass) #sudo密码 88 | print 'su:',type(options.su),repr(options.su) #是否使用su 89 | print 'su_pass:',type(su_pass),repr(su_pass) #su密码 90 | print 'su_user:',type(options.su_user),repr(options.su_user) #su密码 91 | ''' 92 | 93 | pb = YunweiPlayBook( 94 | playbook=playbook_path, 95 | inventory=inventory, 96 | callbacks=playbook_cb, 97 | runner_callbacks=runner_cb, 98 | stats=stats, 99 | sudo=get_sudo(), 100 | #yunwei_task=yunwei_task, 101 | rsfile=rsfile, 102 | # remote_user='ansibleuser', 103 | # remote_pass='nWrjcUZzoyvP', 104 | # sudo_user='root', 105 | # sudo_pass=None 106 | ) 107 | 108 | failed_hosts = [] 109 | unreachable_hosts = [] 110 | 111 | # 运行pb,然后使用返回的数据 112 | # try: 113 | # pb.run()直接写结果到console 114 | ansible_res=pb.run() 115 | # print ansible_res 116 | hosts = sorted(pb.stats.processed.keys()) 117 | display(callbacks.banner("PLAY RECAP")) 118 | playbook_cb.on_stats(pb.stats) 119 | 120 | for h in hosts: 121 | t = pb.stats.summarize(h) 122 | if t['failures'] > 0: 123 | failed_hosts.append(h) 124 | if t['unreachable'] > 0: 125 | unreachable_hosts.append(h) 126 | 127 | retries = failed_hosts + unreachable_hosts 128 | 129 | # if len(retries) > 0: 130 | # filename = pb.generate_retry_inventory(retries) 131 | # if filename: 132 | # display(" to retry, use: --limit @%s\n" % filename) 133 | # raise RuntimeError('ansible error') 134 | 135 | for h in hosts: 136 | t = pb.stats.summarize(h) 137 | 138 | display("%s : %s %s %s %s" % ( 139 | hostcolor(h, t), 140 | colorize('ok', t['ok'], 'green'), 141 | colorize('changed', t['changed'], 'yellow'), 142 | colorize('unreachable', t['unreachable'], 'red'), 143 | colorize('failed', t['failures'], 'red')), 144 | screen_only=True 145 | ) 146 | 147 | display("%s : %s %s %s %s" % ( 148 | hostcolor(h, t, False), 149 | colorize('ok', t['ok'], None), 150 | colorize('changed', t['changed'], None), 151 | colorize('unreachable', t['unreachable'], None), 152 | colorize('failed', t['failures'], None)), 153 | log_only=True 154 | ) 155 | 156 | print "" 157 | # if len(failed_hosts) > 0: 158 | # return ansible_res 159 | # if len(unreachable_hosts) > 0: 160 | # return ansible_res 161 | 162 | # except errors.AnsibleError, e: 163 | # # errinfo 164 | # display("ERROR: %s" % e, color='red') 165 | # return ansible_res 166 | # else: 167 | return ansible_res 168 | -------------------------------------------------------------------------------- /lib/cmdbinfo/__init__.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import sys 3 | sys.path.append('/data/work/') 4 | from game import GAME_NAME,PLATFORM 5 | from config.games import HouTais 6 | 7 | from sqlalchemy import create_engine 8 | from sqlalchemy.orm import sessionmaker 9 | 10 | import time,traceback 11 | 12 | CMDB=HouTais[(GAME_NAME+PLATFORM)] 13 | 14 | cmdbip =CMDB['CMDB_IP'] 15 | cmdbport =CMDB['CMDB_PORT'] 16 | cmdbname =CMDB['CMDB_NAME'] 17 | cmdbpasswd =CMDB['CMDB_PASSWD'] 18 | cmdbuser =CMDB['CMDB_USER'] 19 | 20 | VMTABLE =CMDB['VMTABLE'] 21 | ROLETABLE =CMDB['ROLETABLE'] 22 | GAMETABLE =CMDB['GAMETABLE'] 23 | PORTTABLE =CMDB['PORTTABLE'] 24 | no_update_zone=CMDB['no_update_zone'] 25 | 26 | 27 | DB_CONNECT_STRING = r'mysql+mysqldb://%s:%s@%s:%s/%s?charset=utf8' % (cmdbuser,cmdbpasswd,cmdbip,cmdbport,cmdbname,) 28 | # print DB_CONNECT_STRING 29 | engine = create_engine(DB_CONNECT_STRING, echo=False) 30 | DB_Session = sessionmaker(bind=engine) 31 | session = DB_Session() 32 | 33 | 34 | 35 | 36 | def errinfo(): 37 | time.sleep(0.2) 38 | aaa=sys.exc_info() 39 | traceback.print_exception(aaa[0],aaa[1],aaa[2]) 40 | 41 | class cmdbinfo(object): 42 | def __init__(self,num): 43 | self.num=num 44 | 45 | def __str__(self): 46 | return '' % (id(self),self.num) 47 | 48 | def dbinfo(self): 49 | '''A tuple: (dbip, dbport)''' 50 | sql="select av_vmip,av_dbport from %s where sysid in (select ar_vmid from %s where ar_zoneid='%s' and ar_typeid=2);" % (VMTABLE,ROLETABLE,self.num) 51 | res=session.execute(sql).fetchall() 52 | if not res: return '' 53 | return res[0] 54 | 55 | def slaveinfo(self): 56 | '''A tuple: (slaveip,slaveport,slavepassword)''' 57 | sql="select av_vmip,av_dbport,av_dbpass from %s where av_masterid=(select ar_vmid from %s where ar_zoneid='%s' and ar_typeid=2);" % (VMTABLE,ROLETABLE,self.num) 58 | res=session.execute(sql).fetchall() 59 | if not res: return '' 60 | return res[0] 61 | 62 | def to_dbinfo(self): 63 | '''A tuple: (to_dbip, to_dbport)''' 64 | sql="select av_vmip,av_dbport from %s where sysid in (select ar_tovmid from %s where ar_zoneid='%s' and ar_typeid=2);" % (VMTABLE,ROLETABLE,self.num) 65 | res=session.execute(sql).fetchall() 66 | if not res: return '' 67 | return res[0] 68 | 69 | def to_slaveinfo(self): 70 | '''A tuple: (to_slaveip,to_slaveport,to_slavepassword)''' 71 | sql="select av_vmip,av_dbport,av_dbpass from %s where av_masterid=(select ar_tovmid from %s where ar_zoneid='%s' and ar_typeid=2);" % (VMTABLE,ROLETABLE,self.num) 72 | res=session.execute(sql).fetchall() 73 | if not res: return '' 74 | return res[0] 75 | 76 | def dbnameinfo(self): 77 | '''A tuple: (dbname, to_dbname)''' 78 | sql="select ab_dbname,ab_todbname from %s where ab_zoneid='%s';" % (GAMETABLE,self.num) 79 | res=session.execute(sql).fetchall() 80 | if not res: return '' 81 | return res[0] 82 | 83 | ################################################################################## 84 | def backendinfo(self): 85 | '''A tuple: (javaip, javaname)''' 86 | sql="select av_vmip,av_domainname from %s where sysid in (select ar_vmid from %s where ar_zoneid='%s' and ar_typeid=1);" % (VMTABLE,ROLETABLE,self.num) 87 | res=session.execute(sql).fetchall() 88 | if not res: return '' 89 | return res[0] 90 | 91 | def to_backendinfo(self): 92 | '''A tuple: (to_javaip, to_javaname)''' 93 | sql="select av_vmip,av_domainname from %s where sysid in (select ar_tovmid from %s where ar_zoneid='%s' and ar_typeid=1);" % (VMTABLE,ROLETABLE,self.num) 94 | res=session.execute(sql).fetchall() 95 | if not res: return '' 96 | return res[0] 97 | 98 | def portidinfo(self): 99 | '''A tuple: (portid, to_portid) int''' 100 | sql="select ar_portid,ar_toportid from %s where ar_zoneid='%s' and ar_typeid=1;" % (ROLETABLE,self.num) 101 | res=session.execute(sql).fetchall() 102 | if not res: return '' 103 | return res[0] 104 | 105 | ##################################################################################### 106 | def hefu_baoliu(self): 107 | ''' 合服保留区区号 int''' 108 | if not self.hefu_zones(): return '' 109 | return min(self.hefu_zones()) 110 | 111 | def hefu_zones(self): 112 | '''合服关系: list: [int,int,int ...]''' 113 | sql="select ab_zoneid from %s where ab_dbname=(select ab_dbname from %s where ab_zoneid='%s');" % (GAMETABLE,GAMETABLE,self.num) 114 | res=session.execute(sql).fetchall() 115 | if not res: return '' 116 | return [int(i[0]) for i in session.execute(sql).fetchall()] #a list 117 | 118 | def gameinfo(self): 119 | '''A tuple: (前端域名、前端ip、对外id、开服时间、autoid、联运商id) ''' 120 | sql="select ab_fronthost,ab_frontip,ab_outid,ab_opentime,ab_autoid,ab_transportid from %s where ab_zoneid='%s';" % (GAMETABLE,self.num) 121 | res=session.execute(sql).fetchall() # a tuple 122 | if not res: return '' 123 | return res[0] 124 | 125 | def socketport(self): 126 | '''int''' 127 | sql="select ap_game from %s where sysid=(select ar_portid from %s where ar_zoneid='%s' and ar_typeid=1);" % (PORTTABLE,ROLETABLE,self.num) 128 | res=session.execute(sql).fetchall() 129 | if not res: return '' 130 | return res[0][0] 131 | 132 | def to_socketport(self): 133 | '''int''' 134 | sql="select ap_game from %s where sysid=(select ar_toportid from %s where ar_zoneid='%s' and ar_typeid=1);" % (PORTTABLE,ROLETABLE,self.num) 135 | res=session.execute(sql).fetchall() 136 | if not res: return '' 137 | return res[0][0] 138 | 139 | 140 | def timezone(self): 141 | sql="select ab_timezone from %s where ab_zoneid='%s'" % (GAMETABLE,self.num) 142 | res=session.execute(sql).fetchall() 143 | if not res: return '' 144 | return res[0][0] 145 | 146 | 147 | class gameinfo_summarize(object): 148 | def allzone(self): 149 | #A set 150 | sql='select ab_zoneid from %s where ab_normal <> -1' % GAMETABLE 151 | res=session.execute(sql).fetchall() 152 | return set([i[0] for i in res])-no_update_zone #所有正式服(去掉2095、9999、9998) 153 | 154 | def all_baoliu(self): 155 | allzone_baoliu=set() 156 | for num in self.allzone(): 157 | ins=cmdbinfo(num) 158 | # print num,str(num)==str(ins.hefu_baoliu()) 159 | if str(num)==str(ins.hefu_baoliu()): allzone_baoliu.add(num) # 跳过合服区 160 | return allzone_baoliu 161 | 162 | def get_baoliu(self,nums,skiphefu): 163 | new=set() 164 | if skiphefu: 165 | for num in nums: 166 | ins=cmdbinfo(num) 167 | # print num,str(num)==str(ins.hefu_baoliu()) 168 | if str(num)==str(ins.hefu_baoliu()): new.add(num) # 跳过合服区 169 | else: 170 | for num in nums: 171 | ins=cmdbinfo(num) 172 | if ins.hefu_baoliu(): new.add(str(ins.hefu_baoliu())) #不跳过合服区(将合服主区加入) 173 | return new 174 | 175 | 176 | 177 | if __name__=='__main__': 178 | try: 179 | aa=cmdbinfo(sys.argv[1]) 180 | print aa.dbinfo() # dbip dbport 181 | print aa.slaveinfo() # slaveip slaveport slavepassword 182 | print aa.to_dbinfo() # to_dbip to_dbport 183 | print aa.to_slaveinfo() # to_slaveip, to_slaveport, to_slavepassword 184 | print aa.dbnameinfo() # dbname, to_dbname 185 | print aa.backendinfo() # javaip, javaname 186 | print aa.to_backendinfo() # to_javaip, to_javaname 187 | print aa.portidinfo() # portid, to_portid 188 | print aa.hefu_baoliu() 189 | print aa.hefu_zones() 190 | print aa.gameinfo() 191 | print aa.socketport() 192 | print aa.to_socketport() 193 | print aa.timezone() 194 | except : 195 | print aa 196 | errinfo() 197 | 198 | print '==========================' 199 | someinfo=gameinfo_summarize() 200 | print someinfo.all_baoliu() 201 | 202 | 203 | # (u'10.143.82.136', 3306L) 204 | # (u'10.143.84.113', 3306L, u'') 205 | # (u'10.143.82.136', 3306L) 206 | # (u'10.143.84.113', 3306L, u'') 207 | # (u'yxzg_1', u'yxzg_1') 208 | # (u'10.143.78.155', u'203.195.161.52') 209 | # (u'10.143.78.155', u'203.195.161.52') 210 | # (1L, 1L) 211 | # 1 212 | # [1, 2, 3] # int 213 | # (u'10.221.149.20', u'10.221.149.20', 3L, 1407477600L, 10003L, u'373700003') 214 | # 8003 215 | # 8003 216 | # -2 #u'-2' unicode 217 | -------------------------------------------------------------------------------- /lib/cmdbinfo/tools.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import cmdbinfo as cmdb 3 | from sqlalchemy import create_engine 4 | from sqlalchemy.orm import sessionmaker 5 | 6 | import sys,os 7 | 8 | # sys.path.append('/data/ansiblework/') 9 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'../..'))) 10 | 11 | # sys.path.append('/data/ansiblework/config/') 12 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'../../config'))) 13 | 14 | 15 | 16 | from game import GAME_NAME 17 | from games import HouTais 18 | 19 | 20 | def donums(nums,skiphefu=False): 21 | '''是否跳过合服区,返回一个set,''' 22 | new=set() 23 | if skiphefu: 24 | for num in nums: 25 | ins=cmdb.cmdbinfo(num) 26 | # print num,str(num)==str(ins.hefu_baoliu()) 27 | if str(num)==str(ins.hefu_baoliu()): new.add(num) # 跳过合服区 28 | else: 29 | for num in nums: 30 | ins=cmdb.cmdbinfo(num) 31 | if ins.hefu_baoliu(): new.add(str(ins.hefu_baoliu())) #不跳过合服区(将合服主区加入) 32 | return new 33 | 34 | 35 | def grantdb(ip,port,user,passwd): 36 | '''授权函数: sqls在game.py中定义''' 37 | DB_CONNECT_STRING = r'mysql+mysqldb://%s:%s@%s:%s/?charset=utf8' % (user,passwd,ip,port) 38 | engine = create_engine(DB_CONNECT_STRING, echo=False) 39 | DB_Session = sessionmaker(bind=engine) 40 | session = DB_Session() 41 | sqls=HouTais[GAME_NAME]['sqls'] 42 | for sql in sqls: 43 | session.execute(sql).fetchall() 44 | session.commit() 45 | 46 | def conv(adict): 47 | # ''' 传入一个字典重新构造一个字典(用于ansible) 48 | 49 | # {'group1': {'groupvars': {'gvar1': 'gvar2'}, 50 | # 'hosts': {'host1': {'var1': 'var1', 'var2': 'var2'}, 51 | # 'host2': {'var3': 'var3', 'var4': 'var4'}}}, 52 | # 'group2': {'hosts': {'host3': {'var5': 'var5', 'var6': 'var2'}, 53 | # 'host4': {'var7': 'var3', 'var8': 'var4'}}}} 54 | 55 | # ''' 56 | 57 | # raw={} 58 | # raw['_meta']={} 59 | # raw['_meta']['hostvars']={} 60 | # hostslist={} 61 | # for gp,hlist in adict.items(): 62 | # raw[gp]=hlist.keys() 63 | # raw['_meta']['hostvars'].update(hlist) 64 | # return raw 65 | 66 | 67 | 68 | raw={} 69 | raw['_meta']={} 70 | raw['_meta']['hostvars']={} 71 | for gname,ginfo in adict.items(): 72 | raw[gname]={} 73 | raw[gname]['hosts']=ginfo['hosts'].keys() 74 | if 'groupvars' in ginfo: 75 | raw[gname]['vars']={} 76 | raw[gname]['vars'].update(ginfo['groupvars']) 77 | raw['_meta']['hostvars'].update(ginfo['hosts']) 78 | return raw 79 | 80 | ''' 81 | adict={'group1': {'groupvars': {'gvar1': 'gvar2'}, 82 | 'hosts': {'host1': {'var1': 'var1', 'var2': 'var2'}, 83 | 'host2': {'var3': 'var3', 'var4': 'var4'}}}, 84 | 'group2': {'hosts': {'host3': {'var5': 'var5', 'var6': 'var2'}, 85 | 'host4': {'var7': 'var3', 'var8': 'var4'}}}} 86 | pprint.pprint(conv(adict)) 87 | ''' -------------------------------------------------------------------------------- /lib/public.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | 4 | import sys,time 5 | class _tee(file): 6 | def write(self, text): 7 | sys.stdout.write(text) 8 | file.write(self, str(text)+'\n') 9 | 10 | def _write(self, text): 11 | file.write(self, str(text)+'\n') 12 | 13 | 14 | def nowtime(): 15 | return time.strftime(' %Y-%m-%d %H:%M:%S ',time.localtime(time.time())) 16 | 17 | def nowtime_int(): 18 | return time.time() 19 | 20 | if __name__ == '__main__': 21 | with _tee('/tmp/test.txt','a+') as f: 22 | f.write('something .... ') 23 | f._write('something else ... ') 24 | -------------------------------------------------------------------------------- /logs/ansiblework.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neo515/opersible/733f25cad9c436c2928d91b7b03b602b3913d9e0/logs/ansiblework.log -------------------------------------------------------------------------------- /tasks/setup_game/project/shujian.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import cmdbinfo as cmdb 4 | from time import time,strftime,localtime 5 | 6 | def handle(nums,adict): 7 | 8 | 9 | # for num in tools.donums(nums,skiphefu=skiphefu): 10 | for num in nums: 11 | eachone={} 12 | ins=cmdb.cmdbinfo(num) 13 | backendip,backendname =ins.backendinfo() 14 | dbip,dbport =ins.dbinfo() 15 | dbname =ins.dbnameinfo()[0] 16 | socketport =ins.socketport() 17 | t,platforms =ins.gameinfo()[3:6:2] 18 | opentime =strftime('{{%Y,%m,%d},{%H,%M,%S}}.',localtime(t)) 19 | allhefu =ins.hefu_zones() 20 | hefunums =','.join(['\'\\\"S%s\\\"\'' % i for i in allhefu]) 21 | 22 | eachone[('backend_'+str(num))]={ 23 | 'num':num , 24 | 'ansible_ssh_host':backendip, 25 | 'javaip':backendip, 26 | 'javaname':backendname, 27 | 'dbip':dbip, 28 | 'dbport':dbport, 29 | 'dbname':dbname, 30 | 'platforms':platforms, 31 | 'hefunums':hefunums, 32 | 'opentime':opentime, 33 | 'socketport':socketport} 34 | adict['setup_game']['hosts'].update(eachone) 35 | return adict 36 | -------------------------------------------------------------------------------- /tasks/setup_game/roles/3_setup/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - include: "{{GAME_NAME}}_main.yml" 2 | -------------------------------------------------------------------------------- /tasks/setup_game/roles/3_setup/tasks/shujian_main.yml: -------------------------------------------------------------------------------- 1 | - shell: test -e /data/gameserver/{{REAL_NAME}}_{{num}} && rm -rf /data/gameserver/{{REAL_NAME}}_{{num}}; mkdir -p /data/gameserver/{{REAL_NAME}}_{{num}} 2 | - copy: src={{BACKEND_PATH}} dest=/data/gameserver/{{REAL_NAME}}_{{num}}/{{BACKEND}} force=yes 3 | - shell: tar zxf {{BACKEND}} --touch chdir=/data/gameserver/{{REAL_NAME}}_{{num}} 4 | - shell: rm -f {{BACKEND}} chdir=/data/gameserver/{{REAL_NAME}}_{{num}} 5 | 6 | 7 | - shell: mkdir -p logs chdir=/data/gameserver/{{REAL_NAME}}_{{num}} 8 | 9 | - shell: grep {{javaip}} /etc/hosts|| echo {{javaip}} {{javaname}} >>/etc/hosts 10 | 11 | - shell: sed -i "/db_host/c \{db\_host\, \"{{dbip}}\"\}\," config/gs.config chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 12 | - shell: sed -i "/db_port/c \{db\_port\, {{dbport}}\}\," config/gs.config chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 13 | - shell: sed -i "/db_name/c \{db\_name\, \"{{dbname}}\"\}\," config/gs.config chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 14 | - shell: sed -i "/server_num/c \{server\_num\, {{num}}\}\," config/gs.config chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 15 | - shell: sed -i "/platform/c \{platform\, \"{{platforms}}\"\}\," config/gs.config chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 16 | 17 | - shell: sed -i "/card_server/c \{card\_server\, \[{{hefunums}}\]\}" config/gs.config chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 18 | 19 | - shell: sed -i "/^SERVER_NUM=/c SERVER_NUM={{num}}" config/head.sh chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 20 | - shell: sed -i "/^DOMAIN=/c DOMAIN=\"{{javaname}}\"" config/head.sh chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 21 | - shell: sed -i "/^gameip=/c gameip=\"{{javaip}}\"" config/head.sh chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 22 | 23 | 24 | - shell: sed -i "/^COMMON_PORT_START_10=/c COMMON_PORT_START_10={{socketport}}" config/head.sh chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 25 | - shell: sed -i "/^COMMON_PORT_START_1=/c COMMON_PORT_START_1={{socketport|int +1 }}" config/head.sh chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 26 | - shell: sed -i "/^COMMON_PORT_START_0=/c COMMON_PORT_START_0={{socketport|int - 2000}}" config/head.sh chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 27 | - shell: echo "{{opentime}}" > config/open_time.config chdir=/data/gameserver/{{REAL_NAME}}_{{num}}/server 28 | -------------------------------------------------------------------------------- /tasks/setup_game/run.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import os,sys,pprint,json 4 | from ansible.color import stringc 5 | 6 | #这里定义了将要更新的区 7 | from zone import * 8 | 9 | curdir=os.path.dirname(os.path.abspath(__file__)) 10 | 11 | #将项目主目录加入python系统搜索路径, 使可以查找到game.py、config目录 12 | #这里指向operansible目录 13 | sys.path.append(os.path.abspath(os.path.join(curdir,'../..'))) 14 | from game import GAME_NAME 15 | from config.games import LOGFILE 16 | 17 | #将库目录lib加入python系统搜索路径 18 | sys.path.append(os.path.abspath(os.path.join(curdir,'../../lib'))) 19 | from public import _tee,nowtime 20 | import cmdbinfo as cmdb 21 | from ansibleapi.do import job 22 | from cmdbinfo import tools 23 | 24 | sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'project')) 25 | main=__import__(GAME_NAME) 26 | 27 | # ansible需要的site.py 28 | siteyml=os.path.join(os.path.dirname(os.path.abspath(__file__)),'site.yml') 29 | 30 | #定义脚本执行的日志 31 | rsfile=os.getcwd()+'/rs.txt' 32 | open(rsfile,'w').close() 33 | logging_tmp=_tee(rsfile,'a+') 34 | logging=file(LOGFILE,'a+') 35 | logging_tmp._write('[ ' + '='*15 + nowtime() + '='*15 + ' ]') 36 | 37 | 38 | start=start.strip() 39 | end=end.strip() 40 | mobannum=mobannum.strip() 41 | nums=set(tmp_nums.split()) 42 | 43 | if not mobannum: sys.exit('zone.conf中未指定模版区号') 44 | 45 | if (bool(nums)==True and bool(start)==False and bool(end)==False) or (bool(nums)==False and start and end): 46 | print '正在以%s服为模版部署后端: %s - %s ' % (stringc(mobannum,'green'),stringc(start,'green'),stringc(end,'green')) \ 47 | if start and end else \ 48 | '正在以%s服为模版部署后端: %s' % (stringc(mobannum,'green'), stringc(' '.join(nums),'green')) 49 | 50 | logging_tmp._write(('正在以%s服为模版部署后端: %s - %s ' % (mobannum,start,end)) \ 51 | if start and end else \ 52 | ('正在以%s服为模版部署后端: %s' % (mobannum,' '.join(nums)))) 53 | 54 | rep=raw_input('输入y继续: ') 55 | if rep.lower() != 'y': sys.exit('已退出') 56 | 57 | mo=cmdb.cmdbinfo(mobannum) 58 | try: 59 | mo_javaip=mo.backendinfo()[0] 60 | real_num=mo.hefu_baoliu() 61 | except: 62 | sys.exit('错误,可能是该区已经删除,请重新指定打模版区') 63 | 64 | skiphefu=False 65 | if not nums: 66 | nums=[str(i) for i in range(int(start),int(end)+1)] 67 | skiphefu=True 68 | 69 | adict={'do_moban':{'hosts':{}},'setup_game':{'hosts':{}}} 70 | adict['do_moban']['hosts']={'moban_'+str(mobannum):{'num':real_num, 'ansible_ssh_host':mo_javaip},} 71 | nums=tools.donums(nums,skiphefu=skiphefu) 72 | adict=main.handle(nums,adict) 73 | 74 | else: 75 | print '区信息配置错误,请修正conf.py' 76 | 77 | logging_tmp._write(pprint.pformat(adict)) 78 | logging_tmp.close() 79 | raw=tools.conv(adict) 80 | 81 | ret=job(siteyml,json.dumps(raw),rsfile) 82 | logging_tmp=_tee(rsfile,'a+') 83 | logging_tmp._write(ret) 84 | logging_tmp.close() 85 | rs_f=open(rsfile) 86 | logging.write(rs_f.read()) 87 | logging_tmp.close() 88 | rs_f.close() 89 | -------------------------------------------------------------------------------- /tasks/setup_game/site.yml: -------------------------------------------------------------------------------- 1 | - hosts: do_moban 2 | vars_files: 3 | - "../../game.yml" #游戏名、平台 4 | - "../../config_an/{{GAME_NAME}}_{{PLATFORM}}.yml" #site.yml用的开关、REAL_NAME 5 | - "../../config_an/common.yml" #软件包路径等 6 | 7 | # tasks: 8 | # - debug: msg={{ansible_ssh_host}} 9 | 10 | 11 | 12 | roles: 13 | - 1_tar_backend 14 | - 2_rename 15 | 16 | 17 | - hosts: setup_game 18 | vars_files: 19 | - "../../game.yml" #游戏名、平台 20 | - "../../config_an/{{GAME_NAME}}_{{PLATFORM}}.yml" #site.yml用的开关、REAL_NAME 21 | - "../../config_an/common.yml" #软件包路径等 22 | 23 | # tasks: 24 | # - debug: msg="{{num}}={{ansible_ssh_host}} ={{javaip}}={{javaname}}={{dbip}} ; {{dbport}}={{ dbname}}={{platforms}}={{hefunums}}={{opentime}}={{socketport}}" 25 | # - debug: msg={{ansible_ssh_host}} 26 | 27 | roles: 28 | - 5_setup_db 29 | - 3_setup 30 | - 4_checkout 31 | -------------------------------------------------------------------------------- /tasks/setup_game/zone.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | mobannum='10' 4 | 5 | start='12' 6 | end='15' 7 | 8 | tmp_nums=""" 9 | """ 10 | --------------------------------------------------------------------------------