How should I update Java code for add one slave node?

25 views
Skip to first unread message

田欧

unread,
Mar 1, 2019, 7:46:44 AM3/1/19
to Jenkins Users
I'm using `ssh-slaves-plugin` and write some codes, like the below:

@RequestMapping(value = "/test", method = RequestMethod.GET)
public Map<String, Boolean> test() {
Map<String, Boolean> result = new HashMap<>();

// username is my jenkins user
    // password is my jenkins password
    UsernamePasswordCredentialsImpl credentials = new UsernamePasswordCredentialsImpl(CredentialsScope.SYSTEM, "dummyCredentialId", "perf", "myname", "mysceret");
SystemCredentialsProvider.getInstance().getDomainCredentialsMap().put(Domain.global(),
Collections.singletonList(
credentials
)
);

// ip is my slave ip
SSHLauncher launcher = new SSHLauncher("10.10.10.10", 22, "dummyCredentialId", null, null, null,
null, 3, 1, 1, new KnownHostsFileKeyVerificationStrategy());

DumbSlave dumb = null;
try {
dumb = new DumbSlave("slave-test", "", launcher);
dumb.setNodeDescription("dummy-description");
dumb.setNumExecutors(1);
dumb.setMode(Node.Mode.NORMAL);
dumb.setRetentionStrategy(RetentionStrategy.NOOP);
} catch (IOException e) {
e.printStackTrace();
} catch (Descriptor.FormException e) {
e.printStackTrace();
}

    // I see https://github.com/jenkinsci/ssh-slaves-plugin/blob/master/src/test/java/hudson/plugins/sshslaves/SSHLauncherTest.java#L181
    // use JenkinsRule, so I use Jenkins.getInstanceOrNull
try {
Jenkins.getInstanceOrNull().addNode(dumb);
} catch (IOException e) {
e.printStackTrace();
}
result.put("success", true);
return result;
}

when I run it, return error, stack:

java.lang.NullPointerException: null
at jenkins.security.ConfidentialStore.get(ConfidentialStore.java:68) ~[jenkins-core-2.166.jar!/:na]
at jenkins.security.ConfidentialKey.load(ConfidentialKey.java:47) ~[jenkins-core-2.166.jar!/:na]
at jenkins.security.CryptoConfidentialKey.getKey(CryptoConfidentialKey.java:41) ~[jenkins-core-2.166.jar!/:na]
at jenkins.security.CryptoConfidentialKey.decrypt(CryptoConfidentialKey.java:134) ~[jenkins-core-2.166.jar!/:na]
at hudson.util.HistoricalSecrets.decrypt(HistoricalSecrets.java:55) ~[jenkins-core-2.166.jar!/:na]
at hudson.util.Secret.decrypt(Secret.java:212) ~[jenkins-core-2.166.jar!/:na]
at hudson.util.Secret.fromString(Secret.java:254) ~[jenkins-core-2.166.jar!/:na]
at com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl.<init>(UsernamePasswordCredentialsImpl.java:72) ~[credentials-2.1.18.jar!/:2.1.18]
at com.kk.perf.controller.SlaveController.test(SlaveController.java:48) ~[classes!/:0.0.1-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_102]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_102]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_102]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_102]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) ~[tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_102]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_102]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.16.jar!/:9.0.16]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_102]

So, why?

And I want to know, how start it? because I don't set any info about jenkins master.

Thanks!


Mark Waite

unread,
Mar 1, 2019, 8:43:52 AM3/1/19
to Jenkins Users
The ssh agents use secure shell to connect.  The secure shell uses private key / public key pairs to perform the connection.  Your example is trying to use a username / password credential when it needs to use a private key credential.

We use a technique like below from a system groovy script to add a Jenkins agent at startup:

import jenkins.model.*
import hudson.model.*
import hudson.slaves.*
import hudson.plugins.sshslaves.*
import hudson.slaves.EnvironmentVariablesNodeProperty.Entry
import hudson.plugins.sshslaves.verifiers.*

import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.common.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.jenkins.plugins.sshcredentials.impl.*

// SET THE INITIAL SSH CREDENTIALS
global_domain = Domain.global()

credentials_store = Jenkins.instance.getExtensionList(
  'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
)[0].getStore()

credentials = new BasicSSHUserPrivateKey(
  CredentialsScope.SYSTEM,
  "ssh-agent-key",
  "jenkins",
  new BasicSSHUserPrivateKey.FileOnMasterPrivateKeySource(
    '/home/butler/.ssh/id_rsa'
  ),
  '',
  "SSH Key for the Agent"
)

credentials_store.addCredentials(global_domain, credentials)

SshHostKeyVerificationStrategy doNotVerifyHostKey = new NonVerifyingKeyVerificationStrategy()

// CREATE THE JDK8 AGENT
SSHLauncher jdk8Launcher = new SSHLauncher("jdk8-ssh-agent", 22, "ssh-agent-key", "", "", "", "", 33, 2, 5, doNotVerifyHostKey)
Slave jdk8SSHAgent = new DumbSlave("jdk8-node", "/home/jenkins", jdk8Launcher)
jdk8SSHAgent.setLabelString("docker maven jdk8 jdk-8 java8 java-8 maven-jdk8 java")
jdk8SSHAgent.setNodeDescription("Agent node for JDK8")
jdk8SSHAgent.setNumExecutors(2)

List<Entry> jdk8SSHAgentEnv = new ArrayList<Entry>();
jdk8SSHAgentEnv.add(new Entry("JAVA_HOME","/usr/lib/jvm/java-1.8-openjdk"))
EnvironmentVariablesNodeProperty jdk8SSHAgentEnvPro = new EnvironmentVariablesNodeProperty(jdk8SSHAgentEnv);
jdk8SSHAgent.getNodeProperties().add(jdk8SSHAgentEnvPro)

Jenkins.instance.addNode(jdk8SSHAgent)


You can find this script in the Jenkins server that is provided as part of the lab environment for the free Jenkins Pipeline Fundamentals course from https://standard.cbu.cloudbees.com/cloudbees-university-jenkins-pipeline-fundamentals .  Other free courses are available from https://standard.cbu.cloudbees.com/ .  The script is not part of the course, but it is used in the lab environment to configure the agents that are used in the labs.

The 'doNotVerifyHostKey' is a risky setting that works in the lab environment because the lab environment is "disposable".  In your environment you will probably want to use a different setting that assures the connecting agent has the correct host key.  You don't want to risk connecting to the wrong agent.

Mark Waite

--
You received this message because you are subscribed to the Google Groups "Jenkins Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-use...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-users/6cd46b89-519b-4557-8a41-67656b3fa2b2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Thanks!
Mark Waite

田欧

unread,
Mar 3, 2019, 9:33:52 PM3/3/19
to Jenkins Users
Thanks @Mark
I don't need to set jenkins master node address? 


在 2019年3月1日星期五 UTC+8下午8:46:44,田欧写道:

Mark Waite

unread,
Mar 3, 2019, 9:43:18 PM3/3/19
to Jenkins Users
Since your test is using JenkinsRule, I believe the JenkinsRule.createSlave() method will return a DumbSlave without requiring that you use SSHLauncher and without requiring that you have access to a computer at the specific IP address embedded in the test.

Is there a specific reason that your test must have an SSH launched agent?

If so, how will your test run anywhere outside the specific machines you've configured?

Mark Waite
Reply all
Reply to author
Forward
0 new messages