Cannot access file on Jenkins slave

1,576 views
Skip to first unread message

Stéphane Bruckert

unread,
Aug 1, 2013, 10:20:30 AM8/1/13
to jenkin...@googlegroups.com
Hello,

Through my own plugin, I need to know about the existence of a file in the workspace of a Jenkins slave. But the file can't be found whereas it really exists on the slave (D:\workspace\JOB_NAME\test.txt).

    public class MyBuilder extends Builder implements Serializable {
    
    private static final long serialVersionUID = 1L;
   
    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) 
    throws InterruptedException, IOException {
   
    FilePath fp = new FilePath(build.getWorkspace(), "test.txt");
    
    String result = fp.act(new FileCallable<String>() {
    private static final long serialVersionUID = 1L;
    
    @Override
    public String invoke(File file, VirtualChannel channel) throws IOException, InterruptedException {
    if (file.getAbsoluteFile().exists()){
    return file.getName() + " exists.";
    } else {
    return file.getName() + " doesn't exist.";
    }
    }
    });
    
    System.out.println("resultat : " + result);

Result: 

    FATAL: remote file operation failed: D:\workspace\JOB_NAME\test.txt at hudson.remoting.Channel@182752b:Slave
    hudson.util.IOException2: remote file operation failed: D:\workspace\JOB_NAME\test.txt at hudson.remoting.Channel@182752b:Slave
    at hudson.FilePath.act(FilePath.java:900)
    at hudson.FilePath.act(FilePath.java:877)
    at com.company.tlb.proj.MyBuilder.perform(Unknown Source)
    at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:19)
    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:804)
    at hudson.model.Build$BuildExecution.build(Build.java:199)
    at hudson.model.Build$BuildExecution.doRun(Build.java:160)
    at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:586)
    at hudson.model.Run.execute(Run.java:1575)
    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:46)
    at hudson.model.ResourceController.execute(ResourceController.java:88)
    at hudson.model.Executor.run(Executor.java:237)
    Caused by: java.io.IOException: Unable to serialize hudson.FilePath$FileCallableWrapper@18b91cb
    at hudson.remoting.UserRequest.serialize(UserRequest.java:166)
    at hudson.remoting.UserRequest.<init>(UserRequest.java:62)
    at hudson.remoting.Channel.call(Channel.java:671)
    at hudson.FilePath.act(FilePath.java:893)
    ... 11 more
    Caused by: java.io.NotSerializableException: java.io.PrintStream
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
    at hudson.remoting.UserRequest._serialize(UserRequest.java:155)
    at hudson.remoting.UserRequest.serialize(UserRequest.java:164)
    ... 14 more

What am I doing wrong?

Hugh Perkins

unread,
Aug 1, 2013, 10:49:32 AM8/1/13
to jenkin...@googlegroups.com
I'm a newbie to Jenkins, and I don't know what's going on, but just in case it catalyzes some ideas:

