All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.roboconf.plugin.script.internal.PluginScript Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2013-2017 Linagora, Université Joseph Fourier, Floralis
 *
 * The present code is developed in the scope of the joint LINAGORA -
 * Université Joseph Fourier - Floralis research program and is designated
 * as a "Result" pursuant to the terms and conditions of the LINAGORA
 * - Université Joseph Fourier - Floralis research program. Each copyright
 * holder of Results enumerated here above fully & independently holds complete
 * ownership of the complete Intellectual Property rights applicable to the whole
 * of said Results, and may freely exploit it in any manner which does not infringe
 * the moral rights of the other copyright holders.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.roboconf.plugin.script.internal;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;

import net.roboconf.core.model.beans.Import;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.beans.Instance.InstanceStatus;
import net.roboconf.core.model.helpers.InstanceHelpers;
import net.roboconf.core.model.helpers.VariableHelpers;
import net.roboconf.core.utils.DockerAndScriptUtils;
import net.roboconf.core.utils.ProgramUtils;
import net.roboconf.core.utils.Utils;
import net.roboconf.plugin.api.PluginException;
import net.roboconf.plugin.api.PluginInterface;
import net.roboconf.plugin.script.internal.ScriptUtils.ActionFileFilter;
import net.roboconf.plugin.script.internal.templating.InstanceTemplateHelper;

