def _GetMasterJsonData(http_client, master_name, builder_name='', build_number=''): response_json = rpc_util.DownloadJsonData(_MILO_ENDPOINT_MASTER, {'name': master_name}, http_client) return _ProcessMiloData(response_json, master_name, builder_name, build_number)
def GetBuildDataFromBuildMaster(master_name, builder_name, build_number, http_client): """Returns the json-format data of the build.""" data = { 'master': master_name, 'builder': builder_name, 'buildNum': build_number } response_json = rpc_util.DownloadJsonData(_MILO_ENDPOINT_BUILD, data, http_client) return _ProcessMiloData(response_json, master_name, builder_name, str(build_number))
def testDownloadJsonData(self, mock_fn_1, mock_fn_2): mocked_response_json = {'a': 'a'} mocked_response = json.dumps(mocked_response_json) mock_fn_1.return_value = mocked_response mock_fn_2.return_value = mocked_response_json url = 'url' data = {'data': 'data'} http_client = RetryHttpClient() response_json = rpc_util.DownloadJsonData(url, data, http_client) self.assertEqual(response_json, mocked_response_json) mock_fn_1.assert_called_once_with(url, data, http_client) mock_fn_2.assert_called_once_with(mocked_response)
def _GetAnnotationsProtoForPath(host, project, path, http_client): base_error_log = 'Error when load annotations protobuf: %s' data = {'project': project, 'path': path} response_json = rpc_util.DownloadJsonData(_LOGDOG_TAIL_ENDPOINT % host, data, http_client) if not response_json: return None # Gets data for proto. Data format as below: # { # 'logs': [ # { # 'datagram': { # 'data': (base64 encoded data) # } # } # ] # } logs = json.loads(response_json).get('logs') if not logs or not isinstance(logs, list): logging.error(base_error_log % 'Wrong format - "logs"') return None annotations_b64 = logs[-1].get('datagram', {}).get('data') if not annotations_b64: logging.error(base_error_log % 'Wrong format - "data"') return None # Gets proto. try: annotations = base64.b64decode(annotations_b64) step = annotations_pb2.Step() step.ParseFromString(annotations) return step except Exception: logging.error(base_error_log % 'could not get annotations.') return None
def _GetLogForPath(host, project, path, http_client): base_error_log = 'Error when fetch log: %s' data = {'project': project, 'path': path} response_json = rpc_util.DownloadJsonData(_LOGDOG_GET_ENDPOINT % host, data, http_client) if not response_json: logging.error(base_error_log % 'cannot get json log.') return None # Gets data for log. Data format as below: # { # 'logs': [ # { # 'text': { # 'lines': [ # { # 'value': 'line' # } # ] # } # } # ] # } logs = json.loads(response_json).get('logs') if not logs or not isinstance(logs, list): logging.error(base_error_log % 'Wrong format - "logs"') return None sio = cStringIO.StringIO() for log in logs: for line in log.get('text', {}).get('lines', []): sio.write('%s\n' % line.get('value', '').encode('utf-8')) data = sio.getvalue() sio.close() return data
def _GetRawLogsFromGetEndpoint(host, data, http_client, retry_delay=5): """Gets raw logs from Get endpoint. The raw logs can be further processed to get annotations or a specific log. For logs of annotations, it should look like: [ { 'datagram': { 'data': (base64 encoded data) } } ]. For an actual log, it should look like: [ { 'text': { 'lines': [ { 'value': 'line' } ] } } ]. """ tries = 0 error_message = '' # It seems possible to get empty log or log with wrong format. # So also retry for several times even on 200s if the log cannot be used. while tries < 5: # Retry 7 times to allow for logdog's up to 180 second propagation delay. # Exponential backoff starts at 1.5 seconds, reaches 96 seconds for the 7th # retry, for an accumulated total of 190.5 seconds of waiting time. # Should be enough for our purposes. _, response_json = rpc_util.DownloadJsonData(_LOGDOG_GET_ENDPOINT % host, data, http_client, max_retries=7) if response_json is None: # If response is None, it means after 7 retries, Findit still failed to # get response. Seems no need to keep retrying at this case. error_message = 'cannot get json log.' break else: try: logs = json.loads(response_json).get('logs') if not logs or not isinstance(logs, list): error_message = 'Wrong format - %s' % response_json else: return logs except ValueError as e: # For unknown reason sometimes the response_json is truncated and cannot # be json loaded. # This will also help to catch if the response_json is not serializable. error_message = 'Failed to load json - %s' % e.message tries += 1 time.sleep(tries * retry_delay) # Only logs error when the log was failed to get at last. logging.error('Error when fetch log or annotations: %s' % error_message) return None
def _GetAnnotationsProtoForPath(host, project, path, http_client): """Gets annotations from logdog endpoint(s). By default sends request to Tail endpoint for annotations, if only gets a partial results, use Get endpoint instead. """ base_error_log = 'Error when load annotations protobuf: %s' data = {'project': project, 'path': path} _, response_json = rpc_util.DownloadJsonData(_LOGDOG_TAIL_ENDPOINT % host, data, http_client, max_retries=7) if not response_json: return None # Gets data for proto. Data format as below: # { # 'logs': [ # { # 'datagram': { # 'data': (base64 encoded data) # } # } # ] # } logs = json.loads(response_json).get('logs') if not logs or not isinstance(logs, list): logging.error(base_error_log % 'Wrong format - "logs"') return None partial = logs[-1].get('datagram', {}).get('partial') if partial: # Only gets partial result from Tail, use Get instead to get annotations. index = int(logs[-1]['streamIndex']) partial_index = partial['index'] data = { 'project': project, 'path': path, 'index': index - partial_index } logs = _GetRawLogsFromGetEndpoint(host, data, http_client) annotations = '' if not logs: logging.error(base_error_log % 'Wrong format - "logs"') return None sio = cStringIO.StringIO() for log in logs: annotations_b64 = log.get('datagram', {}).get('data') if not annotations_b64: sio.close() logging.error(base_error_log % 'Wrong format - "data"') return None sio.write(base64.b64decode(annotations_b64)) annotations = sio.getvalue() sio.close() # Gets proto. try: step = annotations_pb2.Step() step.ParseFromString(annotations) return step except Exception: logging.error(base_error_log % 'could not get annotations.') return None