diff options
Diffstat (limited to 'scripts/send-error-report')
| -rwxr-xr-x | scripts/send-error-report | 274 |
1 files changed, 178 insertions, 96 deletions
diff --git a/scripts/send-error-report b/scripts/send-error-report index 01c292ead1..1a1b96580d 100755 --- a/scripts/send-error-report +++ b/scripts/send-error-report | |||
| @@ -1,114 +1,196 @@ | |||
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | 2 | ||
| 3 | # Sends an error report (if the report-error class was enabled) to a remote server. | 3 | # Sends an error report (if the report-error class was enabled) to a |
| 4 | # remote server. | ||
| 4 | # | 5 | # |
| 5 | # Copyright (C) 2013 Intel Corporation | 6 | # Copyright (C) 2013 Intel Corporation |
| 6 | # Author: Andreea Proca <andreea.b.proca@intel.com> | 7 | # Author: Andreea Proca <andreea.b.proca@intel.com> |
| 8 | # Author: Michael Wood <michael.g.wood@intel.com> | ||
| 9 | |||
| 10 | import urllib2 | ||
| 11 | import sys | ||
| 12 | import json | ||
| 13 | import os | ||
| 14 | import subprocess | ||
| 15 | import argparse | ||
| 16 | import logging | ||
| 17 | |||
| 18 | version = "0.3" | ||
| 19 | |||
| 20 | log = logging.getLogger("send-error-report") | ||
| 21 | logging.basicConfig(format='%(levelname)s: %(message)s') | ||
| 22 | |||
| 23 | def getPayloadLimit(url): | ||
| 24 | req = urllib2.Request(url, None) | ||
| 25 | try: | ||
| 26 | response = urllib2.urlopen(req) | ||
| 27 | except urllib2.URLError as e: | ||
| 28 | # Use this opportunity to bail out if we can't even contact the server | ||
| 29 | log.error("Could not contact server: " + url) | ||
| 30 | log.error(e.reason) | ||
| 31 | sys.exit(1) | ||
| 32 | try: | ||
| 33 | ret = json.loads(response.read()) | ||
| 34 | max_log_size = ret.get('max_log_size', 0) | ||
| 35 | return int(max_log_size) | ||
| 36 | except: | ||
| 37 | pass | ||
| 38 | |||
| 39 | return 0 | ||
| 40 | |||
| 41 | def ask_for_contactdetails(): | ||
| 42 | print("Please enter your name and your email (optionally), they'll be saved in the file you send.") | ||
| 43 | username = raw_input("Name (required): ") | ||
| 44 | email = raw_input("E-mail (not required): ") | ||
| 45 | return username, email | ||
| 46 | |||
| 47 | def edit_content(json_file_path): | ||
| 48 | edit = raw_input("Review information before sending? (y/n): ") | ||
| 49 | if 'y' in edit or 'Y' in edit: | ||
| 50 | editor = os.environ.get('EDITOR', None) | ||
| 51 | if editor: | ||
| 52 | subprocess.check_call([editor, json_file_path]) | ||
| 53 | else: | ||
| 54 | log.error("Please set your EDITOR value") | ||
| 55 | sys.exit(1) | ||
| 56 | return True | ||
| 57 | return False | ||
| 7 | 58 | ||
| 59 | def prepare_data(args): | ||
| 60 | # attempt to get the max_log_size from the server's settings | ||
| 61 | max_log_size = getPayloadLimit("http://"+args.server+"/ClientPost/JSON") | ||
| 8 | 62 | ||
| 63 | if not os.path.isfile(args.error_file): | ||
| 64 | log.error("No data file found.") | ||
| 65 | sys.exit(1) | ||
| 9 | 66 | ||
| 10 | import httplib, urllib, os, sys, json, base64 | 67 | home = os.path.expanduser("~") |
| 11 | from urllib2 import _parse_proxy as parseproxy | 68 | userfile = os.path.join(home, ".oe-send-error") |
| 12 | |||
| 13 | |||
| 14 | def handle_connection(server, data): | ||
| 15 | params = urllib.urlencode({'data': data}) | ||
| 16 | headers = {"Content-type": "application/json"} | ||
| 17 | proxyrequired = False | ||
| 18 | if os.environ.get("http_proxy") or os.environ.get("HTTP_PROXY"): | ||
| 19 | proxyrequired = True | ||
| 20 | # we need to check that the server isn't a local one, as in no_proxy | ||
| 21 | try: | ||
| 22 | temp = httplib.HTTPConnection(server, strict=True, timeout=5) | ||
| 23 | temp.request("GET", "/Errors/") | ||
| 24 | tempres = temp.getresponse() | ||
| 25 | if tempres.status == 200: | ||
| 26 | proxyrequired = False | ||
| 27 | temp.close() | ||
| 28 | except: | ||
| 29 | pass | ||
| 30 | |||
| 31 | if proxyrequired: | ||
| 32 | proxy = parseproxy(os.environ.get("http_proxy") or os.environ.get("HTTP_PROXY")) | ||
| 33 | if proxy[1] and proxy[2]: | ||
| 34 | auth = base64.encodestring("%s:%s" % (proxy[1], proxy[2])) | ||
| 35 | headers["Authorization"] = "Basic %s" % auth | ||
| 36 | conn = httplib.HTTPConnection(proxy[3]) | ||
| 37 | conn.request("POST", "http://%s/ClientPost/" % server, params, headers) | ||
| 38 | else: | ||
| 39 | conn = httplib.HTTPConnection(server) | ||
| 40 | conn.request("POST", "/ClientPost/", params, headers) | ||
| 41 | 69 | ||
| 42 | return conn | 70 | try: |
| 71 | with open(userfile, 'r') as userfile_fp: | ||
| 72 | if len(args.name) == 0: | ||
| 73 | args.name = userfile_fp.readline() | ||
| 74 | else: | ||
| 75 | #use empty readline to increment the fp | ||
| 76 | userfile_fp.readline() | ||
| 43 | 77 | ||
| 78 | if len(args.email) == 0: | ||
| 79 | args.email = userfile_fp.readline() | ||
| 80 | except: | ||
| 81 | pass | ||
| 44 | 82 | ||
| 45 | def sendData(json_file, server): | 83 | if args.assume_yes == True and len(args.name) == 0: |
| 84 | log.error("Name needs to be provided either via "+userfile+" or as an argument (-n).") | ||
| 85 | sys.exit(1) | ||
| 46 | 86 | ||
| 47 | if os.path.isfile(json_file): | 87 | while len(args.name) <= 0 and len(args.name) < 50: |
| 88 | print("\nName needs to be given and must not more than 50 characters.") | ||
| 89 | args.name, args.email = ask_for_contactdetails() | ||
| 48 | 90 | ||
| 49 | home = os.path.expanduser("~") | 91 | with open(userfile, 'w') as userfile_fp: |
| 50 | userfile = os.path.join(home, ".oe-send-error") | 92 | userfile_fp.write(args.name.strip() + "\n") |
| 51 | if os.path.isfile(userfile): | 93 | userfile_fp.write(args.email.strip() + "\n") |
| 52 | with open(userfile) as g: | 94 | |
| 53 | username = g.readline() | 95 | with open(args.error_file, 'r') as json_fp: |
| 54 | email = g.readline() | 96 | data = json_fp.read() |
| 55 | else: | 97 | |
| 56 | print("Please enter your name and your email (optionally), they'll be saved in the file you send.") | 98 | jsondata = json.loads(data) |
| 57 | username = raw_input("Name: ") | 99 | jsondata['username'] = args.name.strip() |
| 58 | email = raw_input("E-mail (not required): ") | 100 | jsondata['email'] = args.email.strip() |
| 59 | if len(username) > 0 and len(username) < 50: | 101 | jsondata['link_back'] = args.link_back.strip() |
| 60 | with open(userfile, "w") as g: | 102 | # If we got a max_log_size then use this to truncate to get the last |
| 61 | g.write(username + "\n") | 103 | # max_log_size bytes from the end |
| 62 | g.write(email + "\n") | 104 | if max_log_size != 0: |
| 63 | else: | 105 | for fail in jsondata['failures']: |
| 64 | print("Invalid inputs, try again.") | 106 | if len(fail['log']) > max_log_size: |
| 65 | sys.exit(1) | 107 | print "Truncating log to allow for upload" |
| 66 | return | 108 | fail['log'] = fail['log'][-max_log_size:] |
| 67 | 109 | ||
| 68 | with open(json_file) as f: | 110 | data = json.dumps(jsondata, indent=4, sort_keys=True) |
| 69 | data = f.read() | 111 | |
| 70 | 112 | # Write back the result which will contain all fields filled in and | |
| 71 | try: | 113 | # any post processing done on the log data |
| 72 | jsondata = json.loads(data) | 114 | with open(args.error_file, "w") as json_fp: |
| 73 | jsondata['username'] = username.strip() | 115 | if data: |
| 74 | jsondata['email'] = email.strip() | 116 | json_fp.write(data) |
| 75 | data = json.dumps(jsondata, indent=4, sort_keys=True) | 117 | |
| 76 | except: | 118 | |
| 77 | print("Invalid json data") | 119 | if args.assume_yes == False and edit_content(args.error_file): |
| 78 | sys.exit(1) | 120 | #We'll need to re-read the content if we edited it |
| 79 | return | 121 | with open(args.error_file, 'r') as json_fp: |
| 80 | 122 | data = json_fp.read() | |
| 81 | try: | 123 | |
| 82 | conn = handle_connection(server, data) | 124 | return data |
| 83 | response = conn.getresponse() | 125 | |
| 84 | print response.status, response.reason | 126 | |
| 85 | res = response.read() | 127 | def send_data(data, args): |
| 86 | if response.status == 200: | 128 | headers={'Content-type': 'application/json', 'User-Agent': "send-error-report/"+version} |
| 87 | print(res) | 129 | |
| 88 | else: | 130 | if args.json: |
| 89 | print("There was a problem submiting your data, response written in %s.response.html" % json_file) | 131 | url = "http://"+args.server+"/ClientPost/JSON/" |
| 90 | with open("%s.response.html" % json_file, "w") as f: | ||
| 91 | f.write(res) | ||
| 92 | sys.exit(1) | ||
| 93 | conn.close() | ||
| 94 | except Exception as e: | ||
| 95 | print("Server connection failed: %s" % e) | ||
| 96 | sys.exit(1) | ||
| 97 | else: | 132 | else: |
| 98 | print("No data file found.") | 133 | url = "http://"+args.server+"/ClientPost/" |
| 134 | |||
| 135 | req = urllib2.Request(url, data=data, headers=headers) | ||
| 136 | try: | ||
| 137 | response = urllib2.urlopen(req) | ||
| 138 | except urllib2.HTTPError, e: | ||
| 139 | logging.error(e.reason) | ||
| 99 | sys.exit(1) | 140 | sys.exit(1) |
| 100 | 141 | ||
| 142 | print response.read() | ||
| 143 | |||
| 101 | 144 | ||
| 102 | if __name__ == '__main__': | 145 | if __name__ == '__main__': |
| 103 | print ("\nSends an error report (if the report-error class was enabled) to a remote server.") | 146 | arg_parse = argparse.ArgumentParser(description="This scripts will send an error report to your specified error-report-web server.") |
| 104 | print("\nThis scripts sends the contents of the error to a public upstream server.") | 147 | |
| 105 | print("\nPlease remove any identifying information before sending.") | 148 | arg_parse.add_argument("error_file", |
| 106 | if len(sys.argv) < 2: | 149 | help="Generated error report file location", |
| 107 | print("\nUsage: send-error-report <error_fileName> [server]") | 150 | type=str) |
| 108 | print("\nIf this is the first when sending a report you'll be asked for your name and optionally your email address.") | 151 | |
| 109 | print("They will be associated with your report.\n") | 152 | arg_parse.add_argument("-y", |
| 110 | 153 | "--assume-yes", | |
| 111 | elif len(sys.argv) == 3: | 154 | help="Assume yes to all queries and do not prompt", |
| 112 | sendData(sys.argv[1], sys.argv[2]) | 155 | action="store_true") |
| 113 | else: | 156 | |
| 114 | sendData(sys.argv[1], "errors.yoctoproject.org") | 157 | arg_parse.add_argument("-s", |
| 158 | "--server", | ||
| 159 | help="Server to send error report to", | ||
| 160 | type=str, | ||
| 161 | default="errors.yoctoproject.org") | ||
| 162 | |||
| 163 | arg_parse.add_argument("-e", | ||
| 164 | "--email", | ||
| 165 | help="Email address to be used for contact", | ||
| 166 | type=str, | ||
| 167 | default="") | ||
| 168 | |||
| 169 | arg_parse.add_argument("-n", | ||
| 170 | "--name", | ||
| 171 | help="Submitter name used to identify your error report", | ||
| 172 | type=str, | ||
| 173 | default="") | ||
| 174 | |||
| 175 | arg_parse.add_argument("-l", | ||
| 176 | "--link-back", | ||
| 177 | help="A url to link back to this build from the error report server", | ||
| 178 | type=str, | ||
| 179 | default="") | ||
| 180 | |||
| 181 | arg_parse.add_argument("-j", | ||
| 182 | "--json", | ||
| 183 | help="Return the result in json format, silences all other output", | ||
| 184 | action="store_true") | ||
| 185 | |||
| 186 | |||
| 187 | |||
| 188 | args = arg_parse.parse_args() | ||
| 189 | |||
| 190 | if (args.json == False): | ||
| 191 | print "Preparing to send errors to: "+args.server | ||
| 192 | |||
| 193 | data = prepare_data(args) | ||
| 194 | send_data(data, args) | ||
| 195 | |||
| 196 | sys.exit(0) | ||
