/* * RHQ Management Platform * Copyright (C) 2005-2014 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc, * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.coregui.client.admin.topology; import static org.rhq.coregui.client.admin.topology.AgentDatasourceField.FIELD_ADDRESS; import static org.rhq.coregui.client.admin.topology.AgentDatasourceField.FIELD_AFFINITY_GROUP; import static org.rhq.coregui.client.admin.topology.AgentDatasourceField.FIELD_AFFINITY_GROUP_ID; import static org.rhq.coregui.client.admin.topology.AgentDatasourceField.FIELD_SERVER; import static org.rhq.coregui.client.admin.topology.AgentDatasourceField.FIELD_SERVER_ID; import java.util.List; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.types.SortDirection; import com.smartgwt.client.util.BooleanCallback; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.grid.CellFormatter; import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.install.remote.AgentInstall; import org.rhq.core.domain.resource.Agent; import org.rhq.coregui.client.CoreGUI; import org.rhq.coregui.client.IconEnum; import org.rhq.coregui.client.LinkManager; import org.rhq.coregui.client.PopupWindow; import org.rhq.coregui.client.admin.AdministrationView; import org.rhq.coregui.client.admin.agent.install.RemoteAgentInstallView; import org.rhq.coregui.client.admin.agent.install.RemoteAgentInstallView.Type; import org.rhq.coregui.client.components.table.AuthorizedTableAction; import org.rhq.coregui.client.components.table.TableActionEnablement; import org.rhq.coregui.client.components.table.TableSection; import org.rhq.coregui.client.components.view.HasViewName; import org.rhq.coregui.client.components.view.ViewName; import org.rhq.coregui.client.gwt.GWTServiceLookup; import org.rhq.coregui.client.gwt.ResourceGWTServiceAsync; import org.rhq.coregui.client.util.StringUtility; import org.rhq.coregui.client.util.enhanced.EnhancedIButton.ButtonColor; import org.rhq.coregui.client.util.message.Message; /** * Shows the table of all agents. * * This component is used from three various contexts: * 1) simple list of all available agents (url fragment - #Administration/Topology/Agents) * 2) list of agents connected to the server on server detail page (#Administration/Topology/Servers/{serverId}) * 3) list of agents assigned to a affinity group (#Administration/Topology/AffinityGroups/{aGroupId}) * * @author Jirka Kremser */ public class AgentTableView extends TableSection<AgentDatasource> implements HasViewName { public static final ViewName VIEW_ID = new ViewName("Agents", MSG.view_adminTopology_agents(), IconEnum.AGENT); public static final String VIEW_PATH = AdministrationView.VIEW_ID + "/" + AdministrationView.SECTION_TOPOLOGY_VIEW_ID + "/" + VIEW_ID; private final boolean isAffinityGroupId; private final Integer id; private PopupWindow popupWindow = null; private RemoteAgentInstallView remoteAgentView = null; public AgentTableView(Integer id, boolean isAffinityGroupId) { super(null); this.isAffinityGroupId = isAffinityGroupId; this.id = id; setHeight100(); setWidth100(); setDataSource(new AgentDatasource(id, isAffinityGroupId)); } @Override protected void configureTable() { super.configureTable(); List<ListGridField> fields = getDataSource().getListGridFields(); ListGrid listGrid = getListGrid(); listGrid.setFields(fields.toArray(new ListGridField[fields.size()])); listGrid.sort(FIELD_NAME, SortDirection.ASCENDING); for (ListGridField field : fields) { // adding the cell formatter for name field (clickable link) if (FIELD_NAME.equals(field.getName())) { field.setCellFormatter(new CellFormatter() { @Override public String format(Object value, ListGridRecord record, int rowNum, int colNum) { if (value == null) { return ""; } String detailsUrl = "#" + VIEW_PATH + "/" + getId(record); String formattedValue = StringUtility.escapeHtml(value.toString()); return LinkManager.getHref(detailsUrl, formattedValue); } }); } else if (FIELD_SERVER.propertyName().equals(field.getName())) { // adding the cell formatter for server field (clickable link) field.setCellFormatter(new CellFormatter() { @Override public String format(Object value, ListGridRecord record, int rowNum, int colNum) { if (value == null || value.toString().isEmpty()) { return ""; } String detailsUrl = "#" + ServerTableView.VIEW_PATH + "/" + record.getAttributeAsString(FIELD_SERVER_ID.propertyName()); String formattedValue = StringUtility.escapeHtml(value.toString()); return LinkManager.getHref(detailsUrl, formattedValue); } }); } else if (FIELD_AFFINITY_GROUP.propertyName().equals(field.getName())) { // adding the cell formatter for affinity group field (clickable link) field.setCellFormatter(new CellFormatter() { @Override public String format(Object value, ListGridRecord record, int rowNum, int colNum) { if (value == null || value.toString().isEmpty()) { return ""; } String detailsUrl = "#" + AffinityGroupTableView.VIEW_PATH + "/" + record.getAttributeAsString(FIELD_AFFINITY_GROUP_ID.propertyName()); String formattedValue = StringUtility.escapeHtml(value.toString()); return LinkManager.getHref(detailsUrl, formattedValue); } }); } } // list of all agents (context #1 see the class JavaDoc) if (id == null) { setupNewButton(); setupDeleteButton(); setupStartButton(); setupStopButton(); } // list of agents assigned to affinity group (context #3) if (isAffinityGroupId) { showUpdateMembersAction(); } } private void setupNewButton() { addTableAction(MSG.common_button_new(), null, ButtonColor.BLUE, new AuthorizedTableAction(this, TableActionEnablement.ALWAYS, Permission.MANAGE_INVENTORY) { public void executeAction(final ListGridRecord[] selections, Object actionValue) { newDetails(); } }); } private void showRemoteAgentInstallView(AgentInstall ai, String title, RemoteAgentInstallView.Type type) { showRemoteAgentInstallView(ai, title, type, new RemoteAgentInstallView.SuccessHandler() { @Override public void onSuccess(Type type) { closeInstallView(); } }); } private void showRemoteAgentInstallView(AgentInstall ai, String title, RemoteAgentInstallView.Type type, RemoteAgentInstallView.SuccessHandler successHandler) { remoteAgentView = new RemoteAgentInstallView(ai, type); remoteAgentView.setSuccessHandler(successHandler); popupWindow = new PopupWindow(remoteAgentView); popupWindow.setTitle(title); popupWindow.setHeight(350); popupWindow.setWidth(850); popupWindow.show(); refreshTableInfo(); } private void closeInstallView() { remoteAgentView.markForDestroy(); popupWindow.markForDestroy(); } private void setupStartButton() { addTableAction(MSG.common_button_start(), null, ButtonColor.GRAY, new AuthorizedTableAction(this, TableActionEnablement.SINGLE, Permission.MANAGE_INVENTORY) { public void executeAction(final ListGridRecord[] selections, Object actionValue) { if (selections == null || selections.length == 0) { return; // do nothing since nothing is selected (we really shouldn't get here) } final String agentName = selections[0].getAttributeAsString(FIELD_NAME); final String agentAddress = selections[0].getAttributeAsString(FIELD_ADDRESS.propertyName()); GWTServiceLookup.getAgentService().getAgentInstallByAgentName(agentName, new AsyncCallback<AgentInstall>() { @Override public void onSuccess(AgentInstall result) { showRemoteAgentInstallViewAsync(result); } @Override public void onFailure(Throwable caught) { showRemoteAgentInstallViewAsync(null); // can't get any info on the agent - the user will have to provide it all } private void showRemoteAgentInstallViewAsync(AgentInstall ai) { // if no hostname is in agent install info, help out the user by suggesting the agent endpoint hostname if (ai != null && ai.getSshHost() == null) { ai.setSshHost(agentAddress); } showRemoteAgentInstallView(ai, MSG.common_label_startAgent(), Type.START); } }); } }); } private void setupStopButton() { addTableAction(MSG.common_button_stop(), null, ButtonColor.GRAY, new AuthorizedTableAction(this, TableActionEnablement.SINGLE, Permission.MANAGE_INVENTORY) { public void executeAction(final ListGridRecord[] selections, Object actionValue) { if (selections == null || selections.length == 0) { return; // do nothing since nothing is selected (we really shouldn't get here) } final String agentName = selections[0].getAttributeAsString(FIELD_NAME); final String agentAddress = selections[0].getAttributeAsString(FIELD_ADDRESS.propertyName()); GWTServiceLookup.getAgentService().getAgentInstallByAgentName(agentName, new AsyncCallback<AgentInstall>() { @Override public void onSuccess(AgentInstall result) { showRemoteAgentInstallViewAsync(result); } @Override public void onFailure(Throwable caught) { showRemoteAgentInstallViewAsync(null); // can't get any info on the agent - the user will have to provide it all } private void showRemoteAgentInstallViewAsync(AgentInstall ai) { // if no hostname is in agent install info, help out the user by suggesting the agent endpoint hostname if (ai != null && ai.getSshHost() == null) { ai.setSshHost(agentAddress); } showRemoteAgentInstallView(ai, MSG.view_adminTopology_agent_stop(), Type.STOP); } }); } }); } private void setupDeleteButton() { addTableAction(MSG.common_button_delete(), MSG.view_adminTopology_agent_delete_confirm(), ButtonColor.RED, new AuthorizedTableAction(this, TableActionEnablement.SINGLE, Permission.MANAGE_INVENTORY) { public void executeAction(final ListGridRecord[] selections, Object actionValue) { if (selections == null || selections.length == 0) { refresh(); return; // do nothing since nothing is selected (we really shouldn't get here) } // Get the selected agents. // Some of the code below supports removing multiple agents - however, I had to change the UI to only // allow the user to only be able to select one at a time for deletion because we need to support // the ability to uninstall it. And as of the time of me writing this, we can only uninstall via // the dialog box to uninstall which would get ugly if we popped up multiple ones. We could uninstall // multiple agents without asking the user via the dialog however it would mean we must have the SSH // credentials and the install location in the DB for all of them and I'm not sure this is always going // to be available for all agents. final Agent[] agents = new Agent[selections.length]; int i = 0; for (ListGridRecord selection : selections) { final int agentId = selection.getAttributeAsInt(FIELD_ID); final String agentName = selection.getAttribute(FIELD_NAME); final String agentHost = selection.getAttribute(FIELD_ADDRESS.propertyName()); // this might not be needed final Agent agent = new Agent(); agent.setId(agentId); agent.setName(agentName); agent.setAddress(agentHost); agents[i++] = agent; } // ask if we want to uninstall it SC.ask(MSG.view_adminTopology_agent_uninstallConfirm(), new BooleanCallback() { public void execute(final Boolean uninstall) { // if uninstall is true the user wants us to try to remove the agent installation files on the remote box if (uninstall) { GWTServiceLookup.getAgentService().getAgentInstallByAgentName(agents[0].getName(), new AsyncCallback<AgentInstall>() { @Override public void onSuccess(AgentInstall result) { RemoteAgentInstallView.SuccessHandler resourceRemover = new RemoteAgentInstallView.SuccessHandler() { @Override public void onSuccess(RemoteAgentInstallView.Type type) { if (type == Type.UNINSTALL) { removeResources(); closeInstallView(); } } }; showRemoteAgentInstallView(result, MSG.view_adminTopology_agent_uninstall(), Type.UNINSTALL, resourceRemover); } @Override public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError( MSG.view_adminTopology_agent_delete_error(), caught); refreshTableInfo(); } }); } else { // user doesn't want us to uninstall, just to remove the agent resources removeResources(); } } private void removeResources() { final ResourceGWTServiceAsync resourceManager = GWTServiceLookup.getResourceService(); resourceManager.uninventoryAllResourcesByAgent(agents, new AsyncCallback<Void>() { public void onSuccess(Void result) { CoreGUI.getMessageCenter().notify( new Message(MSG.view_adminTopology_agent_delete_submitted(Integer .toString(agents.length)))); refresh(); } public void onFailure(Throwable caught) { CoreGUI.getErrorHandler().handleError(MSG.view_adminTopology_agent_delete_error(), caught); refreshTableInfo(); } }); } }); } }); } private void showUpdateMembersAction() { addTableAction(MSG.view_groupInventoryMembers_button_updateMembership(), ButtonColor.BLUE, new AuthorizedTableAction(this, TableActionEnablement.ALWAYS, Permission.MANAGE_SETTINGS) { public void executeAction(final ListGridRecord[] selections, Object actionValue) { AffinityGroupAgentsSelector.show(id, AgentTableView.this); } }); } @Override public Canvas getDetailsView(Integer id) { if (id != null && id.intValue() > 0) { return new AgentDetailView(id); } else { return new RemoteAgentInstallView(null, Type.INSTALL); } } @Override public ViewName getViewName() { return VIEW_ID; } @Override protected String getBasePath() { return VIEW_PATH; } }