jenkins cli with checkout Subversion using groovy script - jenkins

Is there a way to check out any Subversion project using Jenkins-Cli by executing a groovy script on the master? I can get to the point of creating SVN client manager[org.tmatesoft.svn.core.wc.SVNClientManager], but can't really understand how to employ that in checking out an SVN project from the URL.

After a lot of hit and trials I have come up with this, might be useful for someone else:
import jenkins.*;
import jenkins.model.*;
import hudson.*;
import hudson.model.*;
import hudson.slaves.SlaveComputer;
import hudson.scm.SubversionSCM;
import hudson.remoting.Channel;
import hudson.FilePath;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider;
import org.tmatesoft.svn.core.wc.SVNLogClient;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.ISVNDirEntryHandler;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import java.lang.*;
import java.util.ArrayList;
import java.util.List;
private boolean checkNodeExist(String node_Name){
if (Jenkins.getInstance().slaves.find({it.name == node_Name}) == null)
return false;
else
return true;
}
private ISVNAuthenticationProvider createAuthenticationProvider(AbstractProject context) {
return Jenkins.getInstance().getDescriptorByType(SubversionSCM.DescriptorImpl.class)
.createAuthenticationProvider(context);
}
public class SimpleSVNDirEntryHandler implements ISVNDirEntryHandler {
private final List<SVNDirEntry> dirs = new ArrayList<SVNDirEntry>();
public List<String> getDirs() {
List<String> sortedDirs = new ArrayList<String>();
for (SVNDirEntry dirEntry : dirs) {
sortedDirs.add(dirEntry.getName());
}
return sortedDirs;
}
public void handleDirEntry(SVNDirEntry dirEntry) throws SVNException {
dirs.add(dirEntry);
}
}
public void PerfromSVNListOperationOnMaster(SVNURL svnUrl){
try{
SVNRepository repo = SVNRepositoryFactory.create(svnUrl);
SVNClientManager clientManager = SubversionSCM.createSvnClientManager(createAuthenticationProvider())
SVNLogClient logClient = clientManager.getLogClient();
SimpleSVNDirEntryHandler dirEntryHandler = new SimpleSVNDirEntryHandler();
List<String> dirs = new ArrayList<String>();
logClient.doList(repo.getLocation(),SVNRevision.HEAD, SVNRevision.HEAD,false,SVNDepth.INFINITY,SVNDirEntry.DIRENT_KIND,dirEntryHandler)
dirs = dirEntryHandler.getDirs();
println (dirs)
}
catch(SVNException svnEx){
println "#Error: " + svnEx;
throw svnEx
}
}
public void PerfromSVNCheckOutOperation(SVNURL svnUrl,boolean isMaster,String appender,SlaveComputer computer = null){
try{
SVNRepository repo = SVNRepositoryFactory.create(svnUrl);
SVNClientManager clientManager = SubversionSCM.createSvnClientManager(createAuthenticationProvider());
SVNUpdateClient updateClient = clientManager.getUpdateClient();
updateClient.setIgnoreExternals(false);
String destDir = svnUrl.getPath().substring(svnUrl.getPath().lastIndexOf('/')+1);
if (isMaster == true){
updateClient.doCheckout(repo.getLocation(),new java.io.File(System.getProperty("java.io.tmpdir"),destDir + '_' + appender),SVNRevision.HEAD,SVNRevision.HEAD,SVNDepth.INFINITY,false);
}else{
if (computer == null){
throw new IllegalArgumentException("#Error: Argument:computer can't be null when we need to checkout in slave");
}else{
updateClient.doCheckout(repo.getLocation(),new java.io.File(System.getProperty("java.io.tmpdir"),destDir + '_' + appender),SVNRevision.HEAD,SVNRevision.HEAD,SVNDepth.INFINITY,false);
Channel slaveChannel = computer.getChannel();
FilePath fpSrc = new hudson.FilePath(new java.io.File(System.getProperty("java.io.tmpdir"),destDir + '_' + appender));
//println new java.io.File((slave.getWorkspaceRoot().toString()),destDir).toString().replace('\\','/')
FilePath fpDestination = new hudson.FilePath(slaveChannel,new java.io.File((slave.getWorkspaceRoot().toString()),destDir + '_' + appender).toString().replace('\\','/'));
println "Copying files recursively from Temp directory in master to slave";
int files_copied = fpSrc.copyRecursiveTo(fpDestination);
println files_copied
fpSrc.deleteRecursive();
}
}
}
catch (Exception ex){
throw new Exception("#Error:",ex);
}
}
if (args.length == 4){
String url = new String(args[0]);
SVNURL svn_url = null;
try{
svn_url = SVNURL.parseURIDecoded(url);
}
catch(SVNException svnEX){
println "#Error: Check SVN repository Location.";
throw svnEX;
}
String nodeName = new String(args[1]);
String operation = new String(args[2]);
String checkoutAppendString = new String(args[3]);
println args
if (nodeName.equalsIgnoreCase("master")){
println "Executing script on master"
if (operation.equalsIgnoreCase("list")){
PerfromSVNListOperationOnMaster(svn_url);
}else{
PerfromSVNCheckOutOperation(svn_url,true,checkoutAppendString);
}
}else{
if (checkNodeExist(nodeName)){
slave = Jenkins.getInstance().slaves.find({it.name == nodeName});
SlaveComputer computer = slave.getComputer();
if (computer.isOffline()){
println "#Error: $slave is offline."
return
}else{
if (operation.equalsIgnoreCase("list")){
PerfromSVNListOperationOnMaster(svn_url)
}else{
PerfromSVNCheckOutOperation(svn_url,false,checkoutAppendString,computer);
}
}
}else{
println "#Error: $nodeName not found."
return
}
}
}else{
println "Invalid Usage, expecting 3 arguments : 1.RepositoryURL 2.NodeName 3.OperationType"
return
}

