blob: cfbcaa52cbc36712183065f46b2d10feb83dd0b4 [file] [log] [blame]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001#!/usr/bin/env python3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002
3# Sends an error report (if the report-error class was enabled) to a
4# remote server.
5#
6# Copyright (C) 2013 Intel Corporation
7# Author: Andreea Proca <andreea.b.proca@intel.com>
8# Author: Michael Wood <michael.g.wood@intel.com>
Brad Bishopc342db32019-05-15 21:57:59 -04009#
10# SPDX-License-Identifier: GPL-2.0-only
11#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012
Patrick Williamsc0f7c042017-02-23 20:41:17 -060013import urllib.request, urllib.error
Patrick Williamsc124f4f2015-09-15 14:41:29 -050014import sys
15import json
16import os
17import subprocess
18import argparse
19import logging
20
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050021scripts_lib_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib')
22sys.path.insert(0, scripts_lib_path)
23import argparse_oe
24
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025version = "0.3"
26
27log = logging.getLogger("send-error-report")
28logging.basicConfig(format='%(levelname)s: %(message)s')
29
30def getPayloadLimit(url):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060031 req = urllib.request.Request(url, None)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050032 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060033 response = urllib.request.urlopen(req)
34 except urllib.error.URLError as e:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050035 # Use this opportunity to bail out if we can't even contact the server
36 log.error("Could not contact server: " + url)
37 log.error(e.reason)
38 sys.exit(1)
39 try:
40 ret = json.loads(response.read())
41 max_log_size = ret.get('max_log_size', 0)
42 return int(max_log_size)
43 except:
44 pass
45
46 return 0
47
48def ask_for_contactdetails():
49 print("Please enter your name and your email (optionally), they'll be saved in the file you send.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -060050 username = input("Name (required): ")
51 email = input("E-mail (not required): ")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050052 return username, email
53
54def edit_content(json_file_path):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060055 edit = input("Review information before sending? (y/n): ")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050056 if 'y' in edit or 'Y' in edit:
57 editor = os.environ.get('EDITOR', None)
58 if editor:
59 subprocess.check_call([editor, json_file_path])
60 else:
61 log.error("Please set your EDITOR value")
62 sys.exit(1)
63 return True
64 return False
65
66def prepare_data(args):
67 # attempt to get the max_log_size from the server's settings
Brad Bishopf8caae32019-03-25 13:13:56 -040068 max_log_size = getPayloadLimit(args.protocol+args.server+"/ClientPost/JSON")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069
70 if not os.path.isfile(args.error_file):
71 log.error("No data file found.")
72 sys.exit(1)
73
74 home = os.path.expanduser("~")
75 userfile = os.path.join(home, ".oe-send-error")
76
77 try:
78 with open(userfile, 'r') as userfile_fp:
79 if len(args.name) == 0:
80 args.name = userfile_fp.readline()
81 else:
82 #use empty readline to increment the fp
83 userfile_fp.readline()
84
85 if len(args.email) == 0:
86 args.email = userfile_fp.readline()
87 except:
88 pass
89
90 if args.assume_yes == True and len(args.name) == 0:
91 log.error("Name needs to be provided either via "+userfile+" or as an argument (-n).")
92 sys.exit(1)
93
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080094 while len(args.name) <= 0 or len(args.name) > 50:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050095 print("\nName needs to be given and must not more than 50 characters.")
96 args.name, args.email = ask_for_contactdetails()
97
98 with open(userfile, 'w') as userfile_fp:
99 userfile_fp.write(args.name.strip() + "\n")
100 userfile_fp.write(args.email.strip() + "\n")
101
102 with open(args.error_file, 'r') as json_fp:
103 data = json_fp.read()
104
105 jsondata = json.loads(data)
106 jsondata['username'] = args.name.strip()
107 jsondata['email'] = args.email.strip()
108 jsondata['link_back'] = args.link_back.strip()
109 # If we got a max_log_size then use this to truncate to get the last
110 # max_log_size bytes from the end
111 if max_log_size != 0:
112 for fail in jsondata['failures']:
113 if len(fail['log']) > max_log_size:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600114 print("Truncating log to allow for upload")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500115 fail['log'] = fail['log'][-max_log_size:]
116
117 data = json.dumps(jsondata, indent=4, sort_keys=True)
118
119 # Write back the result which will contain all fields filled in and
120 # any post processing done on the log data
121 with open(args.error_file, "w") as json_fp:
122 if data:
123 json_fp.write(data)
124
125
126 if args.assume_yes == False and edit_content(args.error_file):
127 #We'll need to re-read the content if we edited it
128 with open(args.error_file, 'r') as json_fp:
129 data = json_fp.read()
130
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600131 return data.encode('utf-8')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132
133
134def send_data(data, args):
135 headers={'Content-type': 'application/json', 'User-Agent': "send-error-report/"+version}
136
137 if args.json:
Brad Bishopf8caae32019-03-25 13:13:56 -0400138 url = args.protocol+args.server+"/ClientPost/JSON/"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500139 else:
Brad Bishopf8caae32019-03-25 13:13:56 -0400140 url = args.protocol+args.server+"/ClientPost/"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600142 req = urllib.request.Request(url, data=data, headers=headers)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500143 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600144 response = urllib.request.urlopen(req)
145 except urllib.error.HTTPError as e:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800146 logging.error(str(e))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500147 sys.exit(1)
148
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700149 print(response.read().decode('utf-8'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150
151
152if __name__ == '__main__':
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500153 arg_parse = argparse_oe.ArgumentParser(description="This scripts will send an error report to your specified error-report-web server.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500154
155 arg_parse.add_argument("error_file",
156 help="Generated error report file location",
157 type=str)
158
159 arg_parse.add_argument("-y",
160 "--assume-yes",
161 help="Assume yes to all queries and do not prompt",
162 action="store_true")
163
164 arg_parse.add_argument("-s",
165 "--server",
166 help="Server to send error report to",
167 type=str,
168 default="errors.yoctoproject.org")
169
170 arg_parse.add_argument("-e",
171 "--email",
172 help="Email address to be used for contact",
173 type=str,
174 default="")
175
176 arg_parse.add_argument("-n",
177 "--name",
178 help="Submitter name used to identify your error report",
179 type=str,
180 default="")
181
182 arg_parse.add_argument("-l",
183 "--link-back",
184 help="A url to link back to this build from the error report server",
185 type=str,
186 default="")
187
188 arg_parse.add_argument("-j",
189 "--json",
190 help="Return the result in json format, silences all other output",
191 action="store_true")
192
Brad Bishopf8caae32019-03-25 13:13:56 -0400193 arg_parse.add_argument("--no-ssl",
194 help="Use http instead of https protocol",
195 dest="protocol",
196 action="store_const", const="http://", default="https://")
197
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500198
199
200 args = arg_parse.parse_args()
201
202 if (args.json == False):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600203 print("Preparing to send errors to: "+args.server)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500204
205 data = prepare_data(args)
206 send_data(data, args)
207
208 sys.exit(0)