blob: 9418de8e64e03f7f8582455fce3f77dfea397405 [file] [log] [blame]
Dennis Kempin351024d2013-02-06 11:18:21 -08001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from gzip import GzipFile
6from StringIO import StringIO
7import base64
8import bz2
9import cookielib
10import getpass
11import os
12import os.path
13import re
14import subprocess
15import sys
16import tarfile
17import tempfile
18import urllib2
Dennis Kempinecd9a0c2013-03-27 16:03:46 -070019import zipfile
Dennis Kempin351024d2013-02-06 11:18:21 -080020
21# path to current script directory
22script_dir = os.path.dirname(os.path.realpath(__file__))
23
24# path to the cookies file used for storing the login cookies.
Dennis Kempin136b7322013-02-06 13:20:57 -080025cookies_file = os.path.join(script_dir, "mtedit.cookies")
Dennis Kempin351024d2013-02-06 11:18:21 -080026
27
28def Log(source, options):
29 """
30 Returns a log object containg activity, evdev and system logs.
31 source can be either an ip address to a device from which to
32 download, a url pointing to a feedback report to pull or a filename.
33 """
34 if os.path.exists(source):
35 return FileLog(source, options)
36 else:
37 match = re.search("Report/([0-9]+)", source)
38 if match:
39 return FeedbackLog(match.group(1), options)
40 else:
41 # todo add regex and error message
42 return DeviceLog(source, options)
43
44
45class AbstractLog(object):
46 """
47 A log file consists of the activity log, the evdev log and
48 a system log which can be saved to disk all together.
49 """
50 def SaveAs(self, filename):
51 open(filename, "w").write(self.activity)
52 if self.evdev:
53 open(filename + ".evdev", "w").write(self.evdev)
54 if self.system:
55 open(filename + ".system", "w").write(self.system)
56
57
58class FileLog(AbstractLog):
59 """
60 Loads log from file. Does not contain evdev or system logs.
61 """
62 def __init__(self, filename, options):
63 self.activity = open(filename).read()
64 self.evdev = ""
65 self.system = ""
Dennis Kempinfa6597c2013-02-20 14:05:19 -080066 if os.path.exists(filename + ".evdev"):
67 self.evdev = open(filename + ".evdev").read()
68 if os.path.exists(filename + ".system"):
69 self.system = open(filename + ".system").read()
Dennis Kempin351024d2013-02-06 11:18:21 -080070
71
72class FeedbackLog(AbstractLog):
73 """
74 Downloads logs from a feedback id.
75 """
76 def __init__(self, id, options):
77 # setup cookies file and url opener
78 self.cookies = cookielib.MozillaCookieJar(cookies_file)
79 if os.path.exists(cookies_file):
80 self.cookies.load()
81 cookie_processor = urllib2.HTTPCookieProcessor(self.cookies)
82 opener = urllib2.build_opener(cookie_processor)
83
84 self._DownloadSystemLog(id, opener)
85 self._ExtractLogFiles()
86
87 def _Login(self, opener):
88 print "Login to corp.google.com:"
89 username = getpass.getuser()
90 password = getpass.getpass()
91 sys.stdout.write("OTP: ")
92 otp = sys.stdin.readline().strip()
93
94 # execute login by posting userdata to login.corp.google.com
95 url = "https://login.corp.google.com/login?ssoformat=CORP_SSO"
96 data = "u=%s&pw=%s&otp=%s" % (username, password, otp)
97 result = opener.open(url, data).read()
98
99 # check if the result displays error
100 if result.find("error") >= 0:
101 print "Login failed"
102 exit(-1)
103
104 # login was successful. save cookies to file to be reused later.
105 self.cookies.save()
106
107 def _GetLatestFile(self, match, tar):
108 # find file name containing match with latest timestamp
109 names = filter(lambda n: n.find(match) >= 0, tar.getnames())
110 names.sort()
Dennis Kempin765ad942013-03-26 13:58:46 -0700111 if not names:
112 print "Cannot find files named %s in tar file" % match
113 print "Tar file contents:", tar.getnames()
114 sys.exit(-1)
Dennis Kempin351024d2013-02-06 11:18:21 -0800115 return tar.extractfile(names[-1])
116
117 def _DownloadSystemLog(self, id, opener):
Dennis Kempinecd9a0c2013-03-27 16:03:46 -0700118 # First download the report.zip file
119 logfile = "report-%s-system_logs.zip" % id
Dennis Kempin351024d2013-02-06 11:18:21 -0800120 url = ("https://feedback.corp.googleusercontent.com/binarydata/"+
121 "%s?id=%s&logIndex=0") % (logfile, id)
122 report_bz2 = opener.open(url).read()
Dennis Kempinecd9a0c2013-03-27 16:03:46 -0700123 file("test.zip", "w").write(report_bz2)
Dennis Kempin351024d2013-02-06 11:18:21 -0800124
Dennis Kempinecd9a0c2013-03-27 16:03:46 -0700125 if report_bz2[0:2] != "BZ" and report_bz2[0:2] != "PK":
126 # not a zip/bzip file. Log in and try again.
Dennis Kempin351024d2013-02-06 11:18:21 -0800127 self._Login(opener)
128 report_bz2 = opener.open(url).read()
129
Dennis Kempinecd9a0c2013-03-27 16:03:46 -0700130 if report_bz2[0:2] == "BZ":
131 self.system = bz2.decompress(report_bz2)
132 elif report_bz2[0:2] == "PK":
133 io = StringIO(report_bz2)
134 zip = zipfile.ZipFile(io, "r")
135 self.system = zip.read(zip.namelist()[0])
136 zip.extractall("./")
137 else:
138 print "Cannot download logs file"
139 sys.exit(-1)
Dennis Kempin351024d2013-02-06 11:18:21 -0800140
141 def _ExtractLogFiles(self):
142 # find embedded and uuencoded activity.tar in system log
143 log_start = ("hack-33025-touchpad_activity=\"\"\"\n" +
144 "begin-base64 644 touchpad_activity_log.tar\n")
Dennis Kempinecd9a0c2013-03-27 16:03:46 -0700145 log_start2 = ("hack-33025-touchpad_activity=<multiline>\n" +
146 "---------- START ----------\n" +
147 "begin-base64 644 touchpad_activity_log.tar\n")
148 if log_start in self.system:
149 log_start_index = self.system.index(log_start) + len(log_start)
150 log_end_index = self.system.index("\"\"\"", log_start_index)
151 elif log_start2 in self.system:
152 log_start_index = self.system.index(log_start2) + len(log_start2)
153 log_end_index = self.system.index("---------- END ----------",
154 log_start_index)
155 else:
156 print "cannot find touchpad_activity_log.tar in systems log file"
157 sys.exit(-1)
158
Dennis Kempin351024d2013-02-06 11:18:21 -0800159 activity_tar_enc = self.system[log_start_index:log_end_index]
160
161 # base64 decode
162 activity_tar_data = base64.b64decode(activity_tar_enc)
163
164 # untar
165 activity_tar_file = tarfile.open(fileobj=StringIO(activity_tar_data))
166
167 # find latest log files
Dennis Kempinecd9a0c2013-03-27 16:03:46 -0700168 logs = filter(lambda n: n.find("touchpad_activity") >= 0,
169 activity_tar_file.getnames())
170 if len(logs) == 1:
171 idx = 0
172 else:
173 while True:
174 print "Which log file would you like to use?"
175 for i, name in enumerate(logs):
176 print i, name
177 print ">"
178 selection = sys.stdin.readline()
179 try:
180 idx = int(selection)
181 if idx < 0 or idx >= len(logs):
182 print "Number out of range"
183 else:
184 break
185 except:
186 print "Not a number"
187
188 activity_name = logs[idx]
189
190 # find matching evdev file
191 evdev_name = logs[idx][0:logs[idx].index("touchpad_activity")]
192 evdev_name = evdev_name + "cmt_input_events"
193
194 for name in activity_tar_file.getnames():
195 if name.startswith(evdev_name):
196 evdev_name = name
197 break
198
199 activity_gz = activity_tar_file.extractfile(activity_name)
200 evdev_gz = activity_tar_file.extractfile(evdev_name)
Dennis Kempin351024d2013-02-06 11:18:21 -0800201
202 # decompress log files
203 self.activity = GzipFile(fileobj=activity_gz).read()
204 self.evdev = GzipFile(fileobj=evdev_gz).read()
205
206
207identity_message = """\
208In order to access devices in TPTool, you need to have password-less
209auth for chromebooks set up.
210Would you like tptool to run the following command for you?
211$ %s
212Yes/No? (Default: No)"""
213
214class DeviceLog(AbstractLog):
215 """
216 Downloads logs from a running chromebook via scp.
217 """
218 def __init__(self, ip, options):
219 self.id_path = os.path.expanduser("~/.ssh/identity")
220 if not os.path.exists(self.id_path):
221 self._SetupIdentity()
222
223 if options.new:
224 self._GenerateLogs(ip)
225
226 self.activity = self._Download(ip, "touchpad_activity_log.txt")
227 self.evdev = self._Download(ip, "cmt_input_events.dat")
228 self.system = ""
229
230 def _GenerateLogs(self, ip):
231 cmd = ("ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no " +
232 "-q root@%s /opt/google/touchpad/tpcontrol log") % ip
233 process = subprocess.Popen(cmd.split())
234 process.wait()
235
236 def _Download(self, ip, filename):
237 temp = tempfile.NamedTemporaryFile("r")
238 cmd = ("scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no " +
239 "-q root@%s:/var/log/%s %s")
240 cmd = cmd % (ip, filename, temp.name)
241 process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
242 process.wait()
243 temp.seek(0)
244 return temp.read()
245
246 def _SetupIdentity(self):
247 source = os.path.expanduser("~/trunk/chromite/ssh_keys/testing_rsa")
248 command = "cp %s %s && chmod 600 %s" % (source, self.id_path, self.id_path)
249 print identity_message % command
250 response = sys.stdin.readline().strip()
251 if response in ("Yes", "yes", "Y", "y"):
252 print command
253 os.system(command)