├── .idea └── vcs.xml ├── README.md ├── ansible_playbooks └── test.yml ├── app.py ├── environment.py ├── handlers ├── __init__.py └── ansible_async.py ├── libs ├── __init__.py ├── my_ansible_api.py └── utils.py ├── logconfig ├── __init__.py └── logconfig.py ├── requirements └── requirements.txt ├── settings.py └── urls.py /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | --- 3 | 4 | 基于Ansible2.0 开发一个异步高效的API系统, 供其他系统调用。 5 | 6 | # 组件 7 | --- 8 | 9 | + Ansible 注意版本2.0 10 | + Tornado 异步就靠他了 11 | + MongoDB 数据存储 12 | 13 | # 布局 14 | --- 15 | 16 | + handlers 17 | 18 | tornado handlers 目录, 当import envronment 模块时, 19 | 这个目录下面的所有文件都将加入到PYTHONPATH环境变量. 20 | 21 | 22 | + libs 23 | 24 | 存储Python包的目录,那些不是Tornado request handlers的模块文件都放在这里 25 | 这个目录下面的所有文件都将加入到PYTHONPATH环境变量. 26 | 27 | + logconfig 28 | 29 | python logging的配置文件存放目录, 具体可以参考python logging官方说明, 30 | 这个包主要包含一个initalize_logging的方法,用此方法可以实例华一个真正的logger实例 31 | 在settings.py 文件用此来配置日志 32 | 33 | 注意root logger在settings.py中就已经设置好了, app中仅需要调用他的子logger即可使用 34 | 具体方法如下: 35 | ``` 36 | #!python 37 | import logging 38 | logger = logging.getLogger('five.' + __name__) 39 | ``` 40 | 41 | + requirements 42 | 43 | pip 的requirements文件存放目录,总共分成3类, 44 | 45 | 1. common.txt 开发和生产环境都需要的包 46 | 2. devolop.txt 开发环境依赖的包 47 | 3. production.txt 生产环境依赖的包 48 | 49 | + environment.py 50 | 51 | 修改Python运行时的PYTHONPATH环境变量,这个模块会在settings.py的顶层被导入,以确保handlers和libs下的模块能被python找到。 52 | 53 | + app.py 54 | 55 | Tornado app 入口模块, 用于启动 Tornado Server. 56 | 57 | + settints.py 58 | 59 | app 配置模块 60 | 61 | + urls.py 62 | 63 | app 路由模块 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /ansible_playbooks/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 192.168.10.148 3 | tasks: 4 | - name: test 5 | shell: time ls 6 | 7 | - name: sleep 2 seconds 8 | shell: sleep 2 9 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import tornado.httpserver 4 | import tornado.ioloop 5 | import tornado.web 6 | from tornado.options import options 7 | 8 | from settings import settings 9 | from urls import url_patterns 10 | 11 | 12 | class TornadoBoilerplate(tornado.web.Application): 13 | def __init__(self): 14 | tornado.web.Application.__init__(self, url_patterns, **settings) 15 | 16 | 17 | def main(): 18 | app = TornadoBoilerplate() 19 | http_server = tornado.httpserver.HTTPServer(app) 20 | http_server.listen(options.port) 21 | tornado.ioloop.IOLoop.instance().start() 22 | 23 | if __name__ == "__main__": 24 | main() -------------------------------------------------------------------------------- /environment.py: -------------------------------------------------------------------------------- 1 | # Add the project's directories to Python's site-packages path. 2 | 3 | import os 4 | import site 5 | import sys 6 | 7 | ROOT = os.path.dirname(os.path.abspath(__file__)) 8 | path = lambda *a: os.path.join(ROOT, *a) 9 | 10 | prev_sys_path = list(sys.path) 11 | 12 | site.addsitedir(path('handlers')) 13 | site.addsitedir(path('libs')) 14 | if os.path.exists(path('vendor')): 15 | for directory in os.listdir(path('vendor')): 16 | full_path = path('vendor/%s' % directory) 17 | if os.path.isdir(full_path): 18 | site.addsitedir(full_path) 19 | 20 | # Move the new items to the front of sys.path. (via virtualenv) 21 | new_sys_path = [] 22 | for item in list(sys.path): 23 | if item not in prev_sys_path: 24 | new_sys_path.append(item) 25 | sys.path.remove(item) 26 | sys.path[:0] = new_sys_path 27 | 28 | -------------------------------------------------------------------------------- /handlers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yumaojun03/ansible_async_api/c968d42173b51151b3a78abe8921eddc039bdc21/handlers/__init__.py -------------------------------------------------------------------------------- /handlers/ansible_async.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | import json 5 | 6 | import logging 7 | from tornado import gen 8 | from tornado.web import HTTPError 9 | from tornado.web import RequestHandler, asynchronous 10 | from tornado.concurrent import run_on_executor 11 | from concurrent.futures import ThreadPoolExecutor 12 | 13 | 14 | from libs.my_ansible_api import Ad_Hoc, MyPlaybook 15 | from multiprocessing import cpu_count 16 | 17 | logger = logging.getLogger('tornado.app') 18 | 19 | 20 | class MainHandler(RequestHandler): 21 | def get(self): 22 | self.write("Hello, world") 23 | 24 | 25 | class CommandHandler(RequestHandler): 26 | executor = ThreadPoolExecutor(cpu_count()) 27 | 28 | @asynchronous 29 | @gen.coroutine 30 | def post(self): 31 | try: 32 | data = json.loads(self.request.body) 33 | except ValueError as e: 34 | raise HTTPError(400, e.message) 35 | logger.debug("input data: %s" % data) 36 | response = yield self.exec_command(data.get("resource"), data.get("command")) 37 | self.write(str(response)) 38 | self.finish() 39 | 40 | @run_on_executor 41 | def exec_command(self, resource, command): 42 | """ 43 | use ansible shell module to execute command on inventory. 44 | 45 | Args: 46 | resource: inventory resource, see Resource Class 47 | command: which command you want to execute 48 | Returns: 49 | AnsibleReuslt: AnsibleResult instance, contain the all ansible return information. 50 | """ 51 | res = Ad_Hoc(resource) 52 | result = res.run(command, 'shell') 53 | return result.result_deal 54 | 55 | 56 | class AdHocHandler(RequestHandler): 57 | executor = ThreadPoolExecutor(cpu_count()) 58 | 59 | @asynchronous 60 | @gen.coroutine 61 | def post(self): 62 | try: 63 | data = json.loads(self.request.body) 64 | except ValueError as e: 65 | raise HTTPError(400, reason=e.message) 66 | logger.debug("input data: %s" % data) 67 | resource, module_name, module_arg = data.get("resource"), data.get("module_name"), data.get("module_arg") 68 | if not(resource and module_name and module_arg): 69 | raise HTTPError(400, reason="resource and module_name and module_arg are required.") 70 | 71 | response = yield self.ad_hoc(resource, module_name, module_arg) 72 | self.write(str(response)) 73 | self.finish() 74 | 75 | @run_on_executor 76 | def ad_hoc(self, resource, module_name, module_arg): 77 | """ 78 | 执行ansible hoc-ad 79 | 80 | Args: 81 | resource: ditto 82 | module_name: ditto 83 | module_arg: ditto 84 | """ 85 | res = Ad_Hoc(resource) 86 | result = res.run(module_arg, module_name) 87 | return result.result_deal 88 | 89 | 90 | class PlaybookHandler(RequestHandler): 91 | executor = ThreadPoolExecutor(cpu_count()) 92 | 93 | @asynchronous 94 | @gen.coroutine 95 | def post(self): 96 | try: 97 | data = json.loads(self.request.body) 98 | except ValueError as e: 99 | raise HTTPError(400, reason=e.message) 100 | logger.debug("input data: %s" % data) 101 | resource, playbook = data.get("resource"), data.get("playbook") 102 | if not(resource and playbook): 103 | raise HTTPError(400, reason="resource and playbook are required.") 104 | 105 | response = yield self.run(resource, playbook) 106 | self.write(str(response)) 107 | self.finish() 108 | 109 | @run_on_executor 110 | def run(self, resource, playbook): 111 | """ 112 | 执行ansible playbook 113 | 114 | Args: 115 | resource: ditto 116 | playbook: ditto 117 | """ 118 | res = MyPlaybook(resource, playbook) 119 | result = res.run() 120 | return result 121 | 122 | -------------------------------------------------------------------------------- /libs/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from my_ansible_api import config_ansible 4 | 5 | config_ansible() 6 | -------------------------------------------------------------------------------- /libs/my_ansible_api.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Purpose: This module is for custom ansible api for tornado. 4 | Author: Yu Maojun 5 | Date: 2016-03-20 6 | Version: 0.0.1 7 | """ 8 | 9 | 10 | from __future__ import print_function, unicode_literals 11 | from ansible.inventory import Inventory 12 | from ansible.inventory.group import Group 13 | from ansible.inventory.host import Host 14 | from ansible.runner import Runner 15 | from ansible.playbook import PlayBook 16 | from ansible import callbacks, utils 17 | 18 | import os 19 | import ansible.constants as C 20 | 21 | ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 22 | PLAYBOOK_DIR = os.path.join(ROOT_DIR, 'ansible_playbooks') 23 | 24 | 25 | def config_ansible(): 26 | C.HOST_KEY_CHECKING = False 27 | C.DEFAULT_MODULE_PATH = os.path.join(ROOT_DIR, 'extra_ansible_modules') 28 | 29 | 30 | class AnsibleError(StandardError): 31 | """ 32 | the base AnsibleError which contains all error message. 33 | 34 | Attributes: 35 | message: the main error message 36 | kwargs: the other message data 37 | """ 38 | def __init__(self, message='', **kwargs): 39 | super(AnsibleError, self).__init__(message) 40 | self.message = message 41 | for key, value in kwargs.items(): 42 | setattr(self, key, value) 43 | 44 | 45 | class CommandError(AnsibleError): 46 | """ 47 | the ansible command execute error. 48 | """ 49 | def __init__(self, message=''): 50 | super(CommandError, self).__init__(message) 51 | 52 | 53 | class ResourceBase(object): 54 | """ 55 | gen_inventory methods. 56 | 57 | Attributes: 58 | resource: the inventory's resource. format: 59 | { 60 | "group1": { 61 | "hosts": [{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...], 62 | "vars": {"var1": value1, "var2": value2, ...} 63 | } 64 | } 65 | if your pass a list, the list will add the default group(default_group) 66 | [{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...] 67 | inventory: ansible inventory object use gen_inventory to generate. 68 | Methods: 69 | gen_inventory: generate a ansible inventory object. 70 | """ 71 | 72 | def __init__(self, resource): 73 | self.inventory = Inventory(host_list=[]) 74 | self.resource = resource 75 | self.gen_inventory() 76 | 77 | @staticmethod 78 | def add_group_vars(group, group_vars=None): 79 | """ 80 | if group_vars exists then, add group variable to group 81 | 82 | Args: 83 | group: ansible group object 84 | group_vars: group variables 85 | """ 86 | assert isinstance(group, Group), "the group must be an ansible group object." 87 | 88 | if group_vars: 89 | for key, value in group_vars.iteritems(): 90 | group.set_variable(key, value) 91 | 92 | @staticmethod 93 | def gen_hosts(hosts=None): 94 | """ 95 | if host_vars exists then, generate hosts 96 | 97 | Args: 98 | hosts: [, , ...] 99 | Returns: 100 | host_objs: [, , ...] 101 | """ 102 | assert isinstance(hosts, list), "the hosts must be a list" 103 | host_objs = [] 104 | if hosts: 105 | for host in hosts: 106 | hostname = host.get("hostname") 107 | hostip = host.get('ip', hostname) 108 | hostport = host.get("port") 109 | username = host.get("username") 110 | password = host.get("password") 111 | ssh_key = host.get("ssh_key") 112 | 113 | my_host = Host(name=hostname, port=hostport) 114 | my_host.set_variable('ansible_ssh_host', hostip) 115 | my_host.set_variable('ansible_ssh_port', hostport) 116 | my_host.set_variable('ansible_ssh_user', username) 117 | 118 | if password: 119 | my_host.set_variable('ansible_ssh_pass', password) 120 | if ssh_key: 121 | my_host.set_variable('ansible_ssh_private_key_file', ssh_key) 122 | 123 | # set other variables 124 | for key, value in host.iteritems(): 125 | if key not in ["hostname", "port", "username", "password", "ip", "ssh_key"]: 126 | my_host.set_variable(key, value) 127 | host_objs.append(my_host) 128 | return host_objs 129 | 130 | def my_add_group(self, hosts_vars, group_name, group_vars=None): 131 | """ 132 | add hosts to group. use to generate a inventory. 133 | 134 | Args: 135 | hosts_vars: the hosts variables 136 | group_name: group name 137 | group_vars: group variables 138 | """ 139 | my_group = Group(name=group_name) 140 | self.add_group_vars(my_group, group_vars) 141 | for host in self.gen_hosts(hosts_vars): 142 | my_group.add_host(host) 143 | self.inventory.add_group(my_group) 144 | 145 | def gen_inventory(self): 146 | """ 147 | add hosts to an inventory. 148 | """ 149 | if isinstance(self.resource, list): 150 | self.my_add_group(self.resource, 'default_group') 151 | elif isinstance(self.resource, dict): 152 | for group_name, hosts_vars in self.resource.iteritems(): 153 | self.my_add_group(hosts_vars.get("hosts"), group_name, hosts_vars.get("vars")) 154 | 155 | 156 | class Ad_Hoc(ResourceBase): 157 | """ 158 | execute ansible ad-hoc mode in inventory. 159 | 160 | Args: 161 | resource: the inventory resource, the resource format see MyRunner on top of this module 162 | command: which command your want to run in this resource 163 | Attributes: 164 | results_raw: the raw data returned after ansible run. 165 | """ 166 | def __init__(self, resource): 167 | super(Ad_Hoc, self).__init__(resource) 168 | self.results_raw = {} 169 | 170 | def run(self, module_arg, module_name="shell", timeout=10, forks=10, pattern='*'): 171 | """ 172 | run command from andible ad-hoc. 173 | 174 | Args: 175 | module_arg: ansible module argument 176 | module_name: which module want to use, default use shell 177 | timeout: set runner api 178 | forks: see runner api 179 | pattern: set runner api 180 | """ 181 | hoc = Runner(module_name=module_name, 182 | module_args=module_arg, 183 | timeout=timeout, 184 | inventory=self.inventory, 185 | pattern=pattern, 186 | forks=forks, 187 | ) 188 | self.results_raw = hoc.run() 189 | return AnsibleResult(self.results_raw) 190 | 191 | 192 | class AnsibleResult(object): 193 | """ 194 | container ansible return result. 195 | 196 | Attributes: 197 | result_raw: ansible return raw data 198 | """ 199 | def __init__(self, raw_data): 200 | self.result_raw = raw_data 201 | 202 | @property 203 | def dark(self): 204 | """ 205 | return the failed dark message. 206 | 207 | Returns: 208 | failed: eg:{'failed': {'localhost': ''}} 209 | """ 210 | failed = {} 211 | dark = self.result_raw.get("dark") 212 | if dark: 213 | for host, info in dark.items(): 214 | failed[host] = info.get('msg') 215 | return failed 216 | 217 | @property 218 | def contacted(self): 219 | """ 220 | return the contacted message. 221 | 222 | Returns: 223 | contacted: {'failed': {'host1': ''}, 'ok': {'host2': ''}} 224 | """ 225 | result = {'failed': {}, 'ok': {}} 226 | contacted = self.result_raw.get("contacted") 227 | if contacted: 228 | for host, info in contacted.items(): 229 | if info.get('invocation').get('module_name') in ['raw', 'shell', 'command', 'script']: 230 | if info.get('rc') == 0: 231 | result['ok'][host] = info.get('stdout') + info.get('stderr') 232 | else: 233 | result['failed'][host] = info.get('stdout') + info.get('stderr') 234 | else: 235 | if info.get('failed'): 236 | result['failed'][host] = info.get('msg') 237 | else: 238 | result['ok'][host] = info.get('changed') 239 | return result 240 | 241 | @property 242 | def result_deal(self): 243 | """ 244 | deal the ansible return result. 245 | 246 | Returns: 247 | results: eg: {'failed': {'host1': ''}, 'ok': {'host2': ''}} 248 | """ 249 | results = {'failed': {}, 'ok': {}} 250 | if self.dark: 251 | results['failed'].update(**self.dark) 252 | if self.contacted: 253 | results['failed'].update(**self.contacted['failed']) 254 | results['ok'].update(**self.contacted['ok']) 255 | return results 256 | 257 | def __unicode__(self): 258 | return "%s" % self.result_raw 259 | 260 | def __str__(self): 261 | return self.__unicode__() 262 | 263 | 264 | class MyPlaybook(ResourceBase): 265 | """ 266 | this is my playbook object for execute playbook. 267 | 268 | Attributes: 269 | resource: resource dict ,see ResourceBase class 270 | playbook_path: relational playbook path, the default playbook directory is: 271 | """ 272 | def __init__(self, resource, playbook_path): 273 | super(MyPlaybook, self).__init__(resource) 274 | self.results_raw = None 275 | self.playbook_path = playbook_path 276 | 277 | def run(self, extra_vars=None): 278 | """ 279 | run ansible playbook, only surport relational path. 280 | 281 | Args: 282 | extra_vars: playbook extra variables. 283 | """ 284 | stats = callbacks.AggregateStats() 285 | playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY) 286 | runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY) 287 | playbook_path = os.path.join(PLAYBOOK_DIR, self.playbook_path) 288 | 289 | pb = PlayBook( 290 | playbook=playbook_path, 291 | stats=stats, 292 | callbacks=playbook_cb, 293 | runner_callbacks=runner_cb, 294 | inventory=self.inventory, 295 | extra_vars=extra_vars, 296 | check=False) 297 | 298 | self.results_raw = pb.run() 299 | return self.results_raw 300 | 301 | 302 | if __name__ == "__main__": 303 | resource = [{"hostname": "192.168.10.148", "port": "22", "username": "root", "password": "mypass"}] 304 | cmd = Ad_Hoc(resource) 305 | result = cmd.run('time') 306 | print(result.result_deal) 307 | -------------------------------------------------------------------------------- /libs/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from settings import mongoinfo 5 | import hashlib 6 | from pymongo import MongoClient 7 | 8 | 9 | def get_md5(s): 10 | """ 11 | hash 一段字符串 12 | 13 | Args: 14 | s: 一段字符串 15 | Returns: 16 | digest: hash过后的digest 17 | """ 18 | m = hashlib.md5() 19 | m.update(s) 20 | return m.hexdigest() 21 | 22 | 23 | def conn_mongodb(): 24 | """ 25 | 返回一个mongodb的uri,用于链接mongodb 26 | """ 27 | dbhost = mongoinfo['host'] 28 | dbport = mongoinfo['port'] 29 | dbuser = mongoinfo['user'] 30 | dbpwd = mongoinfo['password'] 31 | dbname = mongoinfo['dbname'] 32 | uri = 'mongodb://%s:%s@%s:%s/%s' % (dbuser, dbpwd, dbhost, dbport, dbname) 33 | return MongoClient(uri, safe=False) 34 | -------------------------------------------------------------------------------- /logconfig/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /logconfig/logconfig.py: -------------------------------------------------------------------------------- 1 | # An extended version of the log_settings module from zamboni: 2 | # https://github.com/jbalogh/zamboni/blob/master/log_settings.py 3 | 4 | from __future__ import absolute_import 5 | 6 | from logging.config import dictConfig 7 | import os.path 8 | 9 | PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10 | LOG_DIR = os.path.join(PROJECT_DIR, 'logs') 11 | 12 | LOGGING = { 13 | 'version': 1, 14 | 'disable_existing_loggers': True, 15 | 'formatters': { 16 | 'standard': { 17 | 'format': '%(asctime)s - %(filename)s:%(lineno)d(%(module)s:%(funcName)s) - %(levelname)s - %(message)s', 18 | 'datefmt': '%Y-%m-%d %H:%M:%S' 19 | }, 20 | 'simple': { 21 | 'format': '%(asctime)s - %(levelname)s - %(message)s', 22 | 'datefmt': '%Y-%m-%d %H:%M:%S' 23 | }, 24 | }, 25 | 'filters': { 26 | }, 27 | 'handlers': { 28 | 'null': { 29 | 'level': 'DEBUG', 30 | 'class': 'logging.NullHandler', 31 | }, 32 | 'console': { 33 | 'level': 'DEBUG', 34 | 'class': 'logging.StreamHandler', 35 | 'formatter': 'standard' 36 | }, 37 | 'syslog': { 38 | 'level': 'DEBUG', 39 | 'class': 'logging.handlers.SysLogHandler', 40 | 'facility': 'logging.handlers.SysLogHandler.LOG_LOCAL7', 41 | 'formatter': 'standard', 42 | }, 43 | 'syslog2': { 44 | 'level': 'DEBUG', 45 | 'class': 'logging.handlers.SysLogHandler', 46 | 'facility': 'logging.handlers.SysLogHandler.LOG_LOCAL7', 47 | 'formatter': 'standard', 48 | }, 49 | 'access': { 50 | 'level': 'DEBUG', 51 | 'class': 'logging.handlers.RotatingFileHandler', 52 | 'filename': os.path.join(LOG_DIR, 'access.log'), 53 | 'maxBytes': 1024*1024*2, 54 | 'backupCount': 5, 55 | 'formatter': 'standard', 56 | }, 57 | 'application': { 58 | 'level': 'DEBUG', 59 | 'class': 'logging.handlers.RotatingFileHandler', 60 | 'filename': os.path.join(LOG_DIR, 'app.log'), 61 | 'maxBytes': 1024*1024*2, 62 | 'backupCount': 5, 63 | 'formatter': 'standard', 64 | }, 65 | 'general': { 66 | 'level': 'DEBUG', 67 | 'class': 'logging.handlers.RotatingFileHandler', 68 | 'filename': os.path.join(LOG_DIR, 'gen.log'), 69 | 'maxBytes': 1024*1024*2, 70 | 'backupCount': 5, 71 | 'formatter': 'standard', 72 | }, 73 | }, 74 | 'loggers': { 75 | 'tornado': { 76 | 'handlers': ['console'], 77 | 'level': 'DEBUG', 78 | 'propagate': False 79 | }, 80 | 'tornado.access': { 81 | 'handlers': ['access'], 82 | 'level': 'DEBUG', 83 | 'propagate': False, 84 | }, 85 | 'tornado.app': { 86 | 'handlers': ['application'], 87 | 'level': 'DEBUG', 88 | 'propagate': True 89 | }, 90 | 'tornado.gen': { 91 | 'handlers': ['general'], 92 | 'level': 'DEBUG', 93 | 'propagate': True 94 | } 95 | } 96 | } 97 | 98 | 99 | def init_logging(): 100 | """ 101 | initial logging 102 | """ 103 | dictConfig(LOGGING) 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /requirements/requirements.txt: -------------------------------------------------------------------------------- 1 | pika==0.9.14 -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | import tornado 2 | import tornado.template 3 | import os 4 | from tornado.options import define, options 5 | 6 | # add need module to PYTHONPATH 7 | import environment 8 | 9 | 10 | # Make filepaths relative to settings. 11 | path = lambda root, *a: os.path.join(root, *a) 12 | ROOT = os.path.dirname(os.path.abspath(__file__)) 13 | 14 | define("port", default=8888, help="run on the given port", type=int) 15 | define("config", default=None, help="tornado config file") 16 | define("debug", default=True, help="debug mode") 17 | tornado.options.parse_command_line() 18 | 19 | settings = {} 20 | settings['xsrf_cookies'] = False 21 | 22 | # See PEP 391 and logconfig for formatting help. Each section of LOGGERS 23 | # will get merged into the corresponding section of log_settings.py. 24 | # Handlers and log levels are set up automatically based on LOG_LEVEL and DEBUG 25 | # unless you set them here. Messages will not propagate through a logger 26 | # unless propagate: True is set. 27 | from logconfig.logconfig import init_logging 28 | init_logging() 29 | 30 | if options.config: 31 | tornado.options.parse_config_file(options.config) 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /urls.py: -------------------------------------------------------------------------------- 1 | from handlers.ansible_async import MainHandler, CommandHandler, AdHocHandler, PlaybookHandler 2 | 3 | url_patterns = [ 4 | (r"/", MainHandler), 5 | (r"/command", CommandHandler), 6 | (r"/ad_hoc", AdHocHandler), 7 | (r"/playbook", PlaybookHandler), 8 | ] --------------------------------------------------------------------------------