Home | History | Annotate | Download | only in afe
      1 package autotest.afe;
      2 
      3 import autotest.afe.create.CreateJobViewPresenter.JobCreateListener;
      4 import autotest.common.CustomHistory.HistoryToken;
      5 import autotest.common.SimpleCallback;
      6 import autotest.common.Utils;
      7 import autotest.common.table.DataSource;
      8 import autotest.common.table.DataSource.DataCallback;
      9 import autotest.common.table.DataSource.Query;
     10 import autotest.common.table.DataSource.SortDirection;
     11 import autotest.common.table.DataTable;
     12 import autotest.common.table.DatetimeSegmentFilter;
     13 import autotest.common.table.DynamicTable;
     14 import autotest.common.table.DynamicTable.DynamicTableListener;
     15 import autotest.common.table.JSONObjectSet;
     16 import autotest.common.table.RpcDataSource;
     17 import autotest.common.table.SelectionManager;
     18 import autotest.common.table.SimpleFilter;
     19 import autotest.common.table.TableDecorator;
     20 import autotest.common.ui.ContextMenu;
     21 import autotest.common.ui.DetailView;
     22 import autotest.common.ui.NotifyManager;
     23 import autotest.common.ui.TableActionsPanel.TableActionsListener;
     24 
     25 import com.google.gwt.event.dom.client.ClickEvent;
     26 import com.google.gwt.event.dom.client.ClickHandler;
     27 import com.google.gwt.event.dom.client.KeyCodes;
     28 import com.google.gwt.event.dom.client.KeyPressEvent;
     29 import com.google.gwt.event.dom.client.KeyPressHandler;
     30 import com.google.gwt.event.logical.shared.ValueChangeEvent;
     31 import com.google.gwt.event.logical.shared.ValueChangeHandler;
     32 import com.google.gwt.json.client.JSONArray;
     33 import com.google.gwt.json.client.JSONBoolean;
     34 import com.google.gwt.json.client.JSONNumber;
     35 import com.google.gwt.json.client.JSONObject;
     36 import com.google.gwt.json.client.JSONString;
     37 import com.google.gwt.json.client.JSONValue;
     38 import com.google.gwt.user.client.Command;
     39 import com.google.gwt.user.client.ui.Button;
     40 import com.google.gwt.user.client.ui.CheckBox;
     41 import com.google.gwt.user.client.ui.TextBox;
     42 
     43 import java.util.List;
     44 import java.util.Map;
     45 import java.util.Set;
     46 
     47 public class HostDetailView extends DetailView implements DataCallback, TableActionsListener {
     48     private static final String[][] HOST_JOBS_COLUMNS = {
     49             {DataTable.WIDGET_COLUMN, ""}, {"type", "Type"}, {"job__id", "Job ID"},
     50             {"job_owner", "Job Owner"}, {"job_name", "Job Name"}, {"started_on", "Time started"},
     51             {"status", "Status"}
     52     };
     53     public static final int JOBS_PER_PAGE = 20;
     54 
     55     public interface HostDetailListener {
     56         public void onJobSelected(int jobId);
     57     }
     58 
     59     private static class HostQueueEntryDataSource extends RpcDataSource {
     60         public HostQueueEntryDataSource() {
     61             super("get_host_queue_entries", "get_num_host_queue_entries");
     62         }
     63 
     64         @Override
     65         protected List<JSONObject> handleJsonResult(JSONValue result) {
     66             List<JSONObject> resultArray = super.handleJsonResult(result);
     67             for (JSONObject row : resultArray) {
     68                 // get_host_queue_entries() doesn't return type, so fill it in for consistency with
     69                 // get_host_queue_entries_and_special_tasks()
     70                 row.put("type", new JSONString("Job"));
     71             }
     72             return resultArray;
     73         }
     74     }
     75 
     76     private static class HostJobsTable extends DynamicTable {
     77         private static final DataSource normalDataSource = new HostQueueEntryDataSource();
     78         private static final DataSource dataSourceWithSpecialTasks =
     79             new RpcDataSource("get_host_queue_entries_and_special_tasks",
     80                               "get_num_host_queue_entries_and_special_tasks");
     81 
     82         private SimpleFilter hostFilter = new SimpleFilter();
     83         private String hostId;
     84         private String startTime;
     85         private String endTime;
     86 
     87         public HostJobsTable() {
     88             super(HOST_JOBS_COLUMNS, normalDataSource);
     89             addFilter(hostFilter);
     90         }
     91 
     92         public void setHostId(String hostId) {
     93             this.hostId = hostId;
     94             updateFilter();
     95         }
     96 
     97         public void setStartTime(String startTime) {
     98             this.startTime = startTime;
     99             updateFilter();
    100         }
    101 
    102         public void setEndTime(String endTime) {
    103             this.endTime = endTime;
    104             updateFilter();
    105         }
    106 
    107         private void updateFilter() {
    108             if (getDataSource() == normalDataSource) {
    109                 sortOnColumn("job__id", SortDirection.DESCENDING);
    110             } else {
    111                 clearSorts();
    112             }
    113 
    114             hostFilter.clear();
    115             hostFilter.setParameter("host",
    116                                     new JSONNumber(Double.parseDouble(hostId)));
    117             if (startTime != null && startTime != "")
    118                 hostFilter.setParameter("start_time", new JSONString(startTime));
    119             if (endTime != null && endTime != "")
    120                 hostFilter.setParameter("end_time", new JSONString(endTime));
    121         }
    122 
    123         public void setSpecialTasksEnabled(boolean enabled) {
    124             if (enabled) {
    125                 setDataSource(dataSourceWithSpecialTasks);
    126             } else {
    127                 setDataSource(normalDataSource);
    128             }
    129 
    130             updateFilter();
    131         }
    132 
    133         @Override
    134         protected void preprocessRow(JSONObject row) {
    135             JSONObject job = row.get("job").isObject();
    136             JSONString blank = new JSONString("");
    137             JSONString jobId = blank, owner = blank, name = blank;
    138             if (job != null) {
    139                 int id = (int) job.get("id").isNumber().doubleValue();
    140                 jobId = new JSONString(Integer.toString(id));
    141                 owner = job.get("owner").isString();
    142                 name = job.get("name").isString();
    143             }
    144 
    145             row.put("job__id", jobId);
    146             row.put("job_owner", owner);
    147             row.put("job_name", name);
    148         }
    149     }
    150 
    151     private String hostname = "";
    152     private String hostId = "";
    153     private DataSource hostDataSource = new HostDataSource();
    154     private HostJobsTable jobsTable = new HostJobsTable();
    155     private TableDecorator tableDecorator = new TableDecorator(jobsTable);
    156     private HostDetailListener hostDetailListener = null;
    157     private JobCreateListener jobCreateListener = null;
    158     private SelectionManager selectionManager;
    159 
    160     private JSONObject currentHostObject;
    161 
    162     private Button lockButton = new Button();
    163     private Button reverifyButton = new Button("Reverify");
    164     private Button repairButton = new Button("Repair");
    165     private CheckBox showSpecialTasks = new CheckBox();
    166     private DatetimeSegmentFilter startedTimeFilter = new DatetimeSegmentFilter();
    167     private TextBox hostnameInput = new TextBox();
    168     private Button hostnameFetchButton = new Button("Go");
    169     private TextBox lockReasonInput = new TextBox();
    170 
    171     public HostDetailView(HostDetailListener hostDetailListener,
    172                           JobCreateListener jobCreateListener) {
    173         this.hostDetailListener = hostDetailListener;
    174         this.jobCreateListener = jobCreateListener;
    175     }
    176 
    177     @Override
    178     public String getElementId() {
    179         return "view_host";
    180     }
    181 
    182     @Override
    183     protected String getFetchControlsElementId() {
    184         return "view_host_fetch_controls";
    185     }
    186 
    187     private String getFetchByHostnameControlsElementId() {
    188         return "view_host_fetch_by_hostname_controls";
    189     }
    190 
    191     @Override
    192     protected String getDataElementId() {
    193         return "view_host_data";
    194     }
    195 
    196     @Override
    197     protected String getTitleElementId() {
    198         return "view_host_title";
    199     }
    200 
    201     @Override
    202     protected String getNoObjectText() {
    203         return "No host selected";
    204     }
    205 
    206     @Override
    207     protected String getObjectId() {
    208         return hostId;
    209     }
    210 
    211     protected String getHostname() {
    212         return hostname;
    213     }
    214 
    215     @Override
    216     protected void setObjectId(String id) {
    217         if (id.length() == 0) {
    218             throw new IllegalArgumentException();
    219         }
    220         this.hostId = id;
    221     }
    222 
    223     @Override
    224     protected void fetchData() {
    225         JSONObject params = new JSONObject();
    226         params.put("id", new JSONString(getObjectId()));
    227         fetchDataCommmon(params);
    228     }
    229 
    230     private void fetchDataByHostname(String hostname) {
    231         JSONObject params = new JSONObject();
    232         params.put("hostname", new JSONString(hostname));
    233         fetchDataCommmon(params);
    234     }
    235 
    236     private void fetchDataCommmon(JSONObject params) {
    237         params.put("valid_only", JSONBoolean.getInstance(false));
    238         hostDataSource.query(params, this);
    239     }
    240 
    241     private void fetchByHostname(String hostname) {
    242         fetchDataByHostname(hostname);
    243         updateHistory();
    244     }
    245 
    246     @Override
    247     public void handleTotalResultCount(int totalCount) {}
    248 
    249     @Override
    250     public void onQueryReady(Query query) {
    251         query.getPage(null, null, null, this);
    252     }
    253 
    254     public void handlePage(List<JSONObject> data) {
    255         try {
    256             currentHostObject = Utils.getSingleObjectFromList(data);
    257         }
    258         catch (IllegalArgumentException exc) {
    259             NotifyManager.getInstance().showError("No such host found");
    260             resetPage();
    261             return;
    262         }
    263 
    264         setObjectId(currentHostObject.get("id").toString());
    265 
    266         String lockedText = Utils.jsonToString(currentHostObject.get(HostDataSource.LOCKED_TEXT));
    267         if (currentHostObject.get("locked").isBoolean().booleanValue()) {
    268             String lockedBy = Utils.jsonToString(currentHostObject.get("locked_by"));
    269             String lockedTime = Utils.jsonToString(currentHostObject.get("lock_time"));
    270             String lockReasonText = Utils.jsonToString(currentHostObject.get("lock_reason"));
    271             lockedText += ", by " + lockedBy + " on " + lockedTime;
    272             lockedText += ", reason: " + lockReasonText;
    273         }
    274 
    275         showField(currentHostObject, "status", "view_host_status");
    276         showField(currentHostObject, "platform", "view_host_platform");
    277         showField(currentHostObject, HostDataSource.HOST_ACLS, "view_host_acls");
    278         showField(currentHostObject, HostDataSource.OTHER_LABELS, "view_host_labels");
    279         showText(lockedText, "view_host_locked");
    280         String shard_url = Utils.jsonToString(currentHostObject.get("shard")).trim();
    281         String host_id = Utils.jsonToString(currentHostObject.get("id")).trim();
    282         if (shard_url.equals("<null>")){
    283             shard_url = "";
    284         } else {
    285             shard_url = "http://" + shard_url;
    286         }
    287         shard_url = shard_url + "/afe/#tab_id=view_host&object_id=" + host_id;
    288         showField(currentHostObject, "shard", "view_host_shard");
    289         getElementById("view_host_shard").setAttribute("href", shard_url);
    290 
    291         String job_id = Utils.jsonToString(currentHostObject.get("current_job")).trim();
    292         if (!job_id.equals("<null>")){
    293             String job_url = "#tab_id=view_job&object_id=" + job_id;
    294             showField(currentHostObject, "current_job", "view_host_current_job");
    295             getElementById("view_host_current_job").setAttribute("href", job_url);
    296         }
    297         hostname = currentHostObject.get("hostname").isString().stringValue();
    298 
    299         String task = Utils.jsonToString(currentHostObject.get("current_special_task")).trim();
    300         if (!task.equals("<null>")){
    301             String task_url = Utils.getRetrieveLogsUrl("hosts/" + hostname + "/" + task);
    302             showField(currentHostObject, "current_special_task", "view_host_current_special_task");
    303             getElementById("view_host_current_special_task").setAttribute("href", task_url);
    304         }
    305 
    306         showField(currentHostObject, "protection", "view_host_protection");
    307         String pageTitle = "Host " + hostname;
    308         hostnameInput.setText(hostname);
    309         hostnameInput.setWidth("240px");
    310         updateLockButton();
    311         updateLockReasonInput();
    312         displayObjectData(pageTitle);
    313 
    314         jobsTable.setHostId(getObjectId());
    315         jobsTable.refresh();
    316     }
    317 
    318     @Override
    319     public void initialize() {
    320         super.initialize();
    321 
    322         // Replace fetch by id with fetch by hostname
    323         addWidget(hostnameInput, getFetchByHostnameControlsElementId());
    324         addWidget(hostnameFetchButton, getFetchByHostnameControlsElementId());
    325 
    326         hostnameInput.addKeyPressHandler(new KeyPressHandler() {
    327             public void onKeyPress (KeyPressEvent event) {
    328                 if (event.getCharCode() == (char) KeyCodes.KEY_ENTER)
    329                     fetchByHostname(hostnameInput.getText());
    330             }
    331         });
    332         hostnameFetchButton.addClickHandler(new ClickHandler() {
    333             public void onClick(ClickEvent event) {
    334                 fetchByHostname(hostnameInput.getText());
    335             }
    336         });
    337 
    338         jobsTable.setRowsPerPage(JOBS_PER_PAGE);
    339         jobsTable.setClickable(true);
    340         jobsTable.addListener(new DynamicTableListener() {
    341             public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick) {
    342                 if (isJobRow(row)) {
    343                     JSONObject job = row.get("job").isObject();
    344                     int jobId = (int) job.get("id").isNumber().doubleValue();
    345                     hostDetailListener.onJobSelected(jobId);
    346                 } else {
    347                     String resultsPath = Utils.jsonToString(row.get("execution_path"));
    348                     Utils.openUrlInNewWindow(Utils.getRetrieveLogsUrl(resultsPath));
    349                 }
    350             }
    351 
    352             public void onTableRefreshed() {}
    353         });
    354         tableDecorator.addPaginators();
    355         selectionManager = tableDecorator.addSelectionManager(false);
    356         jobsTable.setWidgetFactory(selectionManager);
    357         tableDecorator.addTableActionsPanel(this, true);
    358         tableDecorator.addControl("Show verifies, repairs, cleanups and resets",
    359                                   showSpecialTasks);
    360         tableDecorator.addFilter("Filter by time started:",
    361                                  startedTimeFilter);
    362         addWidget(tableDecorator, "view_host_jobs_table");
    363 
    364         showSpecialTasks.addClickHandler(new ClickHandler() {
    365             public void onClick(ClickEvent event) {
    366                 selectionManager.deselectAll();
    367                 jobsTable.setSpecialTasksEnabled(showSpecialTasks.getValue());
    368                 jobsTable.refresh();
    369             }
    370         });
    371 
    372         startedTimeFilter.addValueChangeHandler(
    373             new ValueChangeHandler() {
    374                 public void onValueChange(ValueChangeEvent event) {
    375                     String value = (String) event.getValue();
    376                     jobsTable.setStartTime(value);
    377                     if (value == "")
    378                         startedTimeFilter.setStartTimeToPlaceHolderValue();
    379                     jobsTable.refresh();
    380                 }
    381             },
    382             new ValueChangeHandler() {
    383                 public void onValueChange(ValueChangeEvent event) {
    384                     String value = (String) event.getValue();
    385                     jobsTable.setEndTime(value);
    386                     if (value == "")
    387                         startedTimeFilter.setEndTimeToPlaceHolderValue();
    388                     jobsTable.refresh();
    389                 }
    390             }
    391         );
    392 
    393         addWidget(lockButton, "view_host_lock_button");
    394         addWidget(lockReasonInput, "view_host_lock_reason_input");
    395 
    396         lockButton.addClickHandler(new ClickHandler() {
    397             public void onClick(ClickEvent event) {
    398                boolean locked = currentHostObject.get("locked").isBoolean().booleanValue();
    399                changeLock(!locked);
    400             }
    401         });
    402         lockReasonInput.addKeyPressHandler(new KeyPressHandler() {
    403             public void onKeyPress (KeyPressEvent event) {
    404                 if (event.getCharCode() == (char) KeyCodes.KEY_ENTER) {
    405                     boolean locked = currentHostObject.get("locked").isBoolean().booleanValue();
    406                     changeLock(!locked);
    407                 }
    408             }
    409         });
    410 
    411         reverifyButton.addClickHandler(new ClickHandler() {
    412             public void onClick(ClickEvent event) {
    413                 JSONObject params = new JSONObject();
    414 
    415                 params.put("id", currentHostObject.get("id"));
    416                 AfeUtils.callReverify(params, new SimpleCallback() {
    417                     public void doCallback(Object source) {
    418                        refresh();
    419                     }
    420                 }, "Host " + hostname);
    421             }
    422         });
    423         addWidget(reverifyButton, "view_host_reverify_button");
    424 
    425         repairButton.addClickHandler(new ClickHandler() {
    426             public void onClick(ClickEvent event) {
    427                 JSONObject params = new JSONObject();
    428 
    429                 params.put("id", currentHostObject.get("id"));
    430                 AfeUtils.callRepair(params, new SimpleCallback() {
    431                     public void doCallback(Object source) {
    432                        refresh();
    433                     }
    434                 }, "Host " + hostname);
    435             }
    436         });
    437         addWidget(repairButton, "view_host_repair_button");
    438     }
    439 
    440     public void onError(JSONObject errorObject) {
    441         // RPC handler will display error
    442     }
    443 
    444     public ContextMenu getActionMenu() {
    445         ContextMenu menu = new ContextMenu();
    446         menu.addItem("Abort", new Command() {
    447             public void execute() {
    448                 abortSelectedQueueEntriesAndSpecialTasks();
    449             }
    450         });
    451         if (selectionManager.isEmpty())
    452             menu.setEnabled(false);
    453         return menu;
    454     }
    455 
    456     private void abortSelectedQueueEntriesAndSpecialTasks() {
    457         Set<JSONObject> selectedEntries = selectionManager.getSelectedObjects();
    458         Set<JSONObject> selectedQueueEntries = new JSONObjectSet<JSONObject>();
    459         JSONArray selectedSpecialTaskIds = new JSONArray();
    460         for (JSONObject entry : selectedEntries) {
    461             if (isJobRow(entry))
    462                 selectedQueueEntries.add(entry);
    463             else
    464                 selectedSpecialTaskIds.set(selectedSpecialTaskIds.size(),
    465                                            entry.get("oid"));
    466         }
    467         if (!selectedQueueEntries.isEmpty()) {
    468             AfeUtils.abortHostQueueEntries(selectedQueueEntries, new SimpleCallback() {
    469                 public void doCallback(Object source) {
    470                     refresh();
    471                 }
    472             });
    473         }
    474         if (selectedSpecialTaskIds.size() > 0) {
    475             AfeUtils.abortSpecialTasks(selectedSpecialTaskIds, new SimpleCallback() {
    476                 public void doCallback(Object source) {
    477                     refresh();
    478                 }
    479             });
    480         }
    481     }
    482 
    483     private void updateLockButton() {
    484         boolean locked = currentHostObject.get("locked").isBoolean().booleanValue();
    485         if (locked) {
    486             lockButton.setText("Unlock");
    487         } else {
    488             lockButton.setText("Lock");
    489         }
    490     }
    491 
    492     private void updateLockReasonInput() {
    493         boolean locked = currentHostObject.get("locked").isBoolean().booleanValue();
    494         if (locked) {
    495             lockReasonInput.setText("");
    496             lockReasonInput.setEnabled(false);
    497         } else {
    498             lockReasonInput.setEnabled(true);
    499         }
    500     }
    501 
    502     private void changeLock(final boolean lock) {
    503         JSONArray hostIds = new JSONArray();
    504         hostIds.set(0, currentHostObject.get("id"));
    505 
    506         AfeUtils.changeHostLocks(hostIds, lock, lockReasonInput.getText(),
    507                                  "Host " + hostname, new SimpleCallback() {
    508             public void doCallback(Object source) {
    509                 refresh();
    510             }
    511         });
    512     }
    513 
    514     private boolean isJobRow(JSONObject row) {
    515         String type = Utils.jsonToString(row.get("type"));
    516         return type.equals("Job");
    517     }
    518 
    519     public boolean isRowSelectable(JSONObject row) {
    520         return isJobRow(row);
    521     }
    522 
    523     @Override
    524     public void handleHistoryArguments(Map<String, String> arguments) {
    525         String hostname = arguments.get("hostname");
    526         String objectId = arguments.get("object_id");
    527 
    528         if (objectId != null) {
    529             try {
    530                 updateObjectId(objectId);
    531             }
    532             catch (IllegalArgumentException exc) {
    533                 return;
    534             }
    535         } else if (hostname != null) {
    536             fetchDataByHostname(hostname);
    537         } else {
    538             resetPage();
    539         }
    540     }
    541 }
    542