-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[JENKINS-58975] - Update the working directory to match container working directory #610
Conversation
narayanan
commented
Oct 3, 2019
- Modified working directory to match the container working directory before executing commands in a container
- Added unit tests
…s-plugin into Fix-Working-Dir-Exec
…s-plugin into Fix-Working-Dir-Exec
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks promising
if (containerWorkingDir.isPresent() && ! containerWorkingDirFilePath.getRemote().equals(containerWorkingDir.toString())) { | ||
// Container has a custom workingDir, set pwd to the container workspace root | ||
containerWorkingDirStr = containerWorkingDir.get(); | ||
containerWorkingDirFilePath = new FilePath(containerWorkingDirFilePath.getChannel(), containerWorkingDirStr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be misleading, if the working directory has been changed using dir('foo'){...}
, this will alter it to the container root working dir.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm missing something. What do you mean by container root working dir? How is it different from pwd
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you have something like
container('foo') {
dir('mydir') {
sh 'pwd'
}
}
Then mydir will be ignored with the current code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, I'll update the groovy as suggested in the other comment, that will cover this use case and modify the code accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do we do if user has not set a dir(
mydir)
? In such case the pwd
was pointing to /home/jenkins/agent
which does not exist with in the container, should we change it in such a scenario?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should always be interpreted relatively to the current working dir.
So if you have dir('foo')
, pwd should be $WORKSPACE/foo
.
pipeline { | ||
agent { | ||
kubernetes { | ||
defaultContainer 'maven' | ||
yaml """ | ||
metadata: | ||
labels: | ||
some-label: some-label-value | ||
class: KubernetesDeclarativeAgentTest | ||
spec: | ||
containers: | ||
- name: jnlp | ||
env: | ||
- name: CONTAINER_ENV_VAR | ||
value: jnlp | ||
- name: maven | ||
image: maven:3.3.9-jdk-8-alpine | ||
workingDir: /home/jenkins/wsp1 | ||
command: | ||
- cat | ||
tty: true | ||
env: | ||
- name: CONTAINER_ENV_VAR | ||
value: maven | ||
""" | ||
} | ||
} | ||
|
||
stages { | ||
stage('Run maven') { | ||
steps { | ||
sh 'mvn -version' | ||
sh "echo Workspace dir is ${pwd()}" | ||
sh "echo \$WORKSPACE" | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest the following changes to cover more ground. The java part should assert with working dirs.
diff --git a/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/declarativeCustomWorkingDir.groovy b/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/declarativeCustomWorkingDir.groovy
index 72034c55..d4a84771 100644
--- a/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/declarativeCustomWorkingDir.groovy
+++ b/src/test/resources/org/csanchez/jenkins/plugins/kubernetes/pipeline/declarativeCustomWorkingDir.groovy
@@ -1,7 +1,6 @@
pipeline {
agent {
kubernetes {
- defaultContainer 'maven'
yaml """
metadata:
labels:
@@ -29,9 +28,15 @@ spec:
stages {
stage('Run maven') {
steps {
- sh 'mvn -version'
- sh "echo Workspace dir is ${pwd()}"
- sh "echo \$WORKSPACE"
+ dir('foo') {
+ sh 'echo [jnlp] current dir is $(pwd)'
+ sh 'echo [jnlp] WORKSPACE=$WORKSPACE'
+ container('maven') {
+ sh 'mvn -version'
+ sh 'echo [maven] current dir is $(pwd)'
+ sh 'echo [maven] WORKSPACE=$WORKSPACE'
+ }
+ }
}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion. I took the example groovy from the JENKINS bug. I'll enhance the test case.
@Vlatombe I've updated the logic to address pwd. Please take a look. Also, I ran maven build multiple times locally using the following command (same as in the jenkins file) against local minikube. I do not see test failure, so not sure why tests are failing in the Jenkins. mvn -B -ntp clean install -Dmaven.test.skip=true;mvn -e -DconnectorHost=0.0.0.0 -Djenkins.host.address=192.168.99.1 test |
@Vlatombe Please review and provide your feedback when you get a chance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another test with a custom workingDir for the jnlp would be good to cover the remaining case.
if (containerWorkingDir.isPresent() && ! containerWorkingDirFilePath.getRemote().startsWith(containerWorkingDirStr)) { | ||
// Container has a custom workingDir, updated the pwd to match container working dir | ||
containerWorkingDirFilePathStr = containerWorkingDirFilePath.getRemote().replaceFirst( | ||
ContainerTemplate.DEFAULT_WORKING_DIR, containerWorkingDirStr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't work if the jnlp container uses a custom working directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Vlatombe Setting a custom working directory for JNLP container runs into error much before invoking the kubernetes plugin to execute the shell script. Here is my observation
- Jenkins always cosiders
/home/jenkins/agent
as the workspace directory for declarative pipelines. This is happening becauseKubernetesSlave
setsremoteFs
as default working dir in the following method. When this method gets invoked, YAML declaration of the pod was not yet parsed, so, there is no container so, always sets the default container working dir
public String getRemoteFs() {
return getFirstContainer().map(ContainerTemplate::getWorkingDir).orElse(ContainerTemplate.DEFAULT_WORKING_DIR);
}
- In the build console output this can be clearly noticed. Following output is printed even when none of the containers use
/home/jenkins/agent
as working directory, basically this directory will not exist within any of the containers.
Running on declarative-custom-working-dir-1-0597g-xhtl4-dqklj in /home/jenkins/agent/workspace/declarative Custom Working Dir
- When executing shell command, Jenkins tries to store the shell commands as a shell script under the
remoteFs
directory which will be/home/jenkins/agent
for all declarative pipelines. But with in the JNLP container, workspace is mounted in a different directory, not in the/home/jenkins/agent
. So creation of the shell script in the remote slave fails because that directory does not exist with in JNLP container. This shell script file creation happens with in Jenkins, only after creation of the Shell script control is passed to kubernetes plugin to execute the command.
So, my observation is, for declarative pipelines, JNLP container should always use /home/jenkins/agent
as working directory. Declaring a different one will result in error. I think the right solution would be to set the remoteFs
to the working directory of JNLP. But I think that involves a bigger refactoring as YAML has to be parsed prior to setting the remoteFs
.
I think for now, we can treat JNLP containers not able to use a custom working dir as a limitation. Let me know your thoughts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for now, we can treat JNLP containers not able to use a custom working dir as a limitation. Let me know your thoughts.
They used to be able to - and indeed when upgrading I am no longer able to and my pipelines using kaniko became broken - may or may not have been this change, but changing the workingDir back to the default works (ftr may or may not have been this change - but people with custom jnlp and container images expect to be able to set abitrary working directories) - especially given the field it is still exposed.
@narayanan I merged master into your branch, I think it should fix the remaining tests in the CI. |
@Vlatombe Setting a custom working directory for JNLP container runs into error much before invoking the kubernetes plugin to execute the shell script. Here is my observation
So, my observation is, for declarative pipelines, JNLP container should always use /home/jenkins/agent as working directory. Declaring a different one will result in error. I think the right solution would be to set the remoteFs to the working directory of JNLP. But I think that involves a bigger refactoring as YAML has to be parsed prior to setting the remoteFs. I think for now, we can treat JNLP containers not able to use a custom working dir as a limitation. Let me know your thoughts. |
Team, this PR triggers an exception:
|