blob: 1244dfbec36d40b1e5da29555e1d907cd8924c48 [file] [log] [blame]
Sean Dague97fcc7b2014-06-16 17:24:14 -04001#!/usr/bin/env python
2#
3# Copyright 2014 Hewlett-Packard Development Company, L.P.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
Eyale7361772016-04-05 16:18:56 +030017
Sean Dague97fcc7b2014-06-16 17:24:14 -040018"""Dump the state of the world for post mortem."""
19
John L. Villalovos09949e02017-02-06 13:46:32 -080020from __future__ import print_function
21
Sean Dague97fcc7b2014-06-16 17:24:14 -040022import argparse
23import datetime
Chris Dent57d79672016-02-23 15:38:43 +000024from distutils import spawn
Sean Dague737e9422015-05-12 19:51:39 -040025import fnmatch
Sean Dague97fcc7b2014-06-16 17:24:14 -040026import os
27import os.path
Ian Wienand99440f92015-07-01 06:14:01 +100028import subprocess
Sean Dague97fcc7b2014-06-16 17:24:14 -040029import sys
30
31
Ihar Hrachyshkaef219bf2016-02-11 13:54:48 +010032GMR_PROCESSES = (
33 'nova-compute',
34 'neutron-dhcp-agent',
35 'neutron-l3-agent',
36 'neutron-linuxbridge-agent',
37 'neutron-metadata-agent',
38 'neutron-openvswitch-agent',
Eric Harneyd8682db2016-10-14 14:36:29 -040039 'cinder-volume',
Ihar Hrachyshkaef219bf2016-02-11 13:54:48 +010040)
41
42
Sean Dague97fcc7b2014-06-16 17:24:14 -040043def get_options():
44 parser = argparse.ArgumentParser(
45 description='Dump world state for debugging')
46 parser.add_argument('-d', '--dir',
47 default='.',
48 help='Output directory for worlddump')
Sean Dagueac9313e2015-07-27 13:33:30 -040049 parser.add_argument('-n', '--name',
50 default='',
51 help='Additional name to tag into file')
Sean Dague97fcc7b2014-06-16 17:24:14 -040052 return parser.parse_args()
53
54
Sean Dagueac9313e2015-07-27 13:33:30 -040055def filename(dirname, name=""):
Sean Dague97fcc7b2014-06-16 17:24:14 -040056 now = datetime.datetime.utcnow()
Sean Dagueac9313e2015-07-27 13:33:30 -040057 fmt = "worlddump-%Y-%m-%d-%H%M%S"
58 if name:
59 fmt += "-" + name
60 fmt += ".txt"
61 return os.path.join(dirname, now.strftime(fmt))
Sean Dague97fcc7b2014-06-16 17:24:14 -040062
63
64def warn(msg):
Eyale7361772016-04-05 16:18:56 +030065 print("WARN: %s" % msg)
Sean Dague97fcc7b2014-06-16 17:24:14 -040066
67
Sean Dague60a14052015-05-11 14:53:39 -040068def _dump_cmd(cmd):
Eyale7361772016-04-05 16:18:56 +030069 print(cmd)
70 print("-" * len(cmd))
71 print()
Ian Wienand99440f92015-07-01 06:14:01 +100072 try:
73 subprocess.check_call(cmd, shell=True)
Eyale7361772016-04-05 16:18:56 +030074 print()
Ihar Hrachyshka7976aac2016-03-03 15:30:49 +010075 except subprocess.CalledProcessError as e:
Eyale7361772016-04-05 16:18:56 +030076 print("*** Failed to run '%(cmd)s': %(err)s" % {'cmd': cmd, 'err': e})
Sean Dague60a14052015-05-11 14:53:39 -040077
78
Chris Dent57d79672016-02-23 15:38:43 +000079def _find_cmd(cmd):
80 if not spawn.find_executable(cmd):
Eyale7361772016-04-05 16:18:56 +030081 print("*** %s not found: skipping" % cmd)
Chris Dent57d79672016-02-23 15:38:43 +000082 return False
83 return True
84
85
Sean Dague60a14052015-05-11 14:53:39 -040086def _header(name):
Eyale7361772016-04-05 16:18:56 +030087 print()
88 print(name)
89 print("=" * len(name))
90 print()
Sean Dague60a14052015-05-11 14:53:39 -040091
92
fumihiko kakuma578459f2016-04-07 08:15:45 +090093def _bridge_list():
yan.haifeng6ba17f72016-04-29 15:59:56 +080094 process = subprocess.Popen(['sudo', 'ovs-vsctl', 'list-br'],
95 stdout=subprocess.PIPE)
fumihiko kakuma578459f2016-04-07 08:15:45 +090096 stdout, _ = process.communicate()
97 return stdout.split()
98
99
fumihiko kakuma60994012016-03-08 20:55:01 +0900100# This method gets a max openflow version supported by openvswitch.
101# For example 'ovs-ofctl --version' displays the following:
102#
103# ovs-ofctl (Open vSwitch) 2.0.2
104# Compiled Dec 9 2015 14:08:08
105# OpenFlow versions 0x1:0x4
106#
fumihiko kakuma2bd25682016-04-05 10:33:50 +0900107# The above shows that openvswitch supports from OpenFlow10 to OpenFlow13.
fumihiko kakuma60994012016-03-08 20:55:01 +0900108# This method gets max version searching 'OpenFlow versions 0x1:0x'.
109# And return a version value converted to an integer type.
110def _get_ofp_version():
111 process = subprocess.Popen(['ovs-ofctl', '--version'], stdout=subprocess.PIPE)
112 stdout, _ = process.communicate()
113 find_str = 'OpenFlow versions 0x1:0x'
114 offset = stdout.find(find_str)
115 return int(stdout[offset + len(find_str):-1]) - 1
116
117
Sean Dague97fcc7b2014-06-16 17:24:14 -0400118def disk_space():
119 # the df output
Sean Dague60a14052015-05-11 14:53:39 -0400120 _header("File System Summary")
121
Sean Dague97fcc7b2014-06-16 17:24:14 -0400122 dfraw = os.popen("df -Ph").read()
123 df = [s.split() for s in dfraw.splitlines()]
124 for fs in df:
125 try:
126 if int(fs[4][:-1]) > 95:
127 warn("Device %s (%s) is %s full, might be an issue" % (
128 fs[0], fs[5], fs[4]))
129 except ValueError:
130 # if it doesn't look like an int, that's fine
131 pass
132
Eyale7361772016-04-05 16:18:56 +0300133 print(dfraw)
Sean Dague97fcc7b2014-06-16 17:24:14 -0400134
135
Sean Dague2da606d2015-08-06 10:02:43 -0400136def ebtables_dump():
Sean Dague5c5e0862015-11-09 14:08:15 -0500137 tables = ['filter', 'nat', 'broute']
Sean Dague2da606d2015-08-06 10:02:43 -0400138 _header("EB Tables Dump")
Chris Dent57d79672016-02-23 15:38:43 +0000139 if not _find_cmd('ebtables'):
140 return
Sean Dague5c5e0862015-11-09 14:08:15 -0500141 for table in tables:
142 _dump_cmd("sudo ebtables -t %s -L" % table)
Sean Dague2da606d2015-08-06 10:02:43 -0400143
144
Sean Dague168b7c22015-05-07 08:57:28 -0400145def iptables_dump():
146 tables = ['filter', 'nat', 'mangle']
Sean Dague60a14052015-05-11 14:53:39 -0400147 _header("IP Tables Dump")
148
Sean Dague168b7c22015-05-07 08:57:28 -0400149 for table in tables:
Sean Dague60a14052015-05-11 14:53:39 -0400150 _dump_cmd("sudo iptables --line-numbers -L -nv -t %s" % table)
151
152
Ihar Hrachyshka72c34ee2016-01-30 16:18:01 +0100153def _netns_list():
154 process = subprocess.Popen(['ip', 'netns'], stdout=subprocess.PIPE)
155 stdout, _ = process.communicate()
156 return stdout.split()
157
158
Sean Dague60a14052015-05-11 14:53:39 -0400159def network_dump():
160 _header("Network Dump")
161
162 _dump_cmd("brctl show")
163 _dump_cmd("arp -n")
Ihar Hrachyshka72c34ee2016-01-30 16:18:01 +0100164 ip_cmds = ["addr", "link", "route"]
165 for cmd in ip_cmds + ['netns']:
166 _dump_cmd("ip %s" % cmd)
167 for netns_ in _netns_list():
168 for cmd in ip_cmds:
169 args = {'netns': netns_, 'cmd': cmd}
170 _dump_cmd('sudo ip netns exec %(netns)s ip %(cmd)s' % args)
Sean Dague168b7c22015-05-07 08:57:28 -0400171
172
Ihar Hrachyshkac1b7cb12016-02-11 13:50:46 +0100173def ovs_dump():
174 _header("Open vSwitch Dump")
175
Chris Dent57d79672016-02-23 15:38:43 +0000176 # NOTE(cdent): If we're not using neutron + ovs these commands
177 # will not be present so
178 if not _find_cmd('ovs-vsctl'):
179 return
180
fumihiko kakuma578459f2016-04-07 08:15:45 +0900181 bridges = _bridge_list()
fumihiko kakuma60994012016-03-08 20:55:01 +0900182 ofctl_cmds = ('show', 'dump-ports-desc', 'dump-ports', 'dump-flows')
183 ofp_max = _get_ofp_version()
184 vers = 'OpenFlow10'
fumihiko kakuma578459f2016-04-07 08:15:45 +0900185 for i in range(1, ofp_max + 1):
fumihiko kakuma60994012016-03-08 20:55:01 +0900186 vers += ',OpenFlow1' + str(i)
Ihar Hrachyshkac1b7cb12016-02-11 13:50:46 +0100187 _dump_cmd("sudo ovs-vsctl show")
fumihiko kakuma60994012016-03-08 20:55:01 +0900188 for ofctl_cmd in ofctl_cmds:
189 for bridge in bridges:
190 args = {'vers': vers, 'cmd': ofctl_cmd, 'bridge': bridge}
191 _dump_cmd("sudo ovs-ofctl --protocols=%(vers)s %(cmd)s %(bridge)s" % args)
Ihar Hrachyshkac1b7cb12016-02-11 13:50:46 +0100192
193
Sean Dague97fcc7b2014-06-16 17:24:14 -0400194def process_list():
Sean Dague60a14052015-05-11 14:53:39 -0400195 _header("Process Listing")
196 _dump_cmd("ps axo "
197 "user,ppid,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,args")
Sean Dague97fcc7b2014-06-16 17:24:14 -0400198
199
Sean Dague737e9422015-05-12 19:51:39 -0400200def compute_consoles():
201 _header("Compute consoles")
202 for root, dirnames, filenames in os.walk('/opt/stack'):
203 for filename in fnmatch.filter(filenames, 'console.log'):
204 fullpath = os.path.join(root, filename)
205 _dump_cmd("sudo cat %s" % fullpath)
206
207
Ihar Hrachyshkaef219bf2016-02-11 13:54:48 +0100208def guru_meditation_reports():
209 for service in GMR_PROCESSES:
210 _header("%s Guru Meditation Report" % service)
Ian Wienand3a9df1d2015-07-01 06:18:47 +1000211
Ihar Hrachyshkaef219bf2016-02-11 13:54:48 +0100212 try:
213 subprocess.check_call(['pgrep', '-f', service])
214 except subprocess.CalledProcessError:
215 print("Skipping as %s does not appear to be running" % service)
216 continue
Ian Wienand3a9df1d2015-07-01 06:18:47 +1000217
Ihar Hrachyshkaef219bf2016-02-11 13:54:48 +0100218 _dump_cmd("killall -e -USR2 %s" % service)
219 print("guru meditation report in %s log" % service)
Joe Gordon2ebe9932015-06-07 16:57:34 +0900220
221
Sean Dague97fcc7b2014-06-16 17:24:14 -0400222def main():
223 opts = get_options()
Sean Dagueac9313e2015-07-27 13:33:30 -0400224 fname = filename(opts.dir, opts.name)
Eyale7361772016-04-05 16:18:56 +0300225 print("World dumping... see %s for details" % fname)
Sean Dague97fcc7b2014-06-16 17:24:14 -0400226 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
227 with open(fname, 'w') as f:
228 os.dup2(f.fileno(), sys.stdout.fileno())
229 disk_space()
230 process_list()
Sean Dague60a14052015-05-11 14:53:39 -0400231 network_dump()
Ihar Hrachyshkac1b7cb12016-02-11 13:50:46 +0100232 ovs_dump()
Sean Dague168b7c22015-05-07 08:57:28 -0400233 iptables_dump()
Sean Dague2da606d2015-08-06 10:02:43 -0400234 ebtables_dump()
Sean Dague737e9422015-05-12 19:51:39 -0400235 compute_consoles()
Ihar Hrachyshkaef219bf2016-02-11 13:54:48 +0100236 guru_meditation_reports()
Sean Dague97fcc7b2014-06-16 17:24:14 -0400237
238
239if __name__ == '__main__':
240 try:
241 sys.exit(main())
242 except KeyboardInterrupt:
243 sys.exit(1)