summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/docker-compose.yml2
-rwxr-xr-xtools/docker-compose/start_development.sh1
-rw-r--r--tools/rdb.py231
3 files changed, 234 insertions, 0 deletions
diff --git a/tools/docker-compose.yml b/tools/docker-compose.yml
index da7abb7472..26b851db21 100644
--- a/tools/docker-compose.yml
+++ b/tools/docker-compose.yml
@@ -16,6 +16,8 @@ services:
- "8013:8013"
- "8043:8043"
- "6899-6999:6899-6999" # default port range for celery.contrib.rdb
+ extra_hosts:
+ - "dockerhost:${DOCKER_HOST_IP}"
links:
- postgres
- memcached
diff --git a/tools/docker-compose/start_development.sh b/tools/docker-compose/start_development.sh
index 9814a9344c..56a5c968a1 100755
--- a/tools/docker-compose/start_development.sh
+++ b/tools/docker-compose/start_development.sh
@@ -25,6 +25,7 @@ fi
cp -nR /tmp/ansible_tower.egg-info /tower_devel/ || true
cp /tmp/ansible-tower.egg-link /venv/tower/lib/python2.7/site-packages/ansible-tower.egg-link
+ln -s /tower_devel/tools/rdb.py /venv/tower/lib/python2.7/site-packages/rdb.py
yes | cp -rf /tower_devel/tools/docker-compose/supervisor.conf /supervisor.conf
# Tower bootstrapping
diff --git a/tools/rdb.py b/tools/rdb.py
new file mode 100644
index 0000000000..227d2448e5
--- /dev/null
+++ b/tools/rdb.py
@@ -0,0 +1,231 @@
+import rlcompleter
+try:
+ import readline
+except ImportError:
+ print("Module readline not available.")
+else:
+ if 'libedit' in readline.__doc__:
+ readline.parse_and_bind("bind ^I rl_complete")
+ else:
+ readline.parse_and_bind("tab: complete")
+
+import sys
+from celery.contrib.rdb import Rdb
+
+import cmd
+import contextlib
+import os
+import pprint
+import re
+import select
+import socket
+import threading
+from cStringIO import StringIO
+from Queue import Queue, Empty
+
+from pygments import highlight
+from pygments.lexers import PythonLexer
+from pygments.formatters import Terminal256Formatter
+
+
+@contextlib.contextmanager
+def style(im_self, filepart=None, lexer=None):
+
+ lexer = PythonLexer
+ old_stdout = im_self.stdout
+ buff = StringIO()
+ im_self.stdout = buff
+ yield
+
+ value = buff.getvalue()
+ context = len(value.splitlines())
+ file_cache = {}
+
+ if filepart:
+ filepath, lineno = filepart
+ if filepath not in file_cache:
+ with open(filepath, 'r') as source:
+ file_cache[filepath] = source.readlines()
+ value = ''.join(file_cache[filepath][:lineno - 1]) + value
+
+ formatter = Terminal256Formatter(style='friendly')
+ value = highlight(value, lexer(), formatter)
+
+ # Properly format line numbers when they show up in multi-line strings
+ strcolor, _ = formatter.style_string['Token.Literal.String']
+ intcolor, _ = formatter.style_string['Token.Literal.Number.Integer']
+ value = re.sub(
+ r'%s([0-9]+)' % re.escape(strcolor),
+ lambda match: intcolor + match.group(1) + strcolor,
+ value,
+ )
+
+ # Highlight the "current" line in yellow for visibility
+ lineno = im_self.curframe.f_lineno
+
+ value = re.sub(
+ '(?<!\()%s%s[^\>]+>[^\[]+\[39m([^\x1b]+)[^m]+m([^\n]+)' % (re.escape(intcolor), lineno),
+ lambda match: ''.join([
+ str(lineno),
+ ' ->',
+ '\x1b[93m',
+ match.group(1),
+ re.sub('\x1b[^m]+m', '', match.group(2)),
+ '\x1b[0m'
+ ]),
+ value
+ )
+
+ if filepart:
+ _, first = filepart
+ value = '\n'.join(value.splitlines()[-context:]) + '\n'
+
+ if value.strip():
+ old_stdout.write(value)
+ im_self.stdout = old_stdout
+
+
+class CustomPdb(Rdb):
+
+ def cmdloop(self):
+ self.do_list(tuple())
+ return cmd.Cmd.cmdloop(self)
+
+ def do_list(self, args):
+ lines = 60
+ context = (lines - 2) / 2
+ if not args:
+ first = max(1, self.curframe.f_lineno - context)
+ last = first + context * 2 - 1
+ args = "(%s, %s)" % (first, last)
+ self.lineno = None
+ with style(self, (
+ self.curframe.f_code.co_filename, self.curframe.f_lineno - context)
+ ):
+ return Rdb.do_list(self, args)
+ do_l = do_list
+
+ def format_stack_entry(self, *args, **kwargs):
+ entry = Rdb.format_stack_entry(self, *args, **kwargs)
+ return '\n'.join(
+ filter(lambda x: not x.startswith('->'), entry.splitlines())
+ )
+
+ def print_stack_entry(self, *args, **kwargs):
+ with style(self):
+ return Rdb.print_stack_entry(self, *args, **kwargs)
+
+ def set_next(self, curframe):
+ os.system('clear')
+ Rdb.set_next(self, curframe)
+
+ def set_return(self, arg):
+ os.system('clear')
+ Rdb.set_return(self, arg)
+
+ def set_step(self):
+ os.system('clear')
+ Rdb.set_step(self)
+
+ def default(self, line):
+ with style(self):
+ return Rdb.default(self, line)
+
+ def parseline(self, line):
+ line = line.strip()
+ match = re.search('^([0-9]+)([a-zA-Z]+)', line)
+ if match:
+ times, command = match.group(1), match.group(2)
+ line = command
+ self.cmdqueue.extend(list(command * (int(times) - 1)))
+ if line == '?':
+ line = 'dir()'
+ elif line.endswith('??'):
+ line = "import inspect; print ''.join(inspect.getsourcelines(%s)[0][:25])" % line[:-2]
+ elif line.endswith('?'):
+ line = 'dir(%s)' % line[:-1]
+ return cmd.Cmd.parseline(self, line)
+
+ def displayhook(self, obj):
+ if obj is not None and not isinstance(obj, list):
+ return pprint.pprint(obj)
+ return Rdb.displayhook(self, obj)
+
+ def get_avail_port(self, *args, **kwargs):
+ sock, port = Rdb.get_avail_port(self, *args, **kwargs)
+ socket.socket(socket.AF_INET, socket.SOCK_DGRAM).sendto(
+ str(port), ('dockerhost', 6899)
+ )
+ return (sock, port)
+
+
+CustomPdb.complete = rlcompleter.Completer(locals()).complete
+
+
+def set_trace():
+ return CustomPdb().set_trace(sys._getframe().f_back)
+
+
+def listen():
+ queue = Queue()
+
+ def _consume(queue):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.bind(('0.0.0.0', 6899))
+ print 'listening for rdb notifications on :6899...'
+ while True:
+ r, w, x = select.select([sock], [], [])
+ for i in r:
+ data = i.recv(1024)
+ queue.put(data)
+ worker = threading.Thread(target=_consume, args=(queue,))
+ worker.setDaemon(True)
+ worker.start()
+
+ try:
+ while True:
+ try:
+ port = queue.get(timeout=1)
+ queue.task_done()
+ if port == 'q':
+ break
+ port = int(port)
+ print 'opening telnet session at localhost:%d...' % port
+ telnet(port)
+ print 'listening for rdb notifications on :6899...'
+ except Empty:
+ pass
+ except KeyboardInterrupt:
+ print 'got Ctrl-C'
+ queue.put('q')
+
+
+def telnet(port):
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.settimeout(2)
+
+ try:
+ s.connect(('0.0.0.0', port))
+ except:
+ print 'unable to connect'
+ return
+ print 'connected to 0.0.0.0:%d' % port
+
+ while True:
+ socket_list = [sys.stdin, s]
+ r, w, e = select.select(socket_list , [], [])
+ for sock in r:
+ if sock == s:
+ data = sock.recv(4096)
+ if not data:
+ print 'connection closed'
+ return
+ else:
+ sys.stdout.write(data)
+ else:
+ msg = sys.stdin.readline()
+ s.send(msg)
+
+
+if __name__ == '__main__':
+ listen()