Skip to content

Commit 9b5afee

Browse files
committed
Merge branch 'v1.1.0'
2 parents 4ec35b3 + fe8d3a3 commit 9b5afee

File tree

7 files changed

+246
-0
lines changed

7 files changed

+246
-0
lines changed

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,49 @@ It is possible (although not necessary) to explicitly work with docker networks.
6363
6464
```
6565

66+
## Working with Truststores
67+
68+
Often comes a Truststore into play while working with Jenkins and Java. Jenkins can accommodate necessary certificates in its truststore so Java applications like Maven (and others too!) can successfully interact with other parties, like download artifacts from artifact repositories or transport data over the network. Even so, it may be necessary to provide these Java applications with the right certificates when otherwise encrypted communication would fail without doing so.
69+
70+
## Simple Truststore pipeline
71+
72+
For such circumstances this library provides a small snippet. The global `truststore` variable ensures that any truststore files which are copied in the process are also removed at the end of both `copy` and `use` actions.
73+
74+
In order to successfully provide a truststore to any Java process this sequence must be in order:
75+
76+
1. copy the truststore with `truststore.copy()`
77+
1. use the copied truststore with `truststore.use { truststoreFile -> }`
78+
79+
Here is a more elaborate example:
80+
81+
```
82+
Library ('zalenium-build-lib') _
83+
84+
node 'master' {
85+
truststore.copy()
86+
}
87+
node 'docker' {
88+
truststore.use { truststoreFile ->
89+
javaOrMvn "-Djavax.net.ssl.trustStore=${truststoreFile} -Djavax.net.ssl.trustStorePassword=changeit"
90+
}
91+
}
92+
```
93+
94+
## Alternative Ways of Configuration
95+
96+
It is possible to supply a different truststore than the Jenkins one. Also it is possible to provide a different name in order to avoid filename collision:
97+
98+
```
99+
Library ('zalenium-build-lib') _
100+
101+
node('master') {
102+
truststore.copy('/path/to/alternative/truststore/file.jks')
103+
}
104+
node('anotherNode') {
105+
//truststore.use ... as usual
106+
}
107+
```
108+
66109
## Locking
67110

68111
Right now, only one Job can run Zalenium Tests at a time.

vars/helper.groovy

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
String generateZaleniumJobName() {
2+
return "${JOB_BASE_NAME}_${BUILD_NUMBER}"
3+
}
4+
5+
String findHostName() {
6+
String regexMatchesHostName = 'https?://([^:/]*)'
7+
8+
// Storing matcher in a variable might lead to java.io.NotSerializableException: java.util.regex.Matcher
9+
if (!(env.JENKINS_URL =~ regexMatchesHostName)) {
10+
script.error 'Unable to determine hostname from env.JENKINS_URL. Expecting http(s)://server:port/jenkins'
11+
}
12+
return (env.JENKINS_URL =~ regexMatchesHostName)[0][1]
13+
}

vars/helper.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- generateZaleniumJobName() - creates a jobname unique to the current Jenkins job. For the 99th Jenkins build of the job
2+
"ACME" the job name would be "ACME_99".
3+
4+
- findHostName() - returns the host name of the current Jenkins node. This is usually needed for getting the FQDN of the
5+
Cloudogu EcoSystem instance which runs the Jenkins master node.

vars/truststore.groovy

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Provides a simple way to use a Java trust store over different Jenkins nodes.
3+
*
4+
* @param pathToTruststore provides the path to a Java truststore. It defaults to the truststore on the Jenkins master.
5+
*/
6+
def copy(String pathToTruststore = '/var/lib/jenkins/truststore.jks') {
7+
String truststoreFile = 'truststore.jks'
8+
String stashName = 'truststore'
9+
10+
sh "cp ${pathToTruststore} ./${truststoreFile}"
11+
stash includes: truststoreFile, name: stashName
12+
sh "rm -f ./${truststoreFile}"
13+
}
14+
15+
/**
16+
* Unstashes the previously stashed truststore to the current workspace. The truststore will be deleted after the closure
17+
* body finished.
18+
*
19+
* <code>truststore.copy()</code> MUST be called beforehand, otherwise there would be no truststore to be unstashed.
20+
*
21+
* @param closure this closure is executed after the truststore was successfully unstashed.
22+
*/
23+
def use(Closure inner) {
24+
String truststoreFile = 'truststore.jks'
25+
String stashName = 'truststore'
26+
27+
try {
28+
unstash name: stashName
29+
30+
inner.call(truststoreFile)
31+
32+
} catch (Exception ex) {
33+
echo "withTruststore failed because an exception occurred: ${ex}"
34+
throw ex
35+
} finally {
36+
sh "rm -f ./${truststoreFile}"
37+
}
38+
}

vars/truststore.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copies and provides a truststore file for safe use over different Jenkins nodes. When the build job finishes there
2+
will be no truststore file left in the Jenkins workspace.
3+
4+
By default Jenkins's truststore will be used: `/var/lib/jenkins/truststore.jks`
5+
6+
(optional) Parameters:
7+
8+
- pathToTruststore - This path pointing to the truststore file will be used instead of the default path.
9+
10+
Method summary:
11+
12+
- copy() - copies a truststore file and stashed it for later use.
13+
- use { truststoreFile -> } - enables the usage of the previously copied truststore file. The truststore file which
14+
was extracted from the stash will be deleted once the body finishes.
15+
16+
Exemplary calls:
17+
18+
node 'master' {
19+
truststore.copy()
20+
}
21+
node 'docker' {
22+
truststore.use { truststoreFile ->
23+
javaOrMvn "-Djavax.net.ssl.trustStore=${truststoreFile} -Djavax.net.ssl.trustStorePassword=changeit"
24+
}
25+
}

vars/withMavenSettings.groovy

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* Provides a simple custom maven settings.xml file to current working directory with Maven Central mirror in the
3+
* current CES instance.
4+
*
5+
* Example call:
6+
*
7+
* <pre>
8+
* nexusCreds = usernamePassword(credentialsId: 'jenkinsNexusServiceUser', passwordVariable: 'PASSWORD', usernameVariable: 'USERNAME')
9+
* withMavenSettings(nexusCreds, 'cesinstance.stage.host.tld', '/usr/share/maven') { settingsXml ->
10+
* // do your maven call here
11+
* mvn "-s ${settingsXml} test"
12+
* } // settings.xml will be removed automatically
13+
* </pre>
14+
*
15+
* @param nexusCredentials Jenkins credentials which provide USERNAME and PASSWORD to an account which enables Nexus interaction
16+
* @param cesFQDN the full qualified domain name of the current CES instance, f. i. <code>cesinstance.stage.host.tld</code>
17+
* @param pathToLocalMavenRepository without the .m2 directory part, f. i. <code>/usr/share/maven</code>. The suffix <code>/.m2/repository</code> will be added automatically.
18+
*/
19+
def settings(def nexusCredentials, String cesFQDN, String pathToLocalMavenRepository, Closure closure) {
20+
echo "write settings.xml to ${pathToLocalMavenRepository}"
21+
String settingsXml = "settings.xml"
22+
withCredentials([nexusCredentials]) {
23+
writeFile file: settingsXml, text: """
24+
<settings>
25+
<localRepository>${pathToLocalMavenRepository}/.m2/repository</localRepository>
26+
<servers>
27+
<server>
28+
<id>${cesFQDN}</id>
29+
<username>${USERNAME}</username>
30+
<password>${PASSWORD}</password>
31+
</server>
32+
</servers>
33+
<mirrors>
34+
<mirror>
35+
<id>${cesFQDN}</id>
36+
<name>${cesFQDN} Central Mirror</name>
37+
<url>https://${cesFQDN}/nexus/repository/itzbundshared/</url>
38+
<mirrorOf>central</mirrorOf>
39+
</mirror>
40+
</mirrors>
41+
</settings>"""
42+
}
43+
44+
try {
45+
closure.call(settingsXml)
46+
} finally {
47+
sh "rm -f ${settingsXml}"
48+
}
49+
}
50+
51+
def mvnWithSettings(def nexusCredentials, String cesFQDN, String mvnCallArgs) {
52+
def currentHome = env.HOME
53+
settings(nexusCredentials, cesFQDN, currentHome) { settingsXml ->
54+
mvn settingsXml, mvnCallArgs
55+
}
56+
}
57+
58+
/**
59+
* This method extracts the Maven 3 installation from Jenkins and calls Maven with the given settings.xml and Maven arguments
60+
*/
61+
def mvn(String settingsXml, String mvnCallArgs) {
62+
def mvnHome = tool 'M3'
63+
64+
mvnWithHome(mvnHome, settingsXml, mvnCallArgs)
65+
}
66+
67+
def customMvnWithSettings(def nexusCredentials, String cesFQDN, String mvnHome, String pathToLocalMavenRepository, String mvnCallArgs) {
68+
settings(nexusCredentials, cesFQDN, pathToLocalMavenRepository) { settingsXml ->
69+
mvnWithHome(mvnHome, settingsXml, mvnCallArgs)
70+
}
71+
}
72+
73+
def mvnWithHome(String mvnHome, String settingsXml, String mvnCallArgs) {
74+
sh "${mvnHome}/bin/mvn -s ${settingsXml} --batch-mode -V -U -e -Dsurefire.useFile=false ${mvnCallArgs}"
75+
}

vars/withMavenSettings.txt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Provides sophisticated Maven support for custom `settings.xml` files which refer to a central maven mirror in the
2+
context of a Cloudogu EcoSystem. This global variable writes custom `settings.xml` files and can additionally invoke a
3+
provided or custom Maven call.
4+
5+
Any `settings.xml` being writting will be removed once the settings body is left.
6+
7+
Once written, the `settings.xml`'s structure will look like this:
8+
9+
|
10+
+->settings
11+
| +-> localRepository
12+
| `-> servers
13+
| `-> server
14+
| +-> id (generated with FQDN)
15+
| +-> username (taken from credentials)
16+
| `-> password (taken from credentials)
17+
|
18+
`-> mirrors
19+
`-> mirror
20+
+-> id (reference to the server id)
21+
+-> name (generated from FQDN)
22+
+-> url (generated from FQDN)
23+
+-> mirrorOf (fixed value of central maven mirror)
24+
25+
Example call:
26+
27+
nexusCreds = usernamePassword(credentialsId: 'jenkinsNexusServiceUser', passwordVariable: 'PASSWORD', usernameVariable: 'USERNAME')
28+
withMavenSettings.mvnWithSettings(nexusCreds, 'cesinstance.stage.host.tld', '/usr/share/maven') { settingsXml ->
29+
// do something with the settings.xml here
30+
} // settings.xml will be removed automatically
31+
32+
Example call with included Maven call:
33+
34+
withMavenSettings.mvnWithSettings(nexusCreds, 'cesinstance.stage.host.tld', 'yourMavenGoal')
35+
36+
- settings(def nexusCredentials, String cesFQDN, String pathToLocalMavenRepository, Closure closure) - Writes a
37+
`settings.xml` file with the given Nexus credentials and executes the closure body. This method provides a parameter
38+
`settingsXml` which contains the relative file path to the 'settings.xml' file.
39+
40+
- mvn(String settingsXml, String mvnCallArgs) - call the Jenkins Tool Maven with a provided `settings.xml`
41+
42+
- mvnWithSettings(def nexusCredentials, String cesFQDN, String mvnCallArgs) - call Jenkins Tool Maven wrapped within a
43+
settings file. This is basically a convenience mix of `settings` and `mvn`
44+
45+
- customMvnWithSettings(def nexusCredentials, String cesFQDN, String mvnHome, String pathToLocalMavenRepository, String mvnCallArgs) -
46+
similar to `mvnWithSettings` but calls a custom Maven installation instead. It is necessary to know about the location of
47+
the Maven installation. Calling this method can make sense if the Maven installation resides in a Docker container.

0 commit comments

Comments
 (0)