[autotest] Add job history support.
Add a module to be used to collect job history. For example, all special tasks
executed before and after the test job.
Add an rpc get_job_history to afe to get dictionary of the job and its special
tasks' start/end time.
Update AFE to add a button to show job history.
BUG=chromium:394445
TEST=local setup
./site_utils/job_history.py --job_id=4113
http://dshi.mtv.corp.google.com/afe/#tab_id=view_job&object_id=4113
Change-Id: I0da2e77aaf7e2a38158efd6a64d4f924cf0c803d
Reviewed-on: https://chromium-review.googlesource.com/210091
Tested-by: Dan Shi <dshi@chromium.org>
Reviewed-by: Fang Deng <fdeng@chromium.org>
Commit-Queue: Dan Shi <dshi@chromium.org>
diff --git a/frontend/afe/site_rpc_interface.py b/frontend/afe/site_rpc_interface.py
index fa6cb15..78048d1 100644
--- a/frontend/afe/site_rpc_interface.py
+++ b/frontend/afe/site_rpc_interface.py
@@ -24,6 +24,7 @@
from autotest_lib.server.cros.dynamic_suite import job_status
from autotest_lib.server.cros.dynamic_suite import tools
from autotest_lib.server.hosts import moblab_host
+from autotest_lib.site_utils import job_history
_CONFIG = global_config.global_config
@@ -251,3 +252,17 @@
if not os.path.exists(boto_key):
raise error.RPCException('Boto key: %s does not exist!' % boto_key)
shutil.copyfile(boto_key, moblab_host.MOBLAB_BOTO_LOCATION)
+
+
+def get_job_history(**filter_data):
+ """Get history of the job, including the special tasks executed for the job
+
+ @param filter_data: filter for the call, should at least include
+ {'job_id': [job id]}
+ @returns: JSON string of the job's history, including the information such
+ as the hosts run the job and the special tasks executed before
+ and after the job.
+ """
+ job_id = filter_data['job_id']
+ job_info = job_history.get_job_info(job_id)
+ return _rpc_utils().prepare_for_serialization(job_info.get_history())
diff --git a/frontend/client/src/autotest/afe/AfeUtils.java b/frontend/client/src/autotest/afe/AfeUtils.java
index 1b5497c..361ce0f 100644
--- a/frontend/client/src/autotest/afe/AfeUtils.java
+++ b/frontend/client/src/autotest/afe/AfeUtils.java
@@ -436,4 +436,21 @@
}
row.put(targetFieldName, new JSONString(date));
}
+
+ public static void callGetJobHistory(JSONObject params,
+ final SimpleCallback onSuccess,
+ final boolean showMessage) {
+ JsonRpcProxy rpcProxy = JsonRpcProxy.getProxy();
+ rpcProxy.rpcCall("get_job_history", params, new JsonRpcCallback() {
+ @Override
+ public void onSuccess(JSONValue result) {
+ if (showMessage) {
+ NotifyManager.getInstance().showMessage("Get job history succeeded.");
+ }
+ if (onSuccess != null) {
+ onSuccess.doCallback(result);
+ }
+ }
+ });
+ }
}
diff --git a/frontend/client/src/autotest/afe/JobDetailView.java b/frontend/client/src/autotest/afe/JobDetailView.java
index c398c70..b881247 100644
--- a/frontend/client/src/autotest/afe/JobDetailView.java
+++ b/frontend/client/src/autotest/afe/JobDetailView.java
@@ -5,6 +5,7 @@
import autotest.common.StaticDataRepository;
import autotest.common.Utils;
import autotest.common.table.DataTable;
+import autotest.common.table.DataTable.DataTableListener;
import autotest.common.table.DynamicTable;
import autotest.common.table.ListFilter;
import autotest.common.table.RpcDataSource;
@@ -36,6 +37,8 @@
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
public class JobDetailView extends DetailView implements TableWidgetFactory {
@@ -51,6 +54,11 @@
{ "control_type", "Client/Server" }, { JobTable.HOSTS_SUMMARY, "Status" },
{ JobTable.RESULTS_SUMMARY, "Passed Tests" }
};
+ private static final String[][] JOB_HISTORY_COLUMNS = {
+ { "id", "ID" }, { "hostname", "Host" }, { "name", "Name" },
+ { "start_time", "Start Time" }, { "end_time", "End Time" },
+ { "time_used", "Time Used (seconds)" }, { "status", "Status" }
+ };
public static final String NO_URL = "about:blank";
public static final int NO_JOB_ID = -1;
public static final int HOSTS_PER_PAGE = 30;
@@ -70,6 +78,12 @@
}
}
+ protected class JobHistoryListener {
+ public void onJobSelected(String url) {
+ Utils.openUrlInNewWindow(url);
+ }
+ }
+
protected int jobId = NO_JOB_ID;
private JobStatusDataSource jobStatusDataSource = new JobStatusDataSource();
@@ -94,6 +108,10 @@
protected StaticDataRepository staticData = StaticDataRepository.getRepository();
+ protected Button getJobHistoryButton = new Button("Get Job History");
+ protected JobHistoryListener jobHistoryListener = new JobHistoryListener();
+ protected DataTable jobHistoryTable = new DataTable(JOB_HISTORY_COLUMNS);
+
public JobDetailView(JobDetailListener listener) {
this.listener = listener;
setupSpreadsheetListener(Utils.getBaseUrl());
@@ -193,6 +211,8 @@
parentJobIdFliter.setParameter("parent_job", new JSONNumber(jobId));
childJobsTable.refresh();
+
+ jobHistoryTable.clear();
}
@@ -309,6 +329,24 @@
if (!staticData.getData("drone_sets_enabled").isBoolean().booleanValue()) {
AfeUtils.removeElement("view_drone_set_wrapper");
}
+
+ getJobHistoryButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ getJobHistory();
+ }
+ });
+ addWidget(getJobHistoryButton, "view_get_job_history");
+
+ jobHistoryTable.setClickable(true);
+ jobHistoryTable.addListener(new DataTableListener() {
+ public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick) {
+ String log_url= row.get("log_url").isString().stringValue();
+ jobHistoryListener.onJobSelected(log_url);
+ }
+
+ public void onTableRefreshed() {}
+ });
+ addWidget(jobHistoryTable, "job_history_table");
}
protected void addTableFilters() {
@@ -536,4 +574,19 @@
url = Utils.getRetrieveLogsUrl(url);
return "<a target=\"_blank\" href=\"" + url + "\">" + text + "</a>";
}
+
+ private void getJobHistory() {
+ JSONObject params = new JSONObject();
+ params.put("job_id", new JSONNumber(jobId));
+ AfeUtils.callGetJobHistory(params, new SimpleCallback() {
+ public void doCallback(Object result) {
+ jobHistoryTable.clear();
+ List<JSONObject> rows = new ArrayList<JSONObject>();
+ JSONArray history = (JSONArray)result;
+ for (int i = 0; i < history.size(); i++)
+ rows.add((JSONObject)history.get(i));
+ jobHistoryTable.addRows(rows);
+ }
+ }, true);
+ }
}
diff --git a/frontend/client/src/autotest/public/AfeClient.html b/frontend/client/src/autotest/public/AfeClient.html
index f278da4..15e714a 100644
--- a/frontend/client/src/autotest/public/AfeClient.html
+++ b/frontend/client/src/autotest/public/AfeClient.html
@@ -159,6 +159,10 @@
<span class="field-name">Child jobs</span>
<div id="child_jobs_table"></div><br>
+
+ <span class="field-name">Job history</span>
+ <span id="view_get_job_history" />
+ <div id="job_history_table"></div><br>
</div>
</div>