tools/worlddump.py
97fcc7b2
 #!/usr/bin/env python
 #
 # Copyright 2014 Hewlett-Packard Development Company, L.P.
 #
 # Licensed under the Apache License, Version 2.0 (the "License"); you may
 # not use this file except in compliance with the License. You may obtain
 # a copy of the License at
 #
 #      http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 # License for the specific language governing permissions and limitations
 # under the License.
 
 """Dump the state of the world for post mortem."""
 
 import argparse
 import datetime
737e9420
 import fnmatch
97fcc7b2
 import os
 import os.path
99440f9d
 import subprocess
97fcc7b2
 import sys
 
 
 def get_options():
     parser = argparse.ArgumentParser(
         description='Dump world state for debugging')
     parser.add_argument('-d', '--dir',
                         default='.',
                         help='Output directory for worlddump')
ac9313e5
     parser.add_argument('-n', '--name',
                         default='',
                         help='Additional name to tag into file')
97fcc7b2
     return parser.parse_args()
 
 
ac9313e5
 def filename(dirname, name=""):
97fcc7b2
     now = datetime.datetime.utcnow()
ac9313e5
     fmt = "worlddump-%Y-%m-%d-%H%M%S"
     if name:
         fmt += "-" + name
     fmt += ".txt"
     return os.path.join(dirname, now.strftime(fmt))
97fcc7b2
 
 
 def warn(msg):
     print "WARN: %s" % msg
 
 
60a14057
 def _dump_cmd(cmd):
     print cmd
     print "-" * len(cmd)
     print
99440f9d
     try:
         subprocess.check_call(cmd, shell=True)
     except subprocess.CalledProcessError:
         print "*** Failed to run: %s" % cmd
60a14057
 
 
 def _header(name):
     print
     print name
     print "=" * len(name)
     print
 
 
97fcc7b2
 def disk_space():
     # the df output
60a14057
     _header("File System Summary")
 
97fcc7b2
     dfraw = os.popen("df -Ph").read()
     df = [s.split() for s in dfraw.splitlines()]
     for fs in df:
         try:
             if int(fs[4][:-1]) > 95:
                 warn("Device %s (%s) is %s full, might be an issue" % (
                     fs[0], fs[5], fs[4]))
         except ValueError:
             # if it doesn't look like an int, that's fine
             pass
 
     print dfraw
 
 
2da606da
 def ebtables_dump():
     _header("EB Tables Dump")
     _dump_cmd("sudo ebtables -L")
 
 
168b7c22
 def iptables_dump():
     tables = ['filter', 'nat', 'mangle']
60a14057
     _header("IP Tables Dump")
 
168b7c22
     for table in tables:
60a14057
         _dump_cmd("sudo iptables --line-numbers -L -nv -t %s" % table)
 
 
 def network_dump():
     _header("Network Dump")
 
     _dump_cmd("brctl show")
     _dump_cmd("arp -n")
     _dump_cmd("ip addr")
     _dump_cmd("ip link")
     _dump_cmd("ip route")
168b7c22
 
 
97fcc7b2
 def process_list():
60a14057
     _header("Process Listing")
     _dump_cmd("ps axo "
               "user,ppid,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,args")
97fcc7b2
 
 
737e9420
 def compute_consoles():
     _header("Compute consoles")
     for root, dirnames, filenames in os.walk('/opt/stack'):
         for filename in fnmatch.filter(filenames, 'console.log'):
             fullpath = os.path.join(root, filename)
             _dump_cmd("sudo cat %s" % fullpath)
 
 
2ebe993b
 def guru_meditation_report():
     _header("nova-compute Guru Meditation Report")
3a9df1da
 
     try:
         subprocess.check_call(["pgrep","nova-compute"])
     except subprocess.CalledProcessError:
         print "Skipping as nova-compute does not appear to be running"
         return
 
2ebe993b
     _dump_cmd("kill -s USR1 `pgrep nova-compute`")
     print "guru meditation report in nova-compute log"
 
 
97fcc7b2
 def main():
     opts = get_options()
ac9313e5
     fname = filename(opts.dir, opts.name)
97fcc7b2
     print "World dumping... see %s for details" % fname
     sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
     with open(fname, 'w') as f:
         os.dup2(f.fileno(), sys.stdout.fileno())
         disk_space()
         process_list()
60a14057
         network_dump()
168b7c22
         iptables_dump()
2da606da
         ebtables_dump()
737e9420
         compute_consoles()
2ebe993b
         guru_meditation_report()
97fcc7b2
 
 
 if __name__ == '__main__':
     try:
         sys.exit(main())
     except KeyboardInterrupt:
         sys.exit(1)