Related

How to change the Git URL in all Jenkins jobs

Does anyone have an updated version of ceilfors answer that works for both AbstractProject and WorkflowJob?
This is the solution I came up with. It was tested on Jenkins 2.355
The test was run from the script console.
For testing purposes, I limited the test to one Freestyle (AbstractProject) and one Pipeline (WorkflowJob) job each. You would need to modify the code below.
I hope others find this useful
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import hudson.plugins.git.*
import jenkins.*
import jenkins.model.*
def modifyGitUrl(url) {
def updatedUrl = url.toString().replace("git#gitlab", "git#github")
// println "updatedUrl = ${updatedUrl}"
return updatedUrl
}
Jenkins.instance.getAllItems(Job.class).each {
project = it.getFullName()
if(project.toString().equals("PL_Quick_Testing") || project.toString().equals("A_Freestyle_Job")) {
try {
if (it instanceof AbstractProject){
def oldScm = it.scm
def newUserRemoteConfigs = oldScm.userRemoteConfigs.collect {
new UserRemoteConfig(modifyGitUrl(it.url), it.name, it.refspec, it.credentialsId)
}
def newScm = new GitSCM(newUserRemoteConfigs, oldScm.branches, oldScm.doGenerateSubmoduleConfigurations,
oldScm.submoduleCfg, oldScm.browser, oldScm.gitTool, oldScm.extensions)
it.scm = newScm
it.save()
println "Done"
} else if (it instanceof WorkflowJob) {
def oldScm = it.getTypicalSCM()
def definition = it.getDefinition()
String scriptPath = it.getDefinition().getScriptPath()
def newUserRemoteConfigs = oldScm.userRemoteConfigs.collect {
new UserRemoteConfig(modifyGitUrl(oldScm.userRemoteConfigs.url[0]), it.name, it.refspec, it.credentialsId)
}
def newScm = new GitSCM(newUserRemoteConfigs, oldScm.branches, oldScm.doGenerateSubmoduleConfigurations,
oldScm.submoduleCfg, oldScm.browser, oldScm.gitTool, oldScm.extensions)
def newDefinition = new org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition(newScm, scriptPath)
it.definition = newDefinition
it.save()
println "Done"
} else {
println("${project} has no SCM")
}
} catch (Exception e) {
// e.printStackTrace()
}
}
}

Jenkins - Groovy script not ending after return statement

I'm trying to run scheduled Groovy script on Jenkins but I got into some trouble - It won't finish runnning although it reaches the "return" statement.
I'm using in-house dependencies and Classes and I've found the line of code that if omitted, the script returns successfully. But I can't omit this line unfortunately :(
Do you have any idea what could cause a Jenkins build step too stay stuck?
I've noticed that the "culprit" line of code, internally runs the following:
this.executorService.scheduleWithFixedDelay(this.eventsPublisher, 3L, 3L, TimeUnit.SECONDS);
Is it possible that playing with the Executor, messes around with the Jenkins build steps?
I'd love some help,
Thanks a lot :)
UPDATE:
Code:
import java.sql.DriverManager
import java.sql.ResultSet
import java.text.DateFormat
import java.text.SimpleDateFormat
import hudson.model.*
def verticaConn = null
def verticaStmt = null
def mongoConnection = null
try {
println("start script: vertica_to_kafka")
// get params
def verticaHostName = System.getenv("verticaHostName") //dev=192.168.247.11:5433 prod=192.168.251.120:5433
def verticaDbName = System.getenv("verticaDbName")
def verticaTBName = System.getenv("verticaTBName")
def bootstrapServers = System.getenv("bootstrapServers")
def limitNum = System.getenv("limitNum").toInteger()
def startTime = System.getenv("startTime")
MyKafkaStringProducer producer = new MyKafkaStringProducer();
producer.init()
MyEventDao eventDao = new MyEventDao();
eventDao.setStringProducer(stringProducer);
Class.forName("com.vertica.jdbc.Driver")
String verticaConnectionString = "jdbc:vertica://${verticaHostName}/${verticaDbName}"
Properties verticaProp = new Properties();
verticaProp.put("user", "user");
verticaProp.put("password", "password");
verticaProp.put("ConnectionLoadBalance", 1);
verticaConn = DriverManager.getConnection(verticaConnectionString, verticaProp);
verticaStmt = verticaConn.createStatement()
// vertica execution timestamp
long currentTS = System.currentTimeMillis()
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String startTS = "1970-01-01 00:00:00";
String command= "select * from ${verticaTBName} where ts >'${startTS}' "
if (limitNum > 0) command += "limit ${limitNum}"
println("querying vertica")
verticaStmt.execute(command)
ResultSet results = verticaStmt.getResultSet()
println("start to send data to kafka")
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
while(results.next()){
long id = results.getLong("id");
String domain = results.getString("domain");
String text = results.getString("text");
Date ts = dateFormat.parse(results.getString("ts"));
MyEntity myEntity = new MyEntity(id, domain, text, ts);
eventDao.saveEntity(myEntity);
}
} catch (Exception e){
println(e.printStackTrace())
} finally {
println("going to release resources");
if (verticaStmt != null){
try{
verticaStmt.close()
println("vertica statement closed successfully!");
} catch (Exception e) {
//println("error in close the vertica statement {}", e.getMessage());
}
}
if (verticaConn != null){
try{
verticaConn.close()
println("vertica connection closed successfully!");
} catch (Exception e) {
//println("error in close the vertica connection {}", e.getMessage());
}
}
if (mongoConnection != null){
try {
mongoConnection.getMongo().close();
println("mongo connection closed successfully!");
} catch (Exception e) {
//println("error in close the mongo connection {}", e.getMessage());
}
}
println("end script: vertica_to_kafka")
}
return
System.exit(0)
And in MyKafkaStringProducer I found the following:
public synchronized void init() {
if(this.active) {
this.initKafkaProducer();
this.executorService.scheduleWithFixedDelay(this.eventsPublisher, 3L, 3L, TimeUnit.SECONDS);
}
}

Connection error while connecting wamp server with netbeans8.1

I can't get any output from this program. Do you know why? I am using NetBeans 8.1 and wamp server. I design database named assignments online. Can you also suggest if I am using true drivers?
package managmentSystem;
import javax.swing.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
/**
*
* #author DiyaBangesh
*/
public class ManagmentSystem {
//PreparedStatement pst = null;
//Statement st= null;
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
try{
ResultSet rs;
Connection conn;
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost/assignment","root","");
JOptionPane.showMessageDialog(null,"Connection to database is established");
//return conn;
Statement st = conn.createStatement();
String sql ="SELECT * FROM userdetails";
rs = st.executeQuery(sql);
while(rs.next()){
String nam = rs.getString("name");
String uid = rs.getString("user_id");
String pwd = rs.getString("password");
String eid = rs.getString("email_id");
String con = rs.getString("contact");
String ut = rs.getString("usertype");
System.out.println(nam + " " + uid + " " + pwd + " "+ eid + " " + con + " " + ut );
}
conn.close();
}
catch (Exception sqlEx){
System.out.println(sqlEx);
}
}
}
mysql-connector-java-bin.jar is the one needeed and you have already used it. Make sure that you used correct database name & correct password. Replace 'yourpassword' with your database password. And make sure that server is running.
Follow as below.
public class ManagmentSystem {
Connection con;
Statement s;
PreparedStatement ps;
ResultSet rs;
ManagmentSystem()
{
try
{ Class.forName("com.mysql.jdbc.Driver");
con=DriverManager.getConnection("jdbc:mysql://localhost/assignment?user=root&password=yourpassword");
}
catch(SQLException s)
{
System.out.println("Error in DB Connection");
s.printStackTrace();
}
catch(ClassNotFoundException c)
{
System.out.println("Driver not Found");
}
}
}

I writng custom Agile Tab for JIRA server 7.0.2 with JIRA Agile 6.7.11

I writng custom Agile Tab for JIRA server 7.0.2 with JIRA Agile 6.7.11.
That I want list all Spitns to this Tab.
StringBuffer outputProjects = new StringBuffer();
ServiceOutcome<Collection<Sprint>> allsprints = sprintManager.getAllSprints();
Collection<Sprint> allsprintscollection = allsprints.getValue();
outputProjects.append("");
for (Iterator<Sprint> iterator = allsprintscollection.iterator(); iterator.hasNext();) {
Sprint sprint = iterator.next();
outputProjects.append("<tr>");
outputProjects.append("<td>"+sprint.getName()+"</td>");
outputProjects.append("<td>"+sprint.getId()+"</td>");
outputProjects.append("<td></td>");
outputProjects.append("<td></td>");
outputProjects.append("<td></td>");
outputProjects.append("</tr>");
}
Plugin plugin = pluginAccesor.getEnabledPlugin("com.i4ware.plugin.timesheet.timesheet");
PluginInformation pluginInformation = plugin.getPluginInformation();
String version = pluginInformation.getVersion();
tmpParams.put("sprintsHtml", outputProjects.toString());
tmpParams.put("project", context.getProject().getKey());
tmpParams.put("baseUrl",applicationProperties.getBaseUrl());
tmpParams.put("version",version);
return descriptor.getHtml("view",tmpParams);
But I got with error message log file:
2015-12-02 10:31:55,455 http-nio-8181-exec-12 WARN admin 631x1578x1 xhcbd 80.222.144.149,37.48.78.137 /projects/AD [c.atlassian.ozymandias.SafePluginPointAccess] Unable to run plugin code because of 'java.lang.NullPointerException - null'.
Okay I found a solution my self by help of Atlassian Developer Community.
Class:
import com.atlassian.greenhopper.service.sprint.SprintManager;
Is a privete so it must be loeded first like this:
import com.atlassian.greenhopper.service.sprint.SprintManager;
import com.atlassian.greenhopper.service.sprint.Sprint;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.greenhopper.service.ServiceOutcome;
import org.springframework.context.ApplicationContext;
import org.osgi.framework.InvalidSyntaxException;
import com.atlassian.plugin.osgi.container.OsgiContainerManager;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import com.atlassian.greenhopper.web.rapid.view.JqlHelper;
public class LoadSprintsForGanttServlet extends HttpServlet
{
private String jqlQuery;
private SprintManager getSprintManager() throws InvalidSyntaxException {
ApplicationContext appCtx = (ApplicationContext) getGreenHopperAppCtx();
if ( appCtx !=null ) {
return (SprintManager) appCtx.getBean( "sprintManagerImpl" );
}
return null;
}
private JqlHelper getJqlHelper() throws InvalidSyntaxException {
ApplicationContext appCtx = (ApplicationContext) getGreenHopperAppCtx();
if ( appCtx !=null ) {
return (JqlHelper) appCtx.getBean( "jqlHelper" );
}
return null;
}
private Object getGreenHopperAppCtx() throws InvalidSyntaxException {
OsgiContainerManager osgi = ComponentAccessor.getComponentOfType(OsgiContainerManager.class);
if ( osgi==null ) {
java.lang.System.out.println("OSGI Not Found");
return null;
}
Bundle[] bundles = osgi.getBundles();
for(int i=0;i<bundles.length;i++) {
Bundle bundle = bundles[i];
if ( "com.pyxis.greenhopper.jira".equals( bundle.getSymbolicName() ) ) {
BundleContext bctx = bundle.getBundleContext();
ServiceReference[] refs = bctx.getAllServiceReferences(null,null);
if ( refs!=null ) {
for(int j=0; j<refs.length;j++) {
Object prop = refs[j].getProperty("org.springframework.context.service.name");
if ( "com.pyxis.greenhopper.jira".equals(prop) ) {
return bctx.getService( refs[j] );
}
}
}
}
}
return null;
}
And it can be iterated like this:
try {
ServiceOutcome<Collection<Sprint>> allSprints = getSprintManager().getAllSprints();
sprints = allSprints.getValue();
pages = sprints.size();
}
catch (InvalidSyntaxException e)
{
System.out.println("Got an SearchException: " + e.getCause());
}
for (Iterator iteratorSprints = sprints.iterator(); iteratorSprints.hasNext();) {
Sprint sprint = (Sprint) iteratorSprints.next();
//your code here
}

sshexec ant task: environment variables

I'm using SSHExec ant task to connect to a remote host and I depend on the environment variables that are set on the remote host in order to be able to successfully execute some commands.
<sshexec host="somehost"
username="${username}"
password="${password}"
command="set"/>
Using the task the env. variables that are outputed are not the same as the ones I get when I log in using an SSH Client.
How can I make the env. variables of the remote host avaiable for the session?
Actually there is something you can do about the fact it doesn't start a shell. Use the following:
<sshexec command="/bin/bash -l yourScript.sh" .../>
Using /bin/bash -l will start an login shell then execute your script within that shell. It would be exactly as if you had a version of sshexec that properly starts up a login shell. It has to be a script. If you want to run a single executable command you can do this:
<sshexec command="/bin/bash -l -c 'echo $CATALINA_HOME'" .../>
I've found out that the current SSHExeec task implementation is using JSCh's ChannelExec (remote execution of commands) instead of a ChannelShell (remote shell) as connection channel.
That means that apparentely as per JSCh's current implementation a ChannelExec doesn't load env. variables.
I'm still not sure wether this is a limitation on the protocol or on the API.
The conclusion is that as for now there's no solution for the problem, unless you implement your own Ant task.
A working draft of how it would be:
package org.apache.tools.ant.taskdefs.optional.ssh;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.StringReader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.resources.FileResource;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.KeepAliveOutputStream;
import org.apache.tools.ant.util.TeeOutputStream;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
/**
* Executes a command on a remote machine via ssh.
* #since Ant 1.6 (created February 2, 2003)
*/
public class SSHExecShellSupport extends SSHBase {
private static final String COMMAND_SEPARATOR = System.getProperty("line.separator");
private static final int BUFFER_SIZE = 8192;
private static final int RETRY_INTERVAL = 500;
/** the command to execute via ssh */
private String command = null;
/** units are milliseconds, default is 0=infinite */
private long maxwait = 0;
/** for waiting for the command to finish */
private Thread thread = null;
private String outputProperty = null; // like <exec>
private File outputFile = null; // like <exec>
private boolean append = false; // like <exec>
private Resource commandResource = null;
private boolean isShellMode;
private long maxTimeWithoutAnyData = 1000*10;
private static final String TIMEOUT_MESSAGE =
"Timeout period exceeded, connection dropped.";
public long getMaxTimeWithoutAnyData() {
return maxTimeWithoutAnyData;
}
public void setMaxTimeWithoutAnyData(long maxTimeWithoutAnyData) {
this.maxTimeWithoutAnyData = maxTimeWithoutAnyData;
}
public boolean isShellMode() {
return isShellMode;
}
public void setShellMode(boolean isShellMode) {
this.isShellMode = isShellMode;
}
/**
* Constructor for SSHExecTask.
*/
public SSHExecShellSupport() {
super();
}
/**
* Sets the command to execute on the remote host.
*
* #param command The new command value
*/
public void setCommand(String command) {
this.command = command;
}
/**
* Sets a commandResource from a file
* #param f the value to use.
* #since Ant 1.7.1
*/
public void setCommandResource(String f) {
this.commandResource = new FileResource(new File(f));
}
/**
* The connection can be dropped after a specified number of
* milliseconds. This is sometimes useful when a connection may be
* flaky. Default is 0, which means "wait forever".
*
* #param timeout The new timeout value in seconds
*/
public void setTimeout(long timeout) {
maxwait = timeout;
}
/**
* If used, stores the output of the command to the given file.
*
* #param output The file to write to.
*/
public void setOutput(File output) {
outputFile = output;
}
/**
* Determines if the output is appended to the file given in
* <code>setOutput</code>. Default is false, that is, overwrite
* the file.
*
* #param append True to append to an existing file, false to overwrite.
*/
public void setAppend(boolean append) {
this.append = append;
}
/**
* If set, the output of the command will be stored in the given property.
*
* #param property The name of the property in which the command output
* will be stored.
*/
public void setOutputproperty(String property) {
outputProperty = property;
}
/**
* Execute the command on the remote host.
*
* #exception BuildException Most likely a network error or bad parameter.
*/
public void execute() throws BuildException {
if (getHost() == null) {
throw new BuildException("Host is required.");
}
if (getUserInfo().getName() == null) {
throw new BuildException("Username is required.");
}
if (getUserInfo().getKeyfile() == null
&& getUserInfo().getPassword() == null) {
throw new BuildException("Password or Keyfile is required.");
}
if (command == null && commandResource == null) {
throw new BuildException("Command or commandResource is required.");
}
if(isShellMode){
shellMode();
} else {
commandMode();
}
}
private void shellMode() {
final Object lock = new Object();
Session session = null;
try {
session = openSession();
final Channel channel=session.openChannel("shell");
final PipedOutputStream pipedOS = new PipedOutputStream();
PipedInputStream pipedIS = new PipedInputStream(pipedOS);
final Thread commandProducerThread = new Thread("CommandsProducerThread"){
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(commandResource.getInputStream()));
String singleCmd;
synchronized (lock) {
lock.wait(); // waits for the reception of the very first data (before commands are issued)
while ((singleCmd = br.readLine()) != null) {
singleCmd += COMMAND_SEPARATOR;
log("cmd : " + singleCmd, Project.MSG_INFO);
pipedOS.write(singleCmd.getBytes());
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
log(e, Project.MSG_VERBOSE);
break;
}
}
log("Finished producing commands", Project.MSG_VERBOSE);
}
} catch (IOException e) {
log(e, Project.MSG_VERBOSE);
} catch (InterruptedException e) {
log(e, Project.MSG_VERBOSE);
} finally {
FileUtils.close(br);
}
}
};
ByteArrayOutputStream out = new ByteArrayOutputStream();
final TeeOutputStream tee = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
channel.setOutputStream(tee);
channel.setExtOutputStream(tee);
channel.setInputStream(pipedIS);
channel.connect();
// waits for it to finish receiving data response and then ask for another the producer to issue one more command
thread = new Thread("DataReceiverThread") {
public void run() {
long lastTimeConsumedData = System.currentTimeMillis(); // initializes the watch
try {
InputStream in = channel.getInputStream();
byte[] tmp = new byte[1024];
while (true) {
if(thread == null){ // works with maxTimeout (for the whole task to complete)
break;
}
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
lastTimeConsumedData = System.currentTimeMillis();
if (i < 0){
break;
}
tee.write(tmp, 0, i);
}
if (channel.isClosed()) {
log("exit-status: " + channel.getExitStatus(), Project.MSG_INFO);
log("channel.isEOF(): " + channel.isEOF(), Project.MSG_VERBOSE);
log("channel.isConnected(): " + channel.isConnected(), Project.MSG_VERBOSE);
throw new BuildException("Connection lost."); // NOTE: it also can happen that if one of the command are "exit" the channel will be closed!
}
synchronized(lock){
long elapsedTimeWithoutData = (System.currentTimeMillis() - lastTimeConsumedData);
if (elapsedTimeWithoutData > maxTimeWithoutAnyData) {
log(elapsedTimeWithoutData / 1000 + " secs elapsed without any data reception. Notifying command producer.", Project.MSG_VERBOSE);
lock.notify(); // command producer is waiting for this
try {
lock.wait(500); // wait til we have new commands.
Thread.yield();
log("Continuing consumer loop. commandProducerThread.isAlive()?" + commandProducerThread.isAlive(), Project.MSG_VERBOSE);
if(!commandProducerThread.isAlive()){
log("No more commands to be issued and it's been too long without data reception. Exiting consumer.", Project.MSG_VERBOSE);
break;
}
} catch (InterruptedException e) {
log(e, Project.MSG_VERBOSE);
break;
}
lastTimeConsumedData = System.currentTimeMillis(); // resets watch
}
}
}
} catch (IOException e) {
throw new BuildException(e);
}
}
};
thread.start();
commandProducerThread.start();
thread.join(maxwait);
if (thread.isAlive()) {
// ran out of time
thread = null;
if (getFailonerror()) {
throw new BuildException(TIMEOUT_MESSAGE);
} else {
log(TIMEOUT_MESSAGE, Project.MSG_ERR);
}
} else {
//success
if (outputFile != null) {
writeToFile(out.toString(), append, outputFile);
}
// this is the wrong test if the remote OS is OpenVMS,
// but there doesn't seem to be a way to detect it.
log("Exit status (not reliable): " + channel.getExitStatus(), Project.MSG_INFO);
// int ec = channel.getExitStatus(); FIXME
// if (ec != 0) {
// String msg = "Remote command failed with exit status " + ec;
// if (getFailonerror()) {
// throw new BuildException(msg);
// } else {
// log(msg, Project.MSG_ERR);
// }
// }
}
} catch (Exception e){
throw new BuildException(e);
} finally {
if (session != null && session.isConnected()) {
session.disconnect();
}
}
}
private void commandMode() {
Session session = null;
try {
session = openSession();
/* called once */
if (command != null) {
log("cmd : " + command, Project.MSG_INFO);
ByteArrayOutputStream out = executeCommand(session, command);
if (outputProperty != null) {
//#bugzilla 43437
getProject().setNewProperty(outputProperty, command + " : " + out);
}
} else { // read command resource and execute for each command
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(commandResource.getInputStream()));
String cmd;
String output = "";
while ((cmd = br.readLine()) != null) {
log("cmd : " + cmd, Project.MSG_INFO);
ByteArrayOutputStream out = executeCommand(session, cmd);
output += cmd + " : " + out + "\n";
}
if (outputProperty != null) {
//#bugzilla 43437
getProject().setNewProperty(outputProperty, output);
}
FileUtils.close(br);
} catch (IOException e) {
throw new BuildException(e);
}
}
} catch (JSchException e) {
throw new BuildException(e);
} finally {
if (session != null && session.isConnected()) {
session.disconnect();
}
}
}
private ByteArrayOutputStream executeCommand(Session session, String cmd)
throws BuildException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
TeeOutputStream tee = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
try {
final ChannelExec channel;
session.setTimeout((int) maxwait);
/* execute the command */
channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(cmd);
channel.setOutputStream(tee);
channel.setExtOutputStream(tee);
channel.connect();
// wait for it to finish
thread =
new Thread() {
public void run() {
while (!channel.isClosed()) {
if (thread == null) {
return;
}
try {
sleep(RETRY_INTERVAL);
} catch (Exception e) {
// ignored
}
}
}
};
thread.start();
thread.join(maxwait);
if (thread.isAlive()) {
// ran out of time
thread = null;
if (getFailonerror()) {
throw new BuildException(TIMEOUT_MESSAGE);
} else {
log(TIMEOUT_MESSAGE, Project.MSG_ERR);
}
} else {
//success
if (outputFile != null) {
writeToFile(out.toString(), append, outputFile);
}
// this is the wrong test if the remote OS is OpenVMS,
// but there doesn't seem to be a way to detect it.
int ec = channel.getExitStatus();
if (ec != 0) {
String msg = "Remote command failed with exit status " + ec;
if (getFailonerror()) {
throw new BuildException(msg);
} else {
log(msg, Project.MSG_ERR);
}
}
}
} catch (BuildException e) {
throw e;
} catch (JSchException e) {
if (e.getMessage().indexOf("session is down") >= 0) {
if (getFailonerror()) {
throw new BuildException(TIMEOUT_MESSAGE, e);
} else {
log(TIMEOUT_MESSAGE, Project.MSG_ERR);
}
} else {
if (getFailonerror()) {
throw new BuildException(e);
} else {
log("Caught exception: " + e.getMessage(),
Project.MSG_ERR);
}
}
} catch (Exception e) {
if (getFailonerror()) {
throw new BuildException(e);
} else {
log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
}
}
return out;
}
/**
* Writes a string to a file. If destination file exists, it may be
* overwritten depending on the "append" value.
*
* #param from string to write
* #param to file to write to
* #param append if true, append to existing file, else overwrite
* #exception Exception most likely an IOException
*/
private void writeToFile(String from, boolean append, File to)
throws IOException {
FileWriter out = null;
try {
out = new FileWriter(to.getAbsolutePath(), append);
StringReader in = new StringReader(from);
char[] buffer = new char[BUFFER_SIZE];
int bytesRead;
while (true) {
bytesRead = in.read(buffer);
if (bytesRead == -1) {
break;
}
out.write(buffer, 0, bytesRead);
}
out.flush();
} finally {
if (out != null) {
out.close();
}
}
}
}
Another simple workaround is to source the user's .bash_profile before running your commands:
<sshexec host="somehost"
username="${username}"
password="${password}"
command="source ~/.bash_profile && set"/>
Great post chubbsondubs. I needed to set the ORACLE SID then execute a PLSQL script that does not have the proper exit. Hence the echo exit piped.
<sshexec host="${db.ipaddr}"
verbose="true"
trust="true"
username="${scp.oracle.userid}"
password="${scp.oracle.password}"
command="echo exit | /bin/bash -l -c 'export ORACLE_SID=${db.name} ; sqlplus ${db.dbo.userid}/${db.dbo.password} #./INSTALL_REVPORT/CreateDatabase/gengrant.sql'"
/>

Resources