blob: 4407e920d46196f916a1e7f9ab87381774b5522c [file] [log] [blame]
mbligh38e9d782008-05-01 20:49:41 +00001#!/usr/bin/python
2
Dan Shi404c25e2017-08-17 23:11:00 -07003import cgi, os, socket, sys, urllib2
showard170873e2009-01-07 00:22:26 +00004import common
MK Ryua50e70e2015-07-14 11:34:25 -07005from multiprocessing import pool
Dan Shi8e331052015-01-13 11:25:50 -08006from autotest_lib.frontend import setup_django_environment
7
showard170873e2009-01-07 00:22:26 +00008from autotest_lib.client.common_lib import global_config
mbligh062ed152009-01-13 00:57:14 +00009from autotest_lib.client.bin import utils
showardef6fe022009-03-27 20:55:16 +000010from autotest_lib.frontend.afe.json_rpc import serviceHandler
Dan Shi114e1722016-01-10 18:12:53 -080011from autotest_lib.server import system_utils
MK Ryua50e70e2015-07-14 11:34:25 -070012from autotest_lib.server import utils as server_utils
Dan Shi114e1722016-01-10 18:12:53 -080013
mbligh38e9d782008-05-01 20:49:41 +000014
showardef6fe022009-03-27 20:55:16 +000015_PAGE = """\
showarda80823b2008-07-24 16:33:35 +000016Status: 302 Found
mblighe0869d02008-06-04 20:04:28 +000017Content-Type: text/plain
showard77f95db2008-07-17 16:59:38 +000018Location: %s\r\n\r
mbligh38e9d782008-05-01 20:49:41 +000019"""
20
Kevin Chenga78d4212016-03-30 16:33:14 -070021GOOGLE_STORAGE_PATTERN = 'pantheon.corp.google.com/storage/browser/'
Simran Basi6e58d972014-09-18 14:18:44 -070022
showardef6fe022009-03-27 20:55:16 +000023# Define function for retrieving logs
mbligh062ed152009-01-13 00:57:14 +000024def _retrieve_logs_dummy(job_path):
25 pass
26
mblighbafd9a72009-07-28 23:27:42 +000027site_retrieve_logs = utils.import_site_function(__file__,
28 "autotest_lib.tko.site_retrieve_logs", "site_retrieve_logs",
mbligh062ed152009-01-13 00:57:14 +000029 _retrieve_logs_dummy)
30
mblighbafd9a72009-07-28 23:27:42 +000031site_find_repository_host = utils.import_site_function(__file__,
32 "autotest_lib.tko.site_retrieve_logs", "site_find_repository_host",
33 _retrieve_logs_dummy)
34
mbligh38e9d782008-05-01 20:49:41 +000035form = cgi.FieldStorage(keep_blank_values=True)
MK Ryua50e70e2015-07-14 11:34:25 -070036# determine if this is a JSON-RPC request. we support both so that the new TKO
showardef6fe022009-03-27 20:55:16 +000037# client can use its RPC client code, but the old TKO can still use simple GET
38# params.
39_is_json_request = form.has_key('callback')
40
MK Ryua50e70e2015-07-14 11:34:25 -070041# if this key exists, we check if requested log exists in local machine,
42# and do not return Google Storage URL when the log doesn't exist.
43_local_only = form.has_key('localonly')
44
45
showardef6fe022009-03-27 20:55:16 +000046def _get_requested_path():
47 if _is_json_request:
48 request_data = form['request'].value
49 request = serviceHandler.ServiceHandler.translateRequest(request_data)
50 parameters = request['params'][0]
51 return parameters['path']
52
53 return form['job'].value
mbligh38e9d782008-05-01 20:49:41 +000054
showard170873e2009-01-07 00:22:26 +000055
MK Ryua50e70e2015-07-14 11:34:25 -070056def _check_result(args):
57 host = args['host']
58 job_path = args['job_path']
59 shard = args['shard']
60 if shard:
61 http_path = 'http://%s/tko/retrieve_logs.cgi?localonly&job=%s' % (
62 host, job_path)
63 else:
64 http_path = 'http://%s%s' % (host, job_path)
65
66 try:
Prathmesh Prabhu1f9ef092018-04-24 13:52:29 -070067 # HACK: This urlopen call isn't forwarding HTTP headers correctly. This
68 # leads to uberproxy sitting between master (orignator of this request)
69 # and shard (target of the request) to redirect to the the login page.
70 # We detect this condition and reject the target shard as a viable
71 # redirect. The implication is that we will not redirect to the shard
72 # even if the user could themselves access the shard with the correct
73 # credentials.
74 u = utils.urlopen(http_path)
75 redirected_url = u.geturl()
76 if 'accounts.google.com' in redirected_url:
77 return None
MK Ryua50e70e2015-07-14 11:34:25 -070078
79 # On Vms the shard name is set to the default gateway but the
80 # browser used to navigate frontends (that runs on the host of
81 # the vms) is immune to the same NAT routing the vms have, so we
82 # need to replace the gateway with 'localhost'.
83 if utils.DEFAULT_VM_GATEWAY in host:
84 normalized_host = host.replace(utils.DEFAULT_VM_GATEWAY, 'localhost')
85 else:
Dan Shi404c25e2017-08-17 23:11:00 -070086 try:
87 normalized_host = utils.normalize_hostname(host)
88 except socket.herror:
89 # Ignore error: 'socket.herror: [Errno 1] Unknown host'
90 # This can happen when reverse name lookup is not stable.
91 normalized_host = host
MK Ryua50e70e2015-07-14 11:34:25 -070092 return 'http', normalized_host, job_path
93 except urllib2.URLError:
94 return None
95
96
97def _get_tpool_args(hosts, job_path, is_shard, host_set):
98 """Get a list of arguments to be passed to multiprocessing.pool.ThreadPool.
99
100 @param hosts: a list of host names.
101 @param job_path: a requested job path.
102 @param is_shard: True if hosts are shards, False otherwise.
103 @param host_set: a Set to filter out duplicated hosts.
104
105 @return: a list of dictionaries to be used as input of _check_result().
106 """
107 args = []
108 for host in hosts:
109 host = host.strip()
110 if host and host != 'localhost' and host not in host_set:
111 host_set.add(host)
112 arg = {'host': host, 'job_path': job_path, 'shard': is_shard}
113 args.append(arg)
114 return args
115
116
showard9484c312009-01-07 21:07:28 +0000117def find_repository_host(job_path):
showard170873e2009-01-07 00:22:26 +0000118 """Find the machine holding the given logs and return a URL to the logs"""
Dale Curtis74a314b2011-06-23 14:55:46 -0700119 site_repo_info = site_find_repository_host(job_path)
120 if site_repo_info is not None:
121 return site_repo_info
122
MK Ryua50e70e2015-07-14 11:34:25 -0700123 # This cgi script is run only in master (cautotest) and shards.
124 # Drones do not run this script when receiving '/results/...' request.
125 # Only master should check drones and shards for the requested log.
Fang Deng18699fe2015-12-04 16:40:27 -0800126 # Also restricted users do not have access to drones or shards,
127 # always point them to localhost or google storage.
128 if (not server_utils.is_shard() and
129 not server_utils.is_restricted_user(os.environ.get('REMOTE_USER'))):
Dan Shi114e1722016-01-10 18:12:53 -0800130 drones = system_utils.get_drones()
131 shards = system_utils.get_shards()
Prashanth Balasubramanianc85d74f2014-12-09 18:13:57 -0800132
MK Ryua50e70e2015-07-14 11:34:25 -0700133 host_set = set()
134 tpool_args = _get_tpool_args(drones, job_path, False, host_set)
135 tpool_args += _get_tpool_args(shards, job_path, True, host_set)
mblighebf81642009-12-02 19:02:28 +0000136
MK Ryua50e70e2015-07-14 11:34:25 -0700137 tpool = pool.ThreadPool()
138 for result_path in tpool.imap_unordered(_check_result, tpool_args):
139 if result_path:
140 return result_path
mblighebf81642009-12-02 19:02:28 +0000141
Simran Basi6e58d972014-09-18 14:18:44 -0700142 # If the URL requested is a test result, it is now either on the local
143 # host or in Google Storage.
144 if job_path.startswith('/results/'):
145 # We only care about the path after '/results/'.
146 job_relative_path = job_path[9:]
MK Ryua50e70e2015-07-14 11:34:25 -0700147 if not _local_only and not os.path.exists(
148 os.path.join('/usr/local/autotest/results',
149 job_relative_path)):
Simran Basi6e58d972014-09-18 14:18:44 -0700150 gsuri = utils.get_offload_gsuri().split('gs://')[1]
151 return ['https', GOOGLE_STORAGE_PATTERN, gsuri + job_relative_path]
152
showard170873e2009-01-07 00:22:26 +0000153
Dale Curtis74a314b2011-06-23 14:55:46 -0700154def get_full_url(info, log_path):
155 if info is not None:
156 protocol, host, path = info
157 prefix = '%s://%s' % (protocol, host)
showard9484c312009-01-07 21:07:28 +0000158 else:
159 prefix = ''
Dale Curtis74a314b2011-06-23 14:55:46 -0700160 path = log_path
showard9484c312009-01-07 21:07:28 +0000161
showardef6fe022009-03-27 20:55:16 +0000162 if _is_json_request:
163 return '%s/tko/jsonp_fetcher.cgi?%s' % (prefix,
164 os.environ['QUERY_STRING'])
showard9484c312009-01-07 21:07:28 +0000165 else:
166 return prefix + path
167
168
showardef6fe022009-03-27 20:55:16 +0000169log_path = _get_requested_path()
Dale Curtis74a314b2011-06-23 14:55:46 -0700170info = find_repository_host(log_path)
mblighbafd9a72009-07-28 23:27:42 +0000171site_retrieve_logs(log_path)
Dale Curtis74a314b2011-06-23 14:55:46 -0700172print _PAGE % get_full_url(info, log_path)