/** * Copyright (c) 2013 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package com.redhat.rhn.frontend.action.systems; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import org.apache.struts.action.DynaActionForm; import com.redhat.rhn.common.localization.LocalizationService; import com.redhat.rhn.common.util.DatePicker; import com.redhat.rhn.common.util.StringUtil; import com.redhat.rhn.common.util.StringUtil.ScriptCheckResult; import com.redhat.rhn.domain.action.Action; import com.redhat.rhn.domain.action.ActionChain; import com.redhat.rhn.domain.server.Server; import com.redhat.rhn.domain.user.User; import com.redhat.rhn.frontend.struts.ActionChainHelper; import com.redhat.rhn.frontend.struts.RequestContext; import com.redhat.rhn.frontend.struts.RhnAction; import com.redhat.rhn.frontend.struts.RhnHelper; import com.redhat.rhn.manager.action.ActionChainManager; import com.redhat.rhn.manager.action.ActionManager; import com.redhat.rhn.manager.system.SystemManager; /** * Action for the single system remote command scheduling. * * @author Bo Maryniuk <bo@suse.de> */ public class SystemRemoteCommandAction extends RhnAction { /** * Class to retention form data. */ public static final class FormData { public static final String UID = "uid"; public static final String GID = "gid"; public static final String SCRIPT = "script_body"; public static final String LABEL = "lbl"; public static final String TIMEOUT = "timeout"; public static final Long DEFAULT_TIMEOUT = 600L; public static final Long MAX_TIMEOUT = new Long(Integer.MAX_VALUE); public static final String[] MANDATORY_FIELDS = { FormData.UID, FormData.GID, FormData.SCRIPT, }; private String uid; private String gid; private String scriptBody; private String label; private Long timeout; /** * Default constructor. */ public FormData() { this.uid = "root"; this.gid = "root"; this.timeout = FormData.DEFAULT_TIMEOUT; this.label = ""; this.scriptBody = "#!/bin/sh\n# Add your shell script below\n"; } /** * Get UID * @return the uid */ public String getUid() { return uid; } /** * Set UID * @param userid the uid to set * @return Form data object. */ public FormData setUid(String userid) { this.uid = userid; return this; } /** * Get GID * @return the gid */ public String getGid() { return gid; } /** * Set GID * @param groupid the gid to set * @return Form data object. */ public FormData setGid(String groupid) { this.gid = groupid; return this; } /** * Get script content. * @return the scriptBody */ public String getScriptBody() { return scriptBody; } /** * Set script content. * @param script the content of the script to set * @return Form data object. */ public FormData setScriptBody(String script) { this.scriptBody = script; return this; } /** * Get label * @return the label */ public String getLabel() { return label; } /** * Set label * @param commandLabel the label to set * @return Form data object. */ public FormData setLabel(String commandLabel) { this.label = commandLabel; return this; } /** * Get timeout * @return the timeout */ public Long getTimeout() { return timeout; } /** * Set timeout * @param commandTimeout the timeout to set * @return Form data object. */ public FormData setTimeout(Long commandTimeout) { this.timeout = commandTimeout; return this; } } /** * Validate form has required fields. * * @param form * @param errorMessages * @return */ private boolean validate(DynaActionForm form, ActionErrors errorMessages) { boolean formValid = true; for (String fid : SystemRemoteCommandAction.FormData.MANDATORY_FIELDS) { if (StringUtil.nullOrValue(form.getString(fid)) == null) { if (formValid) { formValid = false; } errorMessages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(String.format( "ssm.operations.provisioning." + "remotecommand.form.%s.missing", fid))); } } // Check if Script looks legit :-) if (StringUtil.nullOrValue(form.getString(FormData.SCRIPT)) != null) { ScriptCheckResult checkResult = StringUtil.scriptPrematureCheck( form.getString(FormData.SCRIPT)); if (checkResult != null) { formValid = false; errorMessages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(checkResult.getMessageKey())); } } // Check if timeout exceeds the XMLRPC integer type max if ((Long) form.get(FormData.TIMEOUT) > FormData.MAX_TIMEOUT) { formValid = false; errorMessages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(String.format( "ssm.operations.provisioning.remotecommand." + "form.timeout.max"))); } return formValid; } /** * Schedule remote action script. * * @param form * @param user * @param server * @return Script action details. */ private Set<Action> scheduleScript(DynaActionForm form, User user, Server server) { Date scheduleDate = getStrutsDelegate().readDatePicker( form, "date", DatePicker.YEAR_RANGE_POSITIVE); ActionChain actionChain = ActionChainHelper.readActionChain(form, user); List<Long> servers = new ArrayList<Long>(); servers.add(server.getId()); String label = StringUtil.nullIfEmpty(form.getString("lbl")); String msg = LocalizationService .getInstance() .getMessage("ssm.overview.provisioning.remotecommand.staticname"); return ActionChainManager.scheduleScriptRuns( user, servers, (label != null ? label : MessageFormat.format(msg, server.getName())), ActionManager.createScript(form.getString(FormData.UID), form.getString(FormData.GID), form.get(FormData.TIMEOUT) == null ? FormData.DEFAULT_TIMEOUT : (Long) form.get(FormData.TIMEOUT), form.getString(FormData.SCRIPT)), scheduleDate, actionChain); } /** * Get form into the bean. * * @param form * @return FormData object. */ private FormData getFormData(DynaActionForm form) { FormData data = new FormData(); data.setUid(form.getString(FormData.UID)); data.setGid(form.getString(FormData.GID)); data.setLabel(form.getString(FormData.LABEL)); data.setScriptBody(form.getString(FormData.SCRIPT)); data.setTimeout((Long) form.get(FormData.TIMEOUT)); return data; } /** * {@inheritDoc} */ public ActionForward execute(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { // Prepare DynaActionForm form = (DynaActionForm) actionForm; RequestContext context = new RequestContext(request); User user = context.getCurrentUser(); Server server = SystemManager.lookupByIdAndUser( context.getRequiredParam(RequestContext.SID), user); ActionErrors errorMessages = new ActionErrors(); ActionMessages infoMessages = new ActionMessages(); // Default form values request.setAttribute("formData", new SystemRemoteCommandAction.FormData()); // Are we set up to allow remote-commands on SID? request.setAttribute("has_script_run", SystemManager.clientCapable(server.getId(), "script.run")); // Process submit if (form.get(RhnAction.SUBMITTED) != null) { if (this.validate(form, errorMessages)) { Set<Action> actions = this.scheduleScript(form, user, server); ActionChain actionChain = ActionChainHelper.readActionChain(form, user); if (actionChain == null) { Action action = actions.iterator().next(); infoMessages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("ssm.overview.provisioning" + ".remotecommand.succeed", server.getId().toString(), action.getId().toString(), LocalizationService .getInstance().formatDate(action.getEarliestAction()))); } else { infoMessages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("message.addedtoactionchain", actionChain.getId(), actionChain.getLabel())); } } else { request.setAttribute("formData", this.getFormData(form)); } } // End the page request.setAttribute("date", this.getStrutsDelegate().prepopulateDatePicker( request, form, "date", DatePicker.YEAR_RANGE_POSITIVE)); ActionChainHelper.prepopulateActionChains(request); request.setAttribute("system", server); this.getStrutsDelegate().saveMessages(request, errorMessages); this.getStrutsDelegate().saveMessages(request, infoMessages); form.getMap().clear(); return getStrutsDelegate().forwardParam( mapping.findForward(RhnHelper.DEFAULT_FORWARD), RequestContext.SID, server.getId().toString() ); } }