Add new DUT Manage page to make it easier to add/remove/label DUT's BUG=chromium:653727 TEST=local Change-Id: Id554af22b672ecd1bb9f8eeb89bf9b0a4206a7a0 Reviewed-on: https://chromium-review.googlesource.com/396463 Commit-Ready: Keith Haddow <[email protected]> Tested-by: Keith Haddow <[email protected]> Reviewed-by: Keith Haddow <[email protected]> Reviewed-by: Michael Tang <[email protected]>
diff --git a/frontend/afe/moblab_rpc_interface.py b/frontend/afe/moblab_rpc_interface.py index 22e6fef..f0ec8e3 100644 --- a/frontend/afe/moblab_rpc_interface.py +++ b/frontend/afe/moblab_rpc_interface.py
@@ -18,17 +18,19 @@ import ConfigParser import logging import os +import re import shutil import socket -import re - +import subprocess import common from autotest_lib.client.common_lib import error from autotest_lib.client.common_lib import global_config +from autotest_lib.frontend.afe import models, model_logic, model_attributes from autotest_lib.frontend.afe import rpc_utils from autotest_lib.server.hosts import moblab_host + _CONFIG = global_config.global_config MOBLAB_BOTO_LOCATION = '/home/moblab/.boto' @@ -45,6 +47,11 @@ _RESULT_STORAGE_SERVER = 'results_storage_server' _USE_EXISTING_BOTO_FILE = 'use_existing_boto_file' +# Location where dhcp leases are stored. +_DHCPD_LEASES = '/var/lib/dhcp/dhcpd.leases' + +# File where information about the current device is stored. +_ETC_LSB_RELEASE = '/etc/lsb-release' @rpc_utils.moblab_only def get_config_values(): @@ -456,10 +463,106 @@ @rpc_utils.moblab_only def get_version_info(): """ RPC handler to get informaiton about the version of the moblab. + @return: A serialized JSON RPC object. """ - lines = open('/etc/lsb-release').readlines() - lines.remove('') - version_response = {x.split('=')[0]: x.split('=')[1] for x in lines} + lines = open(_ETC_LSB_RELEASE).readlines() + version_response = { + x.split('=')[0]: x.split('=')[1] for x in lines if '=' in x} return rpc_utils.prepare_for_serialization(version_response) + +@rpc_utils.moblab_only +def get_connected_dut_info(): + """ RPC handler to get informaiton about the DUTs connected to the moblab. + + @return: A serialized JSON RPC object. + """ + # Make a list of the connected DUT's + leases = _get_dhcp_dut_leases() + + # Get a list of the AFE configured DUT's + hosts = list(rpc_utils.get_host_query((), False, False, True, {})) + models.Host.objects.populate_relationships(hosts, models.Label, + 'label_list') + configured_duts = {} + for host in hosts: + labels = [label.name for label in host.label_list] + labels.sort() + configured_duts[host.hostname] = ', '.join(labels) + + return rpc_utils.prepare_for_serialization( + {'configured_duts': configured_duts, + 'connected_duts': leases}) + + +def _get_dhcp_dut_leases(): + """ Extract information about connected duts from the dhcp server. + + @return: A dict of ipaddress to mac address for each device connected. + """ + lease_info = open(_DHCPD_LEASES).read() + + leases = {} + for lease in lease_info.split('lease'): + if lease.find('binding state active;') != -1: + ipaddress = lease.split('\n')[0].strip(' {') + last_octet = int(ipaddress.split('.')[-1].strip()) + if last_octet > 150: + continue + mac_address_search = re.search('hardware ethernet (.*);', lease) + if mac_address_search: + leases[ipaddress] = mac_address_search.group(1) + return leases + + +@rpc_utils.moblab_only +def add_moblab_dut(ipaddress): + """ RPC handler to add a connected DUT to autotest. + + @return: A string giving information about the status. + """ + cmd = '/usr/local/autotest/cli/atest host create %s &' % ipaddress + subprocess.call(cmd, shell=True) + return (True, 'DUT %s added to Autotest' % ipaddress) + + +@rpc_utils.moblab_only +def remove_moblab_dut(ipaddress): + """ RPC handler to remove DUT entry from autotest. + + @return: True if the command succeeds without an exception + """ + models.Host.smart_get(ipaddress).delete() + return (True, 'DUT %s deleted from Autotest' % ipaddress) + + +@rpc_utils.moblab_only +def add_moblab_label(ipaddress, label_name): + """ RPC handler to add a label in autotest to a DUT entry. + + @return: A string giving information about the status. + """ + # Try to create the label in case it does not already exist. + label = None + try: + label = models.Label.add_object(name=label_name) + except: + label = models.Label.smart_get(label_name) + host_obj = models.Host.smart_get(ipaddress) + if label: + label.host_set.add(host_obj) + return (True, 'Added label %s to DUT %s' % (label_name, ipaddress)) + return (False, 'Failed to add label %s to DUT %s' % (label_name, ipaddress)) + + +@rpc_utils.moblab_only +def remove_moblab_label(ipaddress, label_name): + """ RPC handler to remove a label in autotest from a DUT entry. + + @return: A string giving information about the status. + """ + host_obj = models.Host.smart_get(ipaddress) + models.Label.smart_get(label_name).host_set.remove(host_obj) + return (True, 'Removed label %s from DUT %s' % (label_name, ipaddress)) +
diff --git a/frontend/client/src/autotest/MoblabSetupClient.gwt.xml b/frontend/client/src/autotest/MoblabSetupClient.gwt.xml index 97b2859..2face8e 100644 --- a/frontend/client/src/autotest/MoblabSetupClient.gwt.xml +++ b/frontend/client/src/autotest/MoblabSetupClient.gwt.xml
@@ -2,6 +2,7 @@ <inherits name='com.google.gwt.user.User'/> <inherits name='com.google.gwt.json.JSON'/> <inherits name='com.google.gwt.http.HTTP'/> + <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> <source path="moblab"/> <source path="common"/> @@ -10,4 +11,5 @@ <stylesheet src='common.css'/> <stylesheet src='afeclient.css'/> <stylesheet src='standard.css'/> + <stylesheet src='moblabsetup.css'/> </module>
diff --git a/frontend/client/src/autotest/moblab/DutManagementView.java b/frontend/client/src/autotest/moblab/DutManagementView.java new file mode 100644 index 0000000..4e8ddad --- /dev/null +++ b/frontend/client/src/autotest/moblab/DutManagementView.java
@@ -0,0 +1,295 @@ +package autotest.moblab; + +import autotest.common.ui.TabView; +import autotest.moblab.rpc.ConnectedDutInfo; +import autotest.moblab.rpc.MoblabRpcCallbacks; +import autotest.moblab.rpc.MoblabRpcHelper; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.CheckBox; +import com.google.gwt.user.client.ui.FlexTable; +import com.google.gwt.user.client.ui.HasVerticalAlignment; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.TextArea; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; + +/** + * Implement a tab that makes it easier to add/remove/maintain duts. + */ +public class DutManagementView extends TabView { + + private FlexTable dutInfoTable; + private VerticalPanel dutSetupPanel; + private ListBox options; + private TextArea informationArea; + private Button actionButton; + private CheckBox poolCheckBox; + private TextBox poolLabelName; + private Label poolLabel; + + private static final int DHCP_IP_COLUMN = 0; + private static final int DHCP_MAC_COLUMN = 1; + private static final int SELECTION_COLUMN = 2; + private static final int LABELS_COLUMN = 3; + + @Override + public String getElementId() { + return "dut_manage"; + } + + @Override + public void refresh() { + super.refresh(); + dutInfoTable.removeAllRows(); + poolCheckBox.setValue(false); + poolLabelName.setText(""); + loadData(); + } + + @Override + public void initialize() { + super.initialize(); + // Main table of connected DUT information. + dutInfoTable = new FlexTable(); + + // The row of controls underneath the main data table. + dutSetupPanel = new VerticalPanel(); + + // List of actions to be applied to connected DUT's. + options = new ListBox(); + options.addItem("Add Selected DUT's"); + options.addItem("Remove Selected DUT's"); + options.addItem("Add Label Selected DUT's"); + options.addItem("Remove Label Selected DUT's"); + options.setStyleName("dut_manage_action_row"); + options.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + if (options.getSelectedIndex() == 2 || options.getSelectedIndex() == 3) { + poolCheckBox.setEnabled(true); + poolCheckBox.setValue(false); + poolLabelName.setEnabled(true); + poolLabelName.setText(""); + } else { + poolCheckBox.setEnabled(false); + poolLabelName.setEnabled(false); + } + } + }); + + // Logging area at the end of the screen that gives status messages about bulk + // actions requested. + informationArea = new TextArea(); + informationArea.setVisibleLines(10); + informationArea.setCharacterWidth(80); + informationArea.setReadOnly(true); + + // Apply button, each action needs to be applied after selecting the devices and + // the action to be performed. + actionButton = new Button("Apply", new ClickHandler() { + public void onClick(ClickEvent event) { + ((Button)event.getSource()).setEnabled(false); + int action = options.getSelectedIndex(); + try { + for (int i = 1; i < dutInfoTable.getRowCount(); i++) { + if (((CheckBox)dutInfoTable.getWidget(i, SELECTION_COLUMN)).getValue()) { + if (action == 0) { + addDut(i); + } else if (action == 1) { + removeDut(i); + } else if (action == 2) { + addLabel(i, getLabelString()); + } else if (action == 3) { + removeLabel(i, getLabelString()); + } + } + } + } finally { + ((Button)event.getSource()).setEnabled(true); + } + }}); + + + // For adding and removing labels a text input of the label is required. + poolCheckBox = new CheckBox(); + + // Pools are just special labels, this is just a helper to so users get + // it correct more of the time. + poolCheckBox.setText("Is pool label ?"); + poolCheckBox.setStyleName("dut_manage_action_row_item"); + + // The text label explaining the text box is for entering the label. + poolLabel = new Label(); + poolLabel.setText("Label name:"); + poolLabel.setStyleName("dut_manage_action_row_item"); + + // The text entry of the label to add or remove. + poolLabelName = new TextBox(); + poolLabelName.setStyleName("dut_manage_action_row_item"); + poolCheckBox.setEnabled(false); + poolLabelName.setEnabled(false); + } + + private String getLabelString() { + StringBuilder builder = new StringBuilder(poolLabelName.getText()); + if (poolCheckBox.getValue()) { + builder.insert(0, "pool:"); + } + return builder.toString(); + } + + private void loadData() { + + MoblabRpcHelper.fetchDutInformation(new MoblabRpcCallbacks.FetchConnectedDutInfoCallback() { + @Override + public void onFetchConnectedDutInfoSubmitted(ConnectedDutInfo info) { + addTableHeader(); + // The header is row 0 + int row = 1; + for (final String dutIpAddress : info.getConnectedIpsToMacAddress().keySet()) { + addRowStyles(row); + String labelString; + if (info.getConfiguredIpsToLabels().keySet().contains(dutIpAddress)) { + labelString = info.getConfiguredIpsToLabels().get(dutIpAddress); + } else { + labelString = "DUT Not Configured in Autotest"; + } + addRow(row, dutIpAddress, info.getConnectedIpsToMacAddress().get(dutIpAddress), labelString); + row++; + } + for (final String dutIpAddress : info.getConfiguredIpsToLabels().keySet()) { + if (!info.getConnectedIpsToMacAddress().keySet().contains(dutIpAddress)) { + // Device is in AFE but not detected in the DHCP table. + addRowStyles(row); + addRow(row, dutIpAddress, "", + "DUT Configured in Autotest but does not appear to be attached."); + row++; + } + } + } + }); + + // Assemble the display panels in the correct order. + dutSetupPanel.add(dutInfoTable); + HorizontalPanel actionRow = new HorizontalPanel(); + actionRow.setStyleName("dut_manage_action_row"); + actionRow.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); + actionRow.add(options); + actionRow.add(poolCheckBox); + actionRow.add(poolLabel); + actionRow.add(poolLabelName); + actionRow.add(actionButton); + dutSetupPanel.add(actionRow); + dutSetupPanel.add(informationArea); + addWidget(dutSetupPanel, "view_dut_manage"); + } + + /** + * Add the correct css styles for each data row. + * @param row index of the row to apply the styles for, first data row is 1. + */ + private void addRowStyles(int row) { + dutInfoTable.getCellFormatter().addStyleName(row, DHCP_IP_COLUMN,"ip_cell"); + dutInfoTable.getCellFormatter().addStyleName(row,DHCP_MAC_COLUMN,"mac_cell"); + dutInfoTable.getCellFormatter().addStyleName(row,SELECTION_COLUMN,"selection_cell"); + dutInfoTable.getCellFormatter().addStyleName(row,LABELS_COLUMN,"labels_cell"); + } + + /** + * Insert or update the data in the table for a given row. + * @param row The row index to update, first data row is 1. + * @param ipColumn String to be added into the first column. + * @param macColumn String to be added to the second column. + * @param labelsColumn String to be added to the fourth column. + */ + private void addRow(int row, String ipColumn, String macColumn, String labelsColumn) { + dutInfoTable.setWidget(row, DHCP_IP_COLUMN, new Label(ipColumn)); + dutInfoTable.setWidget(row, DHCP_MAC_COLUMN, new Label(macColumn)); + dutInfoTable.setWidget(row, SELECTION_COLUMN, new CheckBox()); + dutInfoTable.setWidget(row, LABELS_COLUMN, new Label(labelsColumn)); + } + + /** + * Add the column headers with the correct css styling into the data table. + */ + private void addTableHeader() { + dutInfoTable.addStyleName("dut_info_table"); + dutInfoTable.getCellFormatter().addStyleName(0, DHCP_IP_COLUMN, + "dut_manage_column_label_c"); + dutInfoTable.getCellFormatter().addStyleName(0, DHCP_MAC_COLUMN, + "dut_manage_column_label_c"); + dutInfoTable.getCellFormatter().addStyleName(0, SELECTION_COLUMN, + "dut_manage_column_label_c"); + dutInfoTable.getCellFormatter().addStyleName(0, LABELS_COLUMN, + "dut_manage_column_label_c"); + dutInfoTable.setWidget(0, DHCP_IP_COLUMN, new Label("DCHP Lease Address")); + dutInfoTable.setWidget(0, DHCP_MAC_COLUMN, new Label("DCHP MAC Address")); + dutInfoTable.setWidget(0, LABELS_COLUMN, new Label("DUT Labels")); + } + + /** + * Make an RPC call to the autotest system to enroll the DUT listed at the given row number. + * @param row_number the row number in the table that has details of the device to enroll. + */ + private void addDut(int row_number) { + String ipAddress = ((Label)dutInfoTable.getWidget(row_number, DHCP_IP_COLUMN)).getText(); + MoblabRpcHelper.addMoblabDut(ipAddress, new LogAction(informationArea)); + } + + /** + * Make an RPC to to the autotest system to delete information about the DUT listed at the given + * row. + * @param row_number the row number in the table that has details of the device to remove. + */ + private void removeDut(int row_number) { + String ipAddress = ((Label)dutInfoTable.getWidget(row_number, DHCP_IP_COLUMN)).getText(); + MoblabRpcHelper.removeMoblabDut(ipAddress, new LogAction(informationArea)); + } + + /** + * Make an RPC to to the autotest system to add a label to a DUT whoes details are in the given + * row. + * @param row_number row in the data table that has the information about the DUT + * @param labelName the label string to be added. + */ + private void addLabel(int row_number, String labelName) { + String ipAddress = ((Label)dutInfoTable.getWidget(row_number, DHCP_IP_COLUMN)).getText(); + MoblabRpcHelper.addMoblabLabel(ipAddress, labelName, new LogAction(informationArea)); + } + + /** + * Make an RPC to to the autotest system to remove a label to a DUT whoes details are in the + * given row. + * @param row_number row in the data table that has the information about the DUT + * @param labelName the label string to be removed. + */ + private void removeLabel(int row_number, String labelName) { + String ipAddress = ((Label)dutInfoTable.getWidget(row_number, DHCP_IP_COLUMN)).getText(); + MoblabRpcHelper.removeMoblabLabel(ipAddress, labelName, new LogAction(informationArea)); + } + + /** + * Call back that inserts a string from an completed RPC into the UI. + */ + private static class LogAction implements MoblabRpcCallbacks.LogActionCompleteCallback { + private TextArea informationArea; + + LogAction(TextArea informationArea){ + this.informationArea = informationArea; + } + @Override + public void onLogActionComplete(boolean status, String information) { + String currentText = informationArea.getText(); + informationArea + .setText(new StringBuilder().append(information).append( + "\n").append(currentText).toString()); + } + } +}
diff --git a/frontend/client/src/autotest/moblab/MoblabSetupClient.java b/frontend/client/src/autotest/moblab/MoblabSetupClient.java index e2a4fc9..a0138d3 100644 --- a/frontend/client/src/autotest/moblab/MoblabSetupClient.java +++ b/frontend/client/src/autotest/moblab/MoblabSetupClient.java
@@ -13,6 +13,7 @@ private ConfigSettingsView configSettingsView; private BotoKeyView botoKeyView; private LaunchControlKeyView launchControlKeyView; + private DutManagementView dutManagementView; public CustomTabPanel mainTabPanel = new CustomTabPanel(); @@ -28,10 +29,12 @@ configSettingsView = new ConfigSettingsView(); botoKeyView = new BotoKeyView(); launchControlKeyView = new LaunchControlKeyView(); + dutManagementView = new DutManagementView(); mainTabPanel.addTabView(configWizardView); mainTabPanel.addTabView(configSettingsView); mainTabPanel.addTabView(botoKeyView); mainTabPanel.addTabView(launchControlKeyView); + mainTabPanel.addTabView(dutManagementView); final RootPanel rootPanel = RootPanel.get("tabs"); rootPanel.add(mainTabPanel);
diff --git a/frontend/client/src/autotest/moblab/rpc/ConnectedDutInfo.java b/frontend/client/src/autotest/moblab/rpc/ConnectedDutInfo.java new file mode 100644 index 0000000..fc670f2 --- /dev/null +++ b/frontend/client/src/autotest/moblab/rpc/ConnectedDutInfo.java
@@ -0,0 +1,44 @@ +package autotest.moblab.rpc; + +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONObject; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * The connected DUT information RPC entity. + */ +public class ConnectedDutInfo extends JsonRpcEntity { + + private Map<String, String> connectedIpsToMacAddresses; + private Map<String, String> configuredIpsToLabels; + + public ConnectedDutInfo() { + connectedIpsToMacAddresses = new TreeMap<String, String>(); + configuredIpsToLabels = new TreeMap<String, String>(); + } + + public Map<String, String> getConnectedIpsToMacAddress() { return connectedIpsToMacAddresses; } + public Map<String, String> getConfiguredIpsToLabels() { return configuredIpsToLabels; } + + @Override + public void fromJson(JSONObject object) { + JSONObject leases = object.get("connected_duts").isObject(); + for (String lease : leases.keySet()) { + connectedIpsToMacAddresses.put(lease, leases.get(lease).isString().stringValue()); + } + JSONObject configuredDuts = object.get("configured_duts").isObject(); + for (String ipAddress : configuredDuts.keySet()) { + configuredIpsToLabels.put(ipAddress, configuredDuts.get(ipAddress).isString().stringValue()); + } + } + + @Override + public JSONObject toJson() { + // This is a read only RPC call so nothing to be submitted back to the + // server from the UI. + return null; + } +}
diff --git a/frontend/client/src/autotest/moblab/rpc/MoblabRpcCallbacks.java b/frontend/client/src/autotest/moblab/rpc/MoblabRpcCallbacks.java index 8429b6f..b439b9d 100644 --- a/frontend/client/src/autotest/moblab/rpc/MoblabRpcCallbacks.java +++ b/frontend/client/src/autotest/moblab/rpc/MoblabRpcCallbacks.java
@@ -41,4 +41,18 @@ public void onVersionInfoFetched(VersionInfo info); } + /** + * Callback for to get information about the connected DUT's. + */ + public interface FetchConnectedDutInfoCallback { + public void onFetchConnectedDutInfoSubmitted(ConnectedDutInfo info); + } + + /** + * Generic callback to return a status and information string from a RPC call. + */ + public interface LogActionCompleteCallback { + public void onLogActionComplete(boolean didSucceed, String information); + } + }
diff --git a/frontend/client/src/autotest/moblab/rpc/MoblabRpcHelper.java b/frontend/client/src/autotest/moblab/rpc/MoblabRpcHelper.java index 26d50c2..12795a6 100644 --- a/frontend/client/src/autotest/moblab/rpc/MoblabRpcHelper.java +++ b/frontend/client/src/autotest/moblab/rpc/MoblabRpcHelper.java
@@ -1,12 +1,15 @@ package autotest.moblab.rpc; +import com.google.gwt.json.client.JSONNumber; import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; import autotest.common.JsonRpcCallback; import autotest.common.JsonRpcProxy; import autotest.common.SimpleCallback; +import com.google.gwt.user.client.Window; import java.util.Map; /** @@ -143,11 +146,111 @@ final MoblabRpcCallbacks.FetchVersionInfoCallback callback) { JsonRpcProxy rpcProxy = JsonRpcProxy.getProxy(); rpcProxy.rpcCall("get_version_info", null, new JsonRpcCallback() { + @Override + public void onSuccess(JSONValue result) { + VersionInfo info = new VersionInfo(); + info.fromJson(result.isObject()); + callback.onVersionInfoFetched(info); + } + }); + } + + /** + * Get information about the DUT's connected to the moblab. + */ + public static void fetchDutInformation( + final MoblabRpcCallbacks.FetchConnectedDutInfoCallback callback) { + JsonRpcProxy rpcProxy = JsonRpcProxy.getProxy(); + rpcProxy.rpcCall("get_connected_dut_info", null, new JsonRpcCallback() { @Override public void onSuccess(JSONValue result) { - VersionInfo info = new VersionInfo(); + ConnectedDutInfo info = new ConnectedDutInfo(); info.fromJson(result.isObject()); - callback.onVersionInfoFetched(info); + callback.onFetchConnectedDutInfoSubmitted(info); + } + }); + } + + /** + * Enroll a device into the autotest syste. + * @param dutIpAddress ipAddress of the new DUT. + * @param callback Callback execute when the RPC is complete. + */ + public static void addMoblabDut(String dutIpAddress, + final MoblabRpcCallbacks.LogActionCompleteCallback callback) { + JsonRpcProxy rpcProxy = JsonRpcProxy.getProxy(); + JSONObject params = new JSONObject(); + params.put("ipaddress", new JSONString(dutIpAddress)); + rpcProxy.rpcCall("add_moblab_dut", params, new JsonRpcCallback() { + @Override + public void onSuccess(JSONValue result) { + boolean didSucceed = result.isArray().get(0).isBoolean().booleanValue(); + String information = result.isArray().get(1).isString().stringValue(); + callback.onLogActionComplete(didSucceed, information); + } + }); + } + + /** + * Remove a device from the autotest system. + * @param dutIpAddress ipAddress of the DUT to remove. + * @param callback Callback to execute when the RPC is complete. + */ + public static void removeMoblabDut(String dutIpAddress, + final MoblabRpcCallbacks.LogActionCompleteCallback callback) { + JsonRpcProxy rpcProxy = JsonRpcProxy.getProxy(); + JSONObject params = new JSONObject(); + params.put("ipaddress", new JSONString(dutIpAddress)); + rpcProxy.rpcCall("remove_moblab_dut", params, new JsonRpcCallback() { + @Override + public void onSuccess(JSONValue result) { + boolean didSucceed = result.isArray().get(0).isBoolean().booleanValue(); + String information = result.isArray().get(1).isString().stringValue(); + callback.onLogActionComplete(didSucceed, information); + } + }); + } + + /** + * Add a label to a specific DUT. + * @param dutIpAddress ipAddress of the device to have the new label applied. + * @param labelName the label to apply + * @param callback callback to execute when the RPC is complete. + */ + public static void addMoblabLabel(String dutIpAddress, String labelName, + final MoblabRpcCallbacks.LogActionCompleteCallback callback) { + JsonRpcProxy rpcProxy = JsonRpcProxy.getProxy(); + JSONObject params = new JSONObject(); + params.put("ipaddress", new JSONString(dutIpAddress)); + params.put("label_name", new JSONString(labelName)); + rpcProxy.rpcCall("add_moblab_label", params, new JsonRpcCallback() { + @Override + public void onSuccess(JSONValue result) { + boolean didSucceed = result.isArray().get(0).isBoolean().booleanValue(); + String information = result.isArray().get(1).isString().stringValue(); + callback.onLogActionComplete(didSucceed, information); + } + }); + } + + /** + * Remove a label from a specific DUT. + * @param dutIpAddress ipAddress of the device to have the label removed. + * @param labelName the label to remove + * @param callback callback to execute when the RPC is complete. + */ + public static void removeMoblabLabel(String dutIpAddress, String labelName, + final MoblabRpcCallbacks.LogActionCompleteCallback callback) { + JsonRpcProxy rpcProxy = JsonRpcProxy.getProxy(); + JSONObject params = new JSONObject(); + params.put("ipaddress", new JSONString(dutIpAddress)); + params.put("label_name", new JSONString(labelName)); + rpcProxy.rpcCall("remove_moblab_label", params, new JsonRpcCallback() { + @Override + public void onSuccess(JSONValue result) { + boolean didSucceed = result.isArray().get(0).isBoolean().booleanValue(); + String information = result.isArray().get(1).isString().stringValue(); + callback.onLogActionComplete(didSucceed, information); } }); }
diff --git a/frontend/client/src/autotest/public/MoblabSetupClient.html b/frontend/client/src/autotest/public/MoblabSetupClient.html index 48bab03..14a8c8b 100644 --- a/frontend/client/src/autotest/public/MoblabSetupClient.html +++ b/frontend/client/src/autotest/public/MoblabSetupClient.html
@@ -34,6 +34,10 @@ <span id="view_submit_launch_control_key"></span> </div> + <div id="dut_manage" title="Manage DUTs"> + <span id="view_dut_manage"></span><br> + </div> + </div> <br>
diff --git a/frontend/client/src/autotest/public/moblabsetup.css b/frontend/client/src/autotest/public/moblabsetup.css new file mode 100644 index 0000000..ed80b74 --- /dev/null +++ b/frontend/client/src/autotest/public/moblabsetup.css
@@ -0,0 +1,58 @@ + +.dut_info_table { + padding: 5px; + background-color: white; + border-spacing: 0; + border-collapse: collapse; + border-bottom: thin solid black; +} + +.dut_manage_column_label_c { + color: black; + border-bottom: thin solid #111111; + text-align: center; + padding-left: 15px; + padding-right: 15px; + padding-bottom: 10px; +} + +.dut_manage_column_label_l { + color: black; + border-bottom: thin solid #111111; + text-align: left; + padding-left: 5px; +} + +.ip_cell, +.mac_cell, +.selection_cell, +.labels_cell { + border-width: 0px 0px 0px 0px; + border-style: solid; + border-color: black; +} + +.ip_cell, +.mac_cell, +.selection_cell { + text-align:center; +} + +.labels_cell { + text-align:left; +} + + +.dut_manage_action_row { + padding: 5px; + text-align: center; +} + +.dut_manage_action_row { + padding: 5px; + text-align: center; +} + +.dut_manage_action_row_item { + padding-left: 20px; +}