- for your builder it says 'unknown source'.  maybe it might be useful to include the source code with your builder so you can get the exact line number of the error (I'm not sure if this is possible?)

- the underlying error seems to be 'Caused by: java.io.NotSerializableException: java.io.PrintStream'.  This doesn't seem to be related to anything to do with the underlying file you are looking for?  Are you sure the error is coming from the existence or not of the file you are looking for, and not something more fundamental, like a broken serializer, or similar, somewhere?

Jesse Glick

unread,
Aug 1, 2013, 11:38:41 AM8/1/13
to jenkin...@googlegroups.com
On Thu, Aug 1, 2013 at 10:20 AM, Stéphane Bruckert
<stephane...@gmail.com> wrote:
> String result = fp.act(new FileCallable<String>() {

This is an antipattern: a FileCallable is Serializable, so if you make
it an anonymous inner class, it picks us this$ references to the
enclosing scope. Just make it a static nested class so you can control
all its fields.

(I have a to-do item for the NetBeans plugin for Jenkins development
to flag this mistake with a warning.)

Vincent Latombe

unread,
Aug 1, 2013, 12:55:55 PM8/1/13
to Jenkins Dev
Hi,

Why not calling fp.exists() [1] directly? The FilePath instance is already a pointer to the remote filesystem.

--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-de...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



Marc MacIntyre

unread,
Aug 1, 2013, 1:21:09 PM8/1/13
to jenkin...@googlegroups.com
This is working for me:

FilePath setupDetailsFile = build.getWorkspace().child("filename.txt")


--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-de...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Marc MacIntyre

Hugh Perkins

unread,
Aug 1, 2013, 2:39:11 PM8/1/13
to jenkin...@googlegroups.com
> Just make it a static nested class so you can control
all its fields.

Currently, the documentation explicitly shows using a nested anonymous class: http://javadoc.jenkins-ci.org/hudson/FilePath.html#exists%28%29

I tried to reproduce the problem on linux, and failed to reproduce it.  My test code is below.  I'm curious why the code runs on linux but not on Windows?  Serialization and so on should behave identically on both platforms I would think?

public class StephaneBuilder extends Builder implements Serializable {
private static final long serialVersionUID = 1L;
@DataBoundConstructor
public StephaneBuilder() {
}
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) 
throws InterruptedException, IOException {
listener.getLogger().println("perform start");
listener.getLogger().println(InetAddress.getLocalHost().getHostName());
FilePath fp = new FilePath(build.getWorkspace(), "test.txt");
listener.getLogger().println("file " + fp.getRemote() + " " + fp.exists() );

String result = fp.act(new FileCallable<String>() {
private static final long serialVersionUID = 1L;

@Override
public String invoke(File file, VirtualChannel channel) throws IOException, InterruptedException {
StringBuilder stringBuilder = new StringBuilder();
if (file.getAbsoluteFile().exists()){
stringBuilder.append( file.getName() + " exists." );
} else {
stringBuilder.append( file.getName() + " doesn't exist." );
}
stringBuilder.append("\nhost: " + InetAddress.getLocalHost().getHostName() );
return stringBuilder.toString();
}
});
try {
listener.getLogger().println(launcher.getChannel().call(new Callable<String,Throwable>(){
private static final long serialVersionUID = 5093762087527902486L;

@Override
public String call() throws Throwable {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("channel callable call");
stringBuilder.append("\nhost: " + InetAddress.getLocalHost().getHostName() );
return stringBuilder.toString();
}
}));
} catch( Throwable e ) {
listener.getLogger().println(e.getMessage());
e.printStackTrace(listener.getLogger());
}

listener.getLogger().println("result: " + result );
System.out.println("resultat : " + result);
return true;
}
@Extension
public static class DescriptorImpl extends Descriptor<Builder> {

@Override
public String getDisplayName() {
return "StephaneBuilder";
}
}
}

Output:

Started by user anonymous
Building remotely on ubuntu64 in workspace /home/ubuntu/slave/workspace/stephanetestubuntu64
perform start
watermelon.localdomain
file /home/ubuntu/slave/workspace/stephanetestubuntu64/test.txt true
channel callable call
host: domU-12-31-39-0A-3C-D0.compute-1.internal
result: test.txt exists.
host: domU-12-31-39-0A-3C-D0.compute-1.internal
Finished: SUCCESS


Stéphane Bruckert

unread,
Aug 2, 2013, 5:21:06 AM8/2/13
to jenkin...@googlegroups.com
Thank you everyone!

Jess Glick, you were on the right track... that was exactly it: to make a static inner class for my FileCallable. Problem also solved here: http://stackoverflow.com/questions/17727054/cannot-access-file-on-jenkins-slave
Vincent Latombe, the strangeness is that fp.exists() works for a folder but not for a file...
Marc MacIntyrebuild.getWorkspace().child("filename.txt"); is the same as new FilePath(build.getWorkspace(), "filename.txt");. The FilePath object was rightly gotten, but the problem occured  within the .act call.
Hugh Perkins, good job you tried under both Linux and Windows. Now that the problem is solved for Windows and that there really was a reason why it did not work, why does Java let it work under Linux? 

I am still wondering, why does the Jenkins doc not indicate to make an inner class?

Hugh Perkins

unread,
Aug 2, 2013, 5:53:25 AM8/2/13
to jenkin...@googlegroups.com
> Now that the problem is solved for Windows and that there really was a reason why it did not work, why does Java let it work under Linux? 

Yes.  Note that I only tried linux, not Windows.  So, the difference might be many things, eg I'm using openjdk 1.7, so maybe a 1.6 versus 1.7 difference, or maybe a Sun versus openjdk difference?

Stéphane Bruckert

unread,
Aug 2, 2013, 6:00:21 AM8/2/13
to jenkin...@googlegroups.com
Yes, it must be due to the Java version.

Jesse Glick

unread,
Aug 2, 2013, 1:56:11 PM8/2/13
to jenkin...@googlegroups.com
On Fri, Aug 2, 2013 at 5:21 AM, Stéphane Bruckert
<stephane...@gmail.com> wrote:
> I am still wondering, why does the Jenkins doc not indicate to make an inner class?

An oversight which I fixed as I posted my earlier reply. New Javadoc
is probably published as part of the weekly build process (not sure).
Reply all
Reply to author
Forward
0 new messages