/**
 * The plug-in invokes a script (eg. shell) on every life cycle change.
 * 

* The action is one of "deploy", "start", "stop", "undeploy" and "update".
* Let's take an example with the "start" action to understand the way this plug-in works. *

*
    *
  • The plug-in will load scripts/start.sh
  • *
  • If it is not found, it will try to load templates/start.sh.template
  • *
  • If it is not found, it will try to load templates/default.sh.template
  • *
  • If it is not found, the plug-in will do nothing
  • *
*

* The default template is used to factorize actions. *

* * @author Noël - LIG * @author Linh-Manh Pham - LIG * @author Pierre-Yves Gibello - Linagora * @author Christophe Hamerling - Linagora */ public class PluginScript implements PluginInterface { public static final String PLUGIN_NAME = "script"; private static final String SCRIPTS_FOLDER_NAME = "scripts"; private static final String TEMPLATES_FOLDER_NAME = "roboconf-templates"; private static final String FILES_FOLDER_NAME = "files"; private final Logger logger = Logger.getLogger( getClass().getName()); String agentId; String applicationName, scopedInstancePath; @Override public String getPluginName() { return PLUGIN_NAME; } @Override public void setNames( String applicationName, String scopedInstancePath ) { this.applicationName = applicationName; this.scopedInstancePath = scopedInstancePath; this.agentId = "'" + scopedInstancePath + "' agent"; } @Override public void initialize( Instance instance ) throws PluginException { this.logger.fine(this.agentId + ": initializing the plugin for " + instance); // All scripts deployed should be made executable (the agent is supposed to run as root) File instanceDirectory = InstanceHelpers.findInstanceDirectoryOnAgent( instance ); ScriptUtils.setScriptsExecutable( new File( instanceDirectory, SCRIPTS_FOLDER_NAME )); } @Override public void deploy( Instance instance ) throws PluginException { this.logger.fine( this.agentId + " is deploying instance " + instance ); try { prepareAndExecuteCommand( "deploy", instance, null, null ); } catch( Exception e ) { throw new PluginException( e ); } } @Override public void start( Instance instance ) throws PluginException { this.logger.fine( this.agentId + " is starting instance " + instance ); try { prepareAndExecuteCommand( "start", instance, null, null ); } catch( Exception e ) { throw new PluginException( e ); } } @Override public void update(Instance instance, Import importChanged, InstanceStatus statusChanged) throws PluginException { this.logger.fine( this.agentId + " is updating instance " + instance ); try { prepareAndExecuteCommand( "update", instance, importChanged, statusChanged ); } catch( Exception e ) { throw new PluginException( e ); } } @Override public void stop( Instance instance ) throws PluginException { this.logger.fine( this.agentId + " is stopping instance " + instance ); try { prepareAndExecuteCommand( "stop", instance, null, null ); } catch( Exception e ) { throw new PluginException( e ); } } @Override public void undeploy( Instance instance ) throws PluginException { this.logger.fine( this.agentId + " is undeploying instance " + instance ); try { prepareAndExecuteCommand( "undeploy", instance, null, null ); } catch( Exception e ) { throw new PluginException( e ); } } private void prepareAndExecuteCommand(String action, Instance instance, Import importChanged, InstanceStatus statusChanged) throws IOException, InterruptedException { this.logger.info("Preparing the invocation of " + action + " script for instance " + instance ); File instanceDirectory = InstanceHelpers.findInstanceDirectoryOnAgent( instance ); File scriptsFolder = new File(instanceDirectory, SCRIPTS_FOLDER_NAME); File templatesFolder = new File(instanceDirectory, TEMPLATES_FOLDER_NAME); // Look for action script (default .sh, or any file that starts with ) File script = new File(scriptsFolder, action + ".sh"); if(! script.exists()) { File[] foundFiles = scriptsFolder.listFiles(new ActionFileFilter(action)); if(foundFiles != null && foundFiles.length > 0) { script = foundFiles[0]; if(foundFiles.length > 1) this.logger.warning("More than one " + action + " script found: taking the 1st one, " + script.getName()); } } File template = new File(templatesFolder, action + ".template"); if( ! template.exists()) template = new File(templatesFolder, "default.template"); if (script.exists()) { executeScript(script, instance, importChanged, statusChanged, instanceDirectory.getAbsolutePath()); } else if (template.exists()) { File generated = generateTemplate(template, instance); executeScript(generated, instance, importChanged, statusChanged, instanceDirectory.getAbsolutePath()); Utils.deleteFilesRecursively( generated ); } else { this.logger.warning("Can not find a script or a template for action " + action); } } /** * Generates a file from the template and the instance. * @param template * @param instance * @return the generated file * @throws IOException */ protected File generateTemplate(File template, Instance instance) throws IOException { String scriptName = instance.getName().replace( "\\s+", "_" ); File generated = File.createTempFile( scriptName, ".script"); InstanceTemplateHelper.injectInstanceImports(instance, template, generated); return generated; } protected void executeScript( File script, Instance instance, Import importChanged, InstanceStatus statusChanged, String instanceDir ) throws IOException, InterruptedException { String[] command = { script.getAbsolutePath() }; if(! script.canExecute()) script.setExecutable(true); Map environmentVars = new HashMap(); Map vars = ScriptUtils.formatExportedVars(instance); environmentVars.putAll(vars); Map importedVars = ScriptUtils.formatImportedVars( instance ); environmentVars.putAll( DockerAndScriptUtils.buildReferenceMap( instance )); environmentVars.putAll( importedVars ); environmentVars.put("ROBOCONF_FILES_DIR", new File( instanceDir, FILES_FOLDER_NAME ).getAbsolutePath()); // Upon update, retrieve the status of the instance that triggered the update. // Should be either DEPLOYED_STARTED or DEPLOYED_STOPPED... if( statusChanged != null ) environmentVars.put("ROBOCONF_UPDATE_STATUS", statusChanged.toString()); // Upon update, retrieve the import that changed // (removed when an instance stopped, or added when it started) if( importChanged != null ) { environmentVars.put("ROBOCONF_IMPORT_CHANGED_INSTANCE_PATH", importChanged.getInstancePath()); environmentVars.put("ROBOCONF_IMPORT_CHANGED_COMPONENT", importChanged.getComponentName()); for (Entry entry : importChanged.getExportedVars().entrySet()) { // "ROBOCONF_IMPORT_CHANGED_ip=127.0.0.1" String vname = VariableHelpers.parseVariableName(entry.getKey()).getValue(); importedVars.put("ROBOCONF_IMPORT_CHANGED_" + vname, entry.getValue()); } } int exitCode = ProgramUtils.executeCommand( this.logger, command, script.getParentFile(), environmentVars, this.applicationName, this.scopedInstancePath ); if( exitCode != 0 ) throw new IOException( "Script execution failed. Exit code: " + exitCode ); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy