/* * 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, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * 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 and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser 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.agent.install; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.RepeatingCommand; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.types.Alignment; import com.smartgwt.client.types.Autofit; import com.smartgwt.client.types.ExpansionMode; import com.smartgwt.client.types.Overflow; import com.smartgwt.client.util.BooleanCallback; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.Dialog; import com.smartgwt.client.widgets.HTMLFlow; import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.events.ClickHandler; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.ButtonItem; import com.smartgwt.client.widgets.form.fields.CanvasItem; import com.smartgwt.client.widgets.form.fields.CheckboxItem; import com.smartgwt.client.widgets.form.fields.HeaderItem; import com.smartgwt.client.widgets.form.fields.PasswordItem; import com.smartgwt.client.widgets.form.fields.StaticTextItem; import com.smartgwt.client.widgets.form.fields.TextItem; import com.smartgwt.client.widgets.form.fields.events.ChangedEvent; import com.smartgwt.client.widgets.form.fields.events.ChangedHandler; import com.smartgwt.client.widgets.form.validator.CustomValidator; import com.smartgwt.client.widgets.form.validator.IntegerRangeValidator; import com.smartgwt.client.widgets.form.validator.IsIntegerValidator; import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import com.smartgwt.client.widgets.layout.HLayout; import com.smartgwt.client.widgets.layout.Layout; import com.smartgwt.client.widgets.layout.VLayout; import org.rhq.core.domain.install.remote.AgentInstall; import org.rhq.core.domain.install.remote.AgentInstallInfo; import org.rhq.core.domain.install.remote.AgentInstallStep; import org.rhq.core.domain.install.remote.CustomAgentInstallData; import org.rhq.core.domain.install.remote.RemoteAccessInfo; import org.rhq.core.domain.install.remote.SSHSecurityException; import org.rhq.core.domain.measurement.MeasurementUnits; import org.rhq.coregui.client.CoreGUI; import org.rhq.coregui.client.IconEnum; import org.rhq.coregui.client.components.upload.DynamicFormHandler; import org.rhq.coregui.client.components.upload.DynamicFormSubmitCompleteEvent; import org.rhq.coregui.client.components.upload.FileUploadForm; import org.rhq.coregui.client.components.view.ViewName; import org.rhq.coregui.client.gwt.GWTServiceLookup; import org.rhq.coregui.client.gwt.RemoteInstallGWTServiceAsync; import org.rhq.coregui.client.util.ErrorHandler; import org.rhq.coregui.client.util.MeasurementConverterClient; import org.rhq.coregui.client.util.enhanced.EnhancedIButton; import org.rhq.coregui.client.util.enhanced.EnhancedVLayout; import org.rhq.coregui.client.util.message.Message; /** * @author Greg Hinkle */ public class RemoteAgentInstallView extends EnhancedVLayout { public static final ViewName VIEW_ID = new ViewName("RemoteAgentInstall", MSG.view_adminTopology_remoteAgentInstall(), IconEnum.AGENT); private RemoteInstallGWTServiceAsync remoteInstallService = GWTServiceLookup.getRemoteInstallService(600000); private DynamicForm connectionForm; private Layout buttonsForm; private EnhancedIButton installButton; private EnhancedIButton uninstallButton; private EnhancedIButton startButton; private EnhancedIButton stopButton; private TextItem agentInstallPath; private StaticTextItem agentStatusText; private ButtonItem findAgentInstallPathButton; private ButtonItem statusCheckButton; private CheckboxItem rememberMeCheckbox; private Dialog dialog; private final boolean showInstallButton; private final boolean showUninstallButton; private final boolean showStartButton; private final boolean showStopButton; private AgentInstall initialAgentInstall; private SuccessHandler successHandler = null; // for installing agents, these are the components to work with uploading config files for the new agent to use private FileUploadForm agentConfigXmlUploadForm; private FileUploadForm rhqAgentEnvUploadForm; private String agentConfigurationXml = null; private String rhqAgentEnvSh = null; private final AbsolutePathValidator absPathValidator = new AbsolutePathValidator(); // if the user has explicitly authorized the unknown host private boolean hostAuthorized = false; public static enum Type { INSTALL, UNINSTALL, START, STOP; } public RemoteAgentInstallView(AgentInstall initialInfo, Type type) { super(); setMembersMargin(1); setWidth100(); setHeight100(); this.initialAgentInstall = initialInfo; this.showInstallButton = (type == Type.INSTALL); this.showUninstallButton = (type == Type.UNINSTALL); this.showStartButton = (type == Type.START); this.showStopButton = (type == Type.STOP); } @Override protected void onInit() { super.onInit(); Layout layout = new VLayout(); layout.setPadding(5); layout.setMembersMargin(5); layout.addMember(getConnectionForm()); layout.setDefaultLayoutAlign(Alignment.CENTER); layout.setLayoutAlign(Alignment.CENTER); if (this.showInstallButton) { agentConfigXmlUploadForm = createAgentConfigXmlUploadForm(); layout.addMember(agentConfigXmlUploadForm); /* For now, don't allow users to upload and ship their own env script to a remote machine; that might have security implications. * If we want to allow this, just uncomment these lines and you are good to go because everything else that is needed * is already in place and working as of April 2014. rhqAgentEnvUploadForm = createAgentEnvUploadForm(); layout.addMember(rhqAgentEnvUploadForm); */ } HTMLFlow header = new HTMLFlow(""); header.setStyleName("headerItem"); header.setExtraSpace(5); layout.addMember(header); layout.addMember(getButtons()); addMember(layout); } private DynamicForm getConnectionForm() { connectionForm = new DynamicForm(); connectionForm.setNumCols(4); connectionForm.setWrapItemTitles(false); connectionForm.setColWidths("130", "450", "110"); connectionForm.setExtraSpace(15); connectionForm.setWidth(790); connectionForm.setPadding(5); connectionForm.setIsGroup(true); connectionForm.setGroupTitle(MSG.view_remoteAgentInstall_connInfo()); final int textFieldWidth = 440; TextItem host = new TextItem("host", MSG.common_title_host()); host.setRequired(true); host.setWidth(textFieldWidth); host.setPrompt(MSG.view_remoteAgentInstall_promptHost()); host.setHoverWidth(300); host.setEndRow(true); host.addChangedHandler(new ChangedHandler() { @Override public void onChanged(ChangedEvent event) { hostAuthorized = false; // if the host changes, we need to make sure the user authorizes it if needed } }); TextItem port = new TextItem("port", MSG.common_title_port()); port.setRequired(false); port.setWidth(textFieldWidth); port.setPrompt(MSG.view_remoteAgentInstall_promptPort()); port.setHoverWidth(300); port.setEndRow(true); IntegerRangeValidator portValidator = new IntegerRangeValidator(); portValidator.setMin(1); portValidator.setMax(65535); port.setValidators(new IsIntegerValidator(), portValidator); TextItem username = new TextItem("username", MSG.common_title_user()); username.setRequired(false); // if not specified, the server will attempt to use the default ssh user defined in system settings username.setWidth(textFieldWidth); username.setPrompt(MSG.view_remoteAgentInstall_promptUser()); username.setHoverWidth(300); username.setEndRow(true); PasswordItem password = new PasswordItem("password", MSG.common_title_password()); password.setRequired(false); // if not specified, the server will attempt to use the default ssh pw defined in system settings password.setWidth(textFieldWidth); password.setPrompt(MSG.view_remoteAgentInstall_promptPassword()); password.setHoverWidth(300); password.setEndRow(true); password.setAttribute("autocomplete", "off"); rememberMeCheckbox = new CheckboxItem("rememberme", MSG.view_remoteAgentInstall_rememberMe()); rememberMeCheckbox.setRequired(false); rememberMeCheckbox.setPrompt(MSG.view_remoteAgentInstall_promptRememberMe()); rememberMeCheckbox.setHoverWidth(300); rememberMeCheckbox.setColSpan(2); rememberMeCheckbox.setEndRow(true); agentInstallPath = new TextItem("agentInstallPath", MSG.view_remoteAgentInstall_installPath()); agentInstallPath.setWidth(textFieldWidth); agentInstallPath.setPrompt(MSG.view_remoteAgentInstall_promptInstallPath()); agentInstallPath.setHoverWidth(300); agentInstallPath.setStartRow(true); agentInstallPath.setEndRow(false); agentInstallPath.setValidators(absPathValidator); // we will "turn this on" when needed - this is to ensure we create paths properly and it doesn't go in places user isn't expecting findAgentInstallPathButton = new ButtonItem("findAgentInstallPathButton", MSG.view_remoteAgentInstall_buttonFindAgent()); findAgentInstallPathButton.setStartRow(false); findAgentInstallPathButton.setEndRow(true); if (findAgentInstallPathButton.getTitle().length() < 15) { //i18n may prolong the title findAgentInstallPathButton.setWidth(100); } findAgentInstallPathButton.addClickHandler(new com.smartgwt.client.widgets.form.fields.events.ClickHandler() { public void onClick(com.smartgwt.client.widgets.form.fields.events.ClickEvent clickEvent) { // we only want to validate host if (connectionForm.getValueAsString("host") == null || connectionForm.getValueAsString("host").trim().isEmpty()) { final HashMap<String, String> errors = new HashMap<String, String>(1); errors.put("host", CoreGUI.getSmartGwtMessages().validator_requiredField()); connectionForm.setErrors(errors, true); return; } new CheckSSHConnectionCallback() { @Override protected void doActualWork() { findAgentInstallPath(); } }.execute(); } }); createAgentStatusTextItem(); statusCheckButton = new ButtonItem("updateStatus", MSG.common_title_updateStatus()); statusCheckButton.setStartRow(false); statusCheckButton.setEndRow(true); if (findAgentInstallPathButton.getTitle().length() < 15) { //i18n may prolong the title statusCheckButton.setWidth(100); } statusCheckButton.addClickHandler(new com.smartgwt.client.widgets.form.fields.events.ClickHandler() { public void onClick(com.smartgwt.client.widgets.form.fields.events.ClickEvent clickEvent) { if (connectionForm.validate()) { new CheckSSHConnectionCallback() { @Override protected void doActualWork() { agentStatusCheck(); } }.execute(); } } }); if (initialAgentInstall != null) { host.setValue(initialAgentInstall.getSshHost()); if (initialAgentInstall.getSshPort() != null) { port.setValue(String.valueOf(initialAgentInstall.getSshPort())); } username.setValue(initialAgentInstall.getSshUsername()); password.setValue(initialAgentInstall.getSshPassword()); agentInstallPath.setValue(initialAgentInstall.getInstallLocation()); // if it was already saved, assume they want it to stay remembered // however, because the uninstall page is getting rid of the agent, we don't need or want to remember the credentials anymore if (!this.showUninstallButton) { rememberMeCheckbox.setValue(initialAgentInstall.getSshPassword() != null); } } // disable some form elements if we don't want the user changing them - they should have been filled in by who ever created this view if (this.showUninstallButton || this.showStartButton || this.showStopButton) { host.setDisabled(true); port.setDisabled(true); agentInstallPath.setDisabled(true); findAgentInstallPathButton.setDisabled(true); } if (this.showUninstallButton) { // don't show rememberMe checkbox - we're getting rid of this agent so there won't be a record to store the creds connectionForm.setFields(host, port, username, password, agentInstallPath, findAgentInstallPathButton, agentStatusText, statusCheckButton); } else { connectionForm.setFields(host, port, username, password, rememberMeCheckbox, agentInstallPath, findAgentInstallPathButton, agentStatusText, statusCheckButton); } return connectionForm; } private void createAgentStatusTextItem() { agentStatusText = new StaticTextItem("agentStatus", MSG.view_remoteAgentInstall_agentStatus()); agentStatusText.setDefaultValue(MSG.view_remoteAgentInstall_agentStatusDefault()); agentStatusText.setRedrawOnChange(true); agentStatusText.setStartRow(true); agentStatusText.setEndRow(false); } private Layout getButtons() { buttonsForm = new HLayout(); installButton = new EnhancedIButton(MSG.view_remoteAgentInstall_installAgent()); installButton.setExtraSpace(10); installButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { absPathValidator.setPerformCheck(true); try { if (connectionForm.validate()) { new CheckSSHConnectionCallback() { @Override protected void doActualWork() { installAgent(); } }.execute(); } } finally { absPathValidator.setPerformCheck(false); } } }); uninstallButton = new EnhancedIButton(MSG.view_remoteAgentInstall_uninstallAgent()); uninstallButton.setExtraSpace(10); uninstallButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { absPathValidator.setPerformCheck(true); try { if (connectionForm.validate()) { new CheckSSHConnectionCallback() { @Override protected void doActualWork() { uninstallAgent(); } }.execute(); } } finally { absPathValidator.setPerformCheck(false); } } }); startButton = new EnhancedIButton(MSG.common_label_startAgent()); startButton.setExtraSpace(10); startButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { if (connectionForm.validate()) { new CheckSSHConnectionCallback() { @Override protected void doActualWork() { startAgent(); } }.execute(); } } }); stopButton = new EnhancedIButton(MSG.view_remoteAgentInstall_stopAgent()); stopButton.setExtraSpace(10); stopButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent clickEvent) { if (connectionForm.validate()) { new CheckSSHConnectionCallback() { @Override protected void doActualWork() { stopAgent(); } }.execute(); } } }); ArrayList<Canvas> buttons = new ArrayList<Canvas>(3); if (this.showInstallButton) { buttons.add(installButton); } if (this.showUninstallButton && initialAgentInstall != null && initialAgentInstall.getAgentName() != null) { buttons.add(uninstallButton); // note we only show this if we were given the agent name because that is required to be known to uninstall } if (this.showStartButton) { buttons.add(startButton); } if (this.showStopButton) { buttons.add(stopButton); } if (buttons.size() > 0) { buttonsForm.setAlign(Alignment.CENTER); buttonsForm.setMembers(buttons.toArray(new Canvas[buttons.size()])); } return buttonsForm; } /** * Call this method when we know all processing (including all async calls) are done * and we are ready for the user to interact with the page again. */ private void doneProcessing() { disableButtons(false); hostAuthorized = false; // if the ssh fingerprint changes under us this forces the user to re-authorize again dialog.markForDestroy(); } private void displayError(String msg) { displayError(msg, null); } private void displayError(String msg, Throwable caught) { CoreGUI.getErrorHandler().handleError(msg, caught); String rootCause = ErrorHandler.getRootCauseMessage(caught); // JSch returns very bad error messages, transform them here before returning to the customer String fullMsg = null; if(rootCause != null && msg != null) { String runtimeException = "java.lang.RuntimeException"; if("com.jcraft.jsch.JSchException:Auth cancel".equals(rootCause)) { fullMsg = MSG.view_remoteAgentInstall_error_authFailed(); } else if(rootCause.indexOf("java.net.UnknownHostException") != -1) { fullMsg = MSG.view_remoteAgentInstall_error_unknownHost(); } else if("java.net.ConnectException:Connection refused".equals(rootCause)) { fullMsg = MSG.view_remoteAgentInstall_error_connRefused(); } else if(rootCause.indexOf(runtimeException) != -1) { int exceptionEnd = rootCause.indexOf(runtimeException) + runtimeException.length() + 1; // remove : also fullMsg = rootCause.substring(exceptionEnd); } } // Fallback if(fullMsg == null) { fullMsg = (rootCause == null) ? msg : msg + ": " + rootCause; } SC.warn(fullMsg); } private void displayMessage(String msg) { CoreGUI.getMessageCenter().notify( new Message(msg, Message.Severity.Info, EnumSet.of(Message.Option.BackgroundJobResult))); } private void setAgentStatusText(String msg) { if (agentStatusText != null) { agentStatusText.setValue(msg); } } private FileUploadForm createAgentConfigXmlUploadForm() { final FileUploadForm uploadForm = new FileUploadForm("agent-configuration.xml", "1", false, true, null, true); uploadForm.setCustomTooltipMessage(MSG.view_remoteAgentInstall_promptAgentConfigXml()); uploadForm.setAutoWidth(); uploadForm.setPadding(5); uploadForm.setIsGroup(true); uploadForm.setGroupTitle("agent-configuration.xml"); uploadForm.addFormHandler(new DynamicFormHandler() { @Override public void onSubmitComplete(DynamicFormSubmitCompleteEvent event) { List<String> paths = uploadForm.getUploadedFilePaths(); if (paths != null && paths.size() == 1) { agentConfigurationXml = paths.get(0); } else { agentConfigurationXml = null; } } }); return uploadForm; } private FileUploadForm createAgentEnvUploadForm() { final FileUploadForm uploadForm = new FileUploadForm("rhq-agent-env.sh", "1", false, true, null, true); uploadForm.setCustomTooltipMessage(MSG.view_remoteAgentInstall_promptRhqAgentEnv()); uploadForm.setAutoWidth(); uploadForm.setPadding(5); uploadForm.setIsGroup(true); uploadForm.setGroupTitle("rhq-agent-env.sh"); uploadForm.addFormHandler(new DynamicFormHandler() { @Override public void onSubmitComplete(DynamicFormSubmitCompleteEvent event) { List<String> paths = uploadForm.getUploadedFilePaths(); if (paths != null && paths.size() == 1) { rhqAgentEnvSh = paths.get(0); } else { rhqAgentEnvSh = null; } } }); return uploadForm; } private void findAgentInstallPath() { disableButtons(true); final String parentPath = getAgentInstallPath(); createWaitingWindow(MSG.view_remoteAgentInstall_findAgentWait(), true); remoteInstallService.findAgentInstallPath(getRemoteAccessInfo(), parentPath, new AsyncCallback<String>() { public void onFailure(Throwable caught) { displayError(MSG.view_remoteAgentInstall_error_1(), caught); doneProcessing(); } public void onSuccess(String result) { if (result != null) { agentInstallPath.setValue(result); agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't do it here } else { String err; if (parentPath == null || parentPath.length() == 0) { err = MSG.view_remoteAgentInstall_error_2(); } else { err = MSG.view_remoteAgentInstall_error_3(parentPath); } displayError(err, null); setAgentStatusText(MSG.view_remoteAgentInstall_agentStatusDefault()); doneProcessing(); } } }); } private void agentStatusCheck() { disableButtons(true); remoteInstallService.agentStatus(getRemoteAccessInfo(), getAgentInstallPath(), new AsyncCallback<String>() { public void onFailure(Throwable caught) { setAgentStatusText(caught.getMessage()); doneProcessing(); } public void onSuccess(String result) { setAgentStatusText(result); doneProcessing(); } }); } private void createWaitingWindow(String text, boolean show) { dialog = new Dialog(); dialog.setMessage(text); dialog.setIcon("[SKIN]notify.png"); dialog.draw(); dialog.setTitle(MSG.view_remoteAgentInstall_dialogTitle()); dialog.setShowCloseButton(false); } private void installAgent() { disableButtons(true); // FOR TESTING WITHOUT DOING A REAL INSTALL - START // AgentInstallInfo result = new AgentInstallInfo("mypath", "myown", "1.1", "localHOST", "serverHOST"); // for (int i = 1; i < 20; i++) // result.addStep(new AgentInstallStep("cmd" + i, "desc" + i, i, "result" + i, i * 10)); // for (Canvas child : agentInfoLayout.getChildren()) // child.destroy(); // buildInstallInfoCanvas(agentInfoLayout, result); // agentInfoLayout.markForRedraw(); // disableButtons(false); // if (true) // return; // FOR TESTING WITHOUT DOING A REAL INSTALL - END // help out the user here - if they selected file(s) but didn't upload them yet, press the upload button(s) for him // Note that if the user didn't upload yet, we have to wait for it to complete and ask the user to press install again boolean needToWaitForUpload = false; if (agentConfigXmlUploadForm != null && agentConfigXmlUploadForm.isFileSelected() && agentConfigurationXml == null) { if (!agentConfigXmlUploadForm.isUploadInProgress()) { agentConfigXmlUploadForm.submitForm(); } needToWaitForUpload = true; } if (rhqAgentEnvUploadForm != null && rhqAgentEnvUploadForm.isFileSelected() && rhqAgentEnvSh == null) { if (!rhqAgentEnvUploadForm.isUploadInProgress()) { rhqAgentEnvUploadForm.submitForm(); } needToWaitForUpload = true; } if (!needToWaitForUpload) { reallyInstallAgent(); return; } createWaitingWindow(MSG.view_remoteAgentInstall_waitForUpload(), true); Scheduler.get().scheduleEntry(new RepeatingCommand() { @Override public boolean execute() { // Make sure the file upload(s) (if there are any) have completed before we do anything boolean waitForUploadToFinish = false; if (agentConfigXmlUploadForm != null && agentConfigXmlUploadForm.isUploadInProgress()) { waitForUploadToFinish = true; } if (rhqAgentEnvUploadForm != null && rhqAgentEnvUploadForm.isUploadInProgress()) { waitForUploadToFinish = true; } if (waitForUploadToFinish) { return true; // keep waiting, call us back later } dialog.destroy(); reallyInstallAgent(); return false; // upload is done, we can stop calling ourselves } }); } private void reallyInstallAgent() { disableButtons(true); setAgentStatusText(MSG.view_remoteAgentInstall_installingPleaseWait()); createWaitingWindow(MSG.view_remoteAgentInstall_installingPleaseWait(), true); SC.ask(MSG.view_remoteAgentInstall_overwriteAgentTitle(), MSG.view_remoteAgentInstall_overwriteAgentQuestion(), new BooleanCallback() { @Override public void execute(Boolean overwriteExistingAgent) { CustomAgentInstallData customData = new CustomAgentInstallData(getAgentInstallPath(), overwriteExistingAgent.booleanValue(), agentConfigurationXml); //, rhqAgentEnvSh); remoteInstallService.installAgent(getRemoteAccessInfo(), customData, new AsyncCallback<AgentInstallInfo>() { public void onFailure(Throwable caught) { displayError(MSG.view_remoteAgentInstall_error_4(), caught); setAgentStatusText(MSG.view_remoteAgentInstall_error_4()); if (agentConfigXmlUploadForm != null) { agentConfigXmlUploadForm.reset(); } if (rhqAgentEnvUploadForm != null) { rhqAgentEnvUploadForm.reset(); } doneProcessing(); } public void onSuccess(AgentInstallInfo result) { // if the install button isn't created, user must have navigated away, so skip the UI stuff if (installButton.isCreated()) { installButton.setDisabled(true); // don't re-enable install - install was successful, no need to do it again displayMessage(MSG.view_remoteAgentInstall_success()); setAgentStatusText(MSG.view_remoteAgentInstall_success()); if (!result.isConfirmedAgentConnection()) { displayError(MSG.view_remoteAgentInstall_error_cannotPingAgent( result.getAgentAddress(), String.valueOf(result.getAgentPort()))); } buildInstallInfoCanvas(result); agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't do it here } // tell the success handler invokeSuccessHandler(Type.INSTALL); } }); } }); } private void uninstallAgent() { disableButtons(true); createWaitingWindow(MSG.view_remoteAgentInstall_uninstallingPleaseWait(), true); remoteInstallService.uninstallAgent(getRemoteAccessInfo(), getAgentInstallPath(), new AsyncCallback<String>() { public void onFailure(Throwable caught) { displayError(MSG.view_remoteAgentInstall_error_7(), caught); setAgentStatusText(MSG.view_remoteAgentInstall_error_7()); doneProcessing(); } public void onSuccess(String result) { if (result != null) { setAgentStatusText(MSG.view_remoteAgentInstall_uninstallSuccess()); displayMessage(MSG.view_remoteAgentInstall_uninstallAgentResults(result)); agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't do it here // tell the success handler invokeSuccessHandler(Type.UNINSTALL); } else { setAgentStatusText(MSG.view_remoteAgentInstall_error_7()); doneProcessing(); } } }); } private void startAgent() { disableButtons(true); createWaitingWindow(MSG.view_remoteAgentInstall_startAgentPleaseWait(), true); remoteInstallService.startAgent(getRemoteAccessInfo(), getAgentInstallPath(), new AsyncCallback<String>() { public void onFailure(Throwable caught) { displayError(MSG.view_remoteAgentInstall_error_5(), caught); doneProcessing(); } public void onSuccess(String result) { displayMessage(MSG.view_remoteAgentInstall_startAgentResults(result)); agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't do it here // tell the success handler invokeSuccessHandler(Type.START); } }); } private void stopAgent() { disableButtons(true); createWaitingWindow(MSG.view_remoteAgentInstall_stopAgentPleaseWait(), true); remoteInstallService.stopAgent(getRemoteAccessInfo(), getAgentInstallPath(), new AsyncCallback<String>() { public void onFailure(Throwable caught) { displayError(MSG.view_remoteAgentInstall_error_6(), caught); doneProcessing(); } public void onSuccess(String result) { displayMessage(MSG.view_remoteAgentInstall_stopAgentResults(result)); agentStatusCheck(); // we are relying on this to call doneProcessing(), we shouldn't do it here // tell the success handler invokeSuccessHandler(Type.STOP); } }); } private void buildInstallInfoCanvas(AgentInstallInfo info) { DynamicForm infoForm = new DynamicForm(); infoForm.setMargin(20); infoForm.setWidth100(); infoForm.setHeight100(); HeaderItem infoHeader = new HeaderItem(); infoHeader.setValue(MSG.view_remoteAgentInstall_installInfo()); StaticTextItem version = new StaticTextItem("version", MSG.common_title_version()); version.setValue(info.getVersion()); StaticTextItem path = new StaticTextItem("path", MSG.common_title_path()); path.setValue(info.getPath()); StaticTextItem owner = new StaticTextItem("owner", MSG.common_title_owner()); owner.setValue(info.getOwner()); StaticTextItem config = new StaticTextItem("config", MSG.common_title_configuration()); config.setValue(info.getConfigurationStartString()); CanvasItem listCanvas = new CanvasItem(); listCanvas.setShowTitle(false); listCanvas.setColSpan(2); VLayout listLayout = new VLayout(0); listLayout.setWidth100(); listLayout.setHeight100(); ListGrid listGrid = new ListGrid() { @Override protected Canvas getExpansionComponent(ListGridRecord record) { Canvas canvas = super.getExpansionComponent(record); canvas.setPadding(5); return canvas; } }; listGrid.setWidth100(); listGrid.setHeight100(); listGrid.setCanExpandRecords(true); listGrid.setExpansionMode(ExpansionMode.DETAIL_FIELD); listGrid.setDetailField("result"); ListGridField step = new ListGridField("description", MSG.view_remoteAgentInstall_step()); ListGridField result = new ListGridField("result", MSG.view_remoteAgentInstall_result()); ListGridField resultCode = new ListGridField("resultCode", MSG.view_remoteAgentInstall_resultCode(), 90); ListGridField duration = new ListGridField("duration", MSG.common_title_duration(), 90); listGrid.setFields(step, result, resultCode, duration); listGrid.setData(getStepRecords(info)); listGrid.setAutoFitData(Autofit.BOTH); listGrid.setLeaveScrollbarGap(false); listGrid.setShowAllRecords(true); listGrid.setBodyOverflow(Overflow.CLIP_H); listGrid.setOverflow(Overflow.SCROLL); listLayout.setLeaveScrollbarGap(true); listLayout.addMember(listGrid); listCanvas.setCanvas(listLayout); listCanvas.setOverflow(Overflow.AUTO); listLayout.setOverflow(Overflow.AUTO); // Replace the current info with just the install steps for (Canvas canvas : this.getChildren()) { canvas.markForDestroy(); } createAgentStatusTextItem(); infoForm.setFields(infoHeader, version, path, owner, config, agentStatusText, listCanvas); addMember(infoForm); this.setMembersMargin(1); this.markForRedraw(); } private ListGridRecord[] getStepRecords(AgentInstallInfo info) { ArrayList<ListGridRecord> steps = new ArrayList<ListGridRecord>(); for (AgentInstallStep step : info.getSteps()) { ListGridRecord rec = new ListGridRecord(); rec.setAttribute("description", step.getDescription()); String result = step.getResult(); if (result == null || result.trim().length() == 0) { result = MSG.view_remoteAgentInstall_resultCode() + "=" + step.getResultCode(); } rec.setAttribute("result", result); rec.setAttribute("resultCode", "" + step.getResultCode()); rec.setAttribute("duration", MeasurementConverterClient.format((double) step.getDuration(), MeasurementUnits.MILLISECONDS, true)); steps.add(rec); } return steps.toArray(new ListGridRecord[steps.size()]); } private void disableCanvas(Canvas obj, boolean disabled) { if (obj.isCreated()) { obj.setDisabled(disabled); } } private void disableCanvasItem(CanvasItem obj, boolean disabled) { if (obj.isDrawn()) { obj.setDisabled(disabled); } } private void disableButtons(boolean disabled) { disableCanvas(installButton, disabled); disableCanvas(uninstallButton, disabled); disableCanvas(startButton, disabled); disableCanvas(stopButton, disabled); disableCanvas(buttonsForm, disabled); disableCanvasItem(statusCheckButton, disabled); // we only want to mess with this if we are in "install" mode if (showInstallButton) { disableCanvasItem(findAgentInstallPathButton, disabled); } } private RemoteAccessInfo getRemoteAccessInfo() { String host = connectionForm.getValueAsString("host"); String port = connectionForm.getValueAsString("port"); String username = connectionForm.getValueAsString("username"); String password = connectionForm.getValueAsString("password"); int portInt; try { portInt = Integer.parseInt(port); } catch (NumberFormatException e) { portInt = 22; } connectionForm.setValue("port", portInt); RemoteAccessInfo info = new RemoteAccessInfo(host, portInt, username, password); if (this.initialAgentInstall != null) { info.setAgentName(this.initialAgentInstall.getAgentName()); } boolean rememberme = Boolean.parseBoolean(connectionForm.getValueAsString("rememberme")); info.setRememberMe(rememberme); info.setHostAuthorized(hostAuthorized); return info; } private String getAgentInstallPath() { return agentInstallPath.getValueAsString(); } private class AbsolutePathValidator extends CustomValidator { private boolean performCheck = false; public AbsolutePathValidator() { setErrorMessage(MSG.view_remoteAgentInstall_error_needAbsPath()); } public void setPerformCheck(boolean b) { this.performCheck = b; } public boolean condition(Object value) { return (this.performCheck == false) || ((value != null) && (value.toString().startsWith("/"))); } } // all our remote SSH work should be wrapped in this callback so we can check the SSH // connection first. This provides a way to notify the user if the host key fingerprint // is unknown or has changed. private abstract class CheckSSHConnectionCallback implements AsyncCallback<Void> { protected abstract void doActualWork(); public void execute() { disableButtons(true); remoteInstallService.checkSSHConnection(getRemoteAccessInfo(), this); } @Override public void onSuccess(Void result) { disableButtons(false); doActualWork(); } @Override public void onFailure(Throwable caught) { disableButtons(false); // if this failure was because the SSH connection wanted to ask a security question // (one of two things - either the host fingerprint is not known and we should add it // or the host fingerprint has changed and we should change it), then ask the question // (which jsch has provided us and we put in the SSHSecurityException) and if the user // answers "yes" then do the work as we originally were asked to do. if (caught instanceof SSHSecurityException) { SC.ask(caught.getMessage(), new BooleanCallback() { @Override public void execute(Boolean value) { if (value != null && value.booleanValue()) { hostAuthorized = true; // the user has just authorized the host doActualWork(); } } }); } else { displayError(MSG.view_remoteAgentInstall_error_connError(), caught); } } } /** * Allows one success handler to be added to this view. When anything is done that is a success, * this handler will be called. If you set this to null, any previous success handler will be removed. * * @param successHandler the handler to call when this view does anything successful. */ public void setSuccessHandler(SuccessHandler successHandler) { this.successHandler = successHandler; } private void invokeSuccessHandler(Type type) { if (this.successHandler != null) { try { this.successHandler.onSuccess(type); } catch (Exception e) { displayError("success handler failed", e); } } } public interface SuccessHandler { void onSuccess(Type type); } }