Skip to content
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

Merged
merged 14 commits into from
Dec 13, 2019
Merged

[JENKINS-58975] - Update the working directory to match container working directory #610

merged 14 commits into from
Dec 13, 2019

Conversation

narayanan
Copy link
Contributor

  • Modified working directory to match the container working directory before executing commands in a container
  • Added unit tests

@Vlatombe Vlatombe added the bug Bug Fixes label Oct 3, 2019
Copy link
Member

@Vlatombe Vlatombe left a 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);
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

@Vlatombe Vlatombe Oct 3, 2019

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

Comment on lines 1 to 38
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"
}
}
}
}
Copy link
Member

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'
+                    }
+                }
             }
         }
     }

Copy link
Contributor Author

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.

@narayanan
Copy link
Contributor Author

@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

@narayanan
Copy link
Contributor Author

@Vlatombe Please review and provide your feedback when you get a chance.

Copy link
Member

@Vlatombe Vlatombe left a 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);
Copy link
Member

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.

Copy link
Contributor Author

@narayanan narayanan Nov 29, 2019

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 because KubernetesSlave sets remoteFs 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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

Copy link
Member

@jtnord jtnord Jan 6, 2020

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.

@Vlatombe
Copy link
Member

Vlatombe commented Oct 9, 2019

@narayanan I merged master into your branch, I think it should fix the remaining tests in the CI.

@narayanan
Copy link
Contributor Author

Another test with a custom workingDir for the jnlp would be good to cover the remaining case.

@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 because KubernetesSlave sets remoteFs 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.

@Vlatombe Vlatombe added ready enhancement Improvements and removed bug Bug Fixes labels Dec 13, 2019
@Vlatombe Vlatombe merged commit cc58b4c into jenkinsci:master Dec 13, 2019
@narayanan narayanan deleted the Fix-Working-Dir-Exec branch December 13, 2019 23:13
@zerkms
Copy link

zerkms commented Dec 19, 2019

Team, this PR triggers an exception:

00:03:31.526  java.lang.NullPointerException
00:03:31.526  	at org.csanchez.jenkins.plugins.kubernetes.pipeline.ContainerExecDecorator$1.launch(ContainerExecDecorator.java:267)

Details: https://issues.jenkins-ci.org/browse/JENKINS-60517

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants