Skip to content

Commit b9d1af1

Browse files
authored
Docker Extractor (#373)
1 parent 8f05816 commit b9d1af1

File tree

23 files changed

+1174
-38
lines changed

23 files changed

+1174
-38
lines changed

README.md

+27-14
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
## Overview
44

5-
Build Info is Artifactory's open integration layer for the CI servers and build tools.
6-
The build information is sent to Artifactory in json format.
5+
Build Info is Artifactory's open integration layer for the CI servers and build tools. The build information is sent to Artifactory in json format.
76

87
## Building and testing the sources
98

@@ -22,15 +21,15 @@ export BITESTS_ARTIFACTORY_PIP_ENV=/Users/user/venv-test/bin
2221
### Building
2322
When running the following commands to build the code, the entire testing suite is also executed. See the *Testing* section for configuration instructions prior to running the tests.
2423

25-
To build the code using the gradle wrapper in Unix run:
24+
To build the code using the gradle wrapper in Unix run:
2625
```
2726
> ./gradlew clean build
2827
```
29-
To build the code using the gradle wrapper in Windows run:
28+
To build the code using the gradle wrapper in Windows run:
3029
```
3130
> gradlew clean build
3231
```
33-
To build the code using the environment gradle run:
32+
To build the code using the environment gradle run:
3433
```
3534
> gradle clean build
3635
```
@@ -40,7 +39,7 @@ To build the code without running the tests, add to the "clean build" command th
4039
```
4140

4241
### Testing
43-
To run *all* tests:
42+
To run *all* tests:
4443
```
4544
> ./gradlew clean test
4645
```
@@ -74,8 +73,8 @@ To run *all* tests:
7473

7574
#### Pip tests
7675
* Add Python and pip executables to the system search path (PATH environment variable).
77-
* Pip tests must run inside a clean pip-environment. Create a virtual environment and provide its path using the 'BITESTS_ARTIFACTORY_PIP_ENV' variable.
78-
When running on a Windows machine, provide the path to the 'Scripts' directory.
76+
* Pip tests must run inside a clean pip-environment. Create a virtual environment and provide its path using the 'BITESTS_ARTIFACTORY_PIP_ENV' variable.
77+
When running on a Windows machine, provide the path to the 'Scripts' directory.
7978
When running on a unix machine, provide the path to the 'bin' directory.
8079
```
8180
> python -m venv buildinfo-tests-env
@@ -89,6 +88,20 @@ When running on a unix machine, provide the path to the 'bin' directory.
8988
> ./gradlew clean build-info-extractor-nuget:test
9089
```
9190

91+
#### Docker tests
92+
* Docker tests run only on Linux/mac.
93+
* In addition to the general environment variables required for running the tests, you must set the following environment variables, required for the docker tests:
94+
95+
```
96+
export BITESTS_ARTIFACTORY_DOCKER_DOMAIN='server-build-info-tests-docker.jfrog.io/'
97+
export BITESTS_ARTIFACTORY_DOCKER_REPO=build-info-tests-docker
98+
export BITESTS_ARTIFACTORY_DOCKER_HOST=tcp://127.0.0.1:1234
99+
```
100+
```
101+
> ./gradlew clean build-info-extractor-docker:test
102+
```
103+
* Before running the tests, please make sure you have a local docker repository named *build-info-tests-docker* in Artifactory.
104+
92105
### Testing on Artifactory OSS
93106
When testing with an instance of Artifactory OSS, only supported tests are for the build-info-gradle-extractor.
94107

@@ -103,7 +116,7 @@ To run Gradle tests on Artifactory OSS:
103116
* Create 3 Gradle repositories:
104117
* Local repository: `build-info-tests-gradle-local`
105118
* Remote repository to jcenter: `build-info-tests-gradle-remote`
106-
* Virtual repository containing both the remote and local: `build-info-tests-gradle-virtual`
119+
* Virtual repository containing both the remote and local: `build-info-tests-gradle-virtual`
107120
* Run tests `./gradlew build-info-extractor-gradle:test`
108121

109122
## Build Info json format
@@ -140,7 +153,7 @@ To run Gradle tests on Artifactory OSS:
140153
}],
141154
"licenseControl" : { // Artifactory License Control information
142155
"runChecks" : true, // Artifactory will run automatic license scanning after the build is complete (true/false)
143-
"includePublishedArtifacts" : true, // Should Artifactory run license checks on the build artifacts, in addition to the build dependecies (true/false)
156+
"includePublishedArtifacts" : true, // Should Artifactory run license checks on the build artifacts, in addition to the build dependecies (true/false)
144157
"autoDiscover" : true, // Should Artifactory auto discover licenses (true/false)
145158
"scopesList" : "", // A space-separated list of dependency scopes/configurations to run license violation checks on. If left empty all dependencies from all scopes will be checked.
146159
"licenseViolationsRecipientsList" : "" // Emails of recipients that should be notified of license violations in the build info (space-separated list)
@@ -151,7 +164,7 @@ To run Gradle tests on Artifactory OSS:
151164
"minimumBuildDate" : 1407345768020, // Earliest build date to store in Artifactory
152165
"buildNumbersNotToBeDiscarded" : [ ] // List of build numbers that should not be removed from Artifactory
153166
},
154-
/* List of build modules */
167+
/* List of build modules */
155168
"modules" : [ { // The build's first module
156169
"properties" : { // Module properties
157170
"project.build.sourceEncoding" : "UTF-8"
@@ -182,7 +195,7 @@ To run Gradle tests on Artifactory OSS:
182195
"project.build.sourceEncoding" : "UTF-8"
183196
},
184197
"id" : "org.jfrog.test:multi3:4.2-SNAPSHOT", // Module ID
185-
/* List of module artifacts */
198+
/* List of module artifacts */
186199
"artifacts" : [ { // Module artifacts
187200
"type" : "war",
188201
"sha1" : "df8e7d7b94d5ec9db3bfc92e945c7ff4e2391c7c",
@@ -233,8 +246,8 @@ To run Gradle tests on Artifactory OSS:
233246
"url" : "https://www.jfrog.com/jira/browse/RTFACT-5678",
234247
"summary" : "Description of the relevant issue",
235248
"aggregated" : true
236-
} ]
237-
},
249+
} ]
250+
},
238251
"governance" : { // Black Duck Code Center integration information
239252
"blackDuckProperties" : {
240253
"appName" : "", // The Black Duck Code Center application name

appveyor.yml

+14-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ environment:
1010
secure: Um8o75MQIieSavIemF4ySA==
1111
BITESTS_ARTIFACTORY_REPO:
1212
secure: Xf371RQAxCTMn/S7NdmV8g==
13+
BITESTS_ARTIFACTORY_DOCKER_DOMAIN:
14+
secure: AoaKTKtH3eL36SmENsm51eRFVLU/BGIK+CrBvmsCqO35j3xM9++4E01YWs5CsfXy
15+
BITESTS_ARTIFACTORY_DOCKER_REPO:
16+
secure: KL72XB/1EBaModiGGpJF9Ge+wdbLmrDwT1lmy28YRiM=
1317

1418
matrix:
1519
# Extractor Tests
@@ -110,16 +114,21 @@ environment:
110114
TEST_SUIT:
111115
"./gradlew clean build-info-extractor-nuget:test"
112116

117+
# Docker Tests
118+
- job_name: docker_extractor_linux
119+
job_group: general
120+
appveyor_build_worker_image: Ubuntu
121+
TEST_SUIT:
122+
"./gradlew clean build-info-extractor-docker:test"
123+
113124
for:
114-
-
115-
matrix:
125+
- matrix:
116126
only:
117127
- job_group: general
118128
test_script:
119129
- sh: "$TEST_SUIT"
120130
- cmd: "%TEST_SUIT%"
121-
-
122-
matrix:
131+
- matrix:
123132
only:
124133
- job_group: pip
125134
test_script:
@@ -129,4 +138,4 @@ for:
129138
- cmd: "C:\\Python37-x64\\python -m venv pip-venv"
130139
- cmd: "%TEST_SUIT%"
131140

132-
build: off
141+
build: off

build-info-api/src/main/java/org/jfrog/build/api/builder/ArtifactBuilder.java

+15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.commons.lang.StringUtils;
2020
import org.jfrog.build.api.Artifact;
2121

22+
import java.util.Map;
2223
import java.util.Properties;
2324

2425
/**
@@ -164,4 +165,18 @@ public ArtifactBuilder addProperty(Object key, Object value) {
164165
properties.put(key, value);
165166
return this;
166167
}
168+
169+
/**
170+
* Adds properties to the properties object
171+
*
172+
* @param properties Artifact properties
173+
* @return Builder instance
174+
*/
175+
public ArtifactBuilder addProperties(Properties properties) {
176+
if (this.properties == null) {
177+
this.properties = new Properties();
178+
}
179+
this.properties.putAll(properties);
180+
return this;
181+
}
167182
}

build-info-api/src/main/java/org/jfrog/build/api/builder/DependencyBuilder.java

+15-4
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@
1919
import com.google.common.collect.Lists;
2020
import org.jfrog.build.api.Dependency;
2121

22-
import java.util.HashSet;
23-
import java.util.List;
24-
import java.util.Properties;
25-
import java.util.Set;
22+
import java.util.*;
2623

2724
/**
2825
* A builder for the dependency class
@@ -214,4 +211,18 @@ public DependencyBuilder addProperty(Object key, Object value) {
214211
properties.put(key, value);
215212
return this;
216213
}
214+
215+
/**
216+
* Adds properties to the properties object
217+
*
218+
* @param properties Dependencies properties
219+
* @return Builder instance
220+
*/
221+
public DependencyBuilder addProperties(Properties properties) {
222+
if (this.properties == null) {
223+
this.properties = new Properties();
224+
}
225+
this.properties.putAll(properties);
226+
return this;
227+
}
217228
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package org.jfrog.build.extractor.docker;
2+
3+
import com.github.dockerjava.api.DockerClient;
4+
import com.github.dockerjava.api.command.BuildImageCmd;
5+
import com.github.dockerjava.api.model.AuthConfig;
6+
import com.github.dockerjava.core.DefaultDockerClientConfig;
7+
import com.github.dockerjava.core.DockerClientBuilder;
8+
import com.github.dockerjava.core.DockerClientConfig;
9+
import com.github.dockerjava.core.command.BuildImageResultCallback;
10+
import com.github.dockerjava.core.command.PullImageResultCallback;
11+
import com.github.dockerjava.core.command.PushImageResultCallback;
12+
import com.github.dockerjava.netty.NettyDockerCmdExecFactory;
13+
import org.apache.commons.lang.StringUtils;
14+
import org.jfrog.build.api.util.Log;
15+
16+
import java.io.IOException;
17+
import java.nio.file.Paths;
18+
import java.util.Arrays;
19+
import java.util.HashSet;
20+
import java.util.Map;
21+
22+
public class DockerJavaWrapper {
23+
24+
/**
25+
* Push docker image using the docker java client.
26+
*
27+
* @param imageTag
28+
* @param username
29+
* @param password
30+
* @param host
31+
* @param envVars
32+
*/
33+
public static void pushImage(String imageTag, String username, String password, String host, Map<String, String> envVars, Log logger) {
34+
final AuthConfig authConfig = new AuthConfig();
35+
authConfig.withUsername(username);
36+
authConfig.withPassword(password);
37+
DockerClient dockerClient = null;
38+
try {
39+
dockerClient = getDockerClient(host, envVars);
40+
dockerClient.pushImageCmd(imageTag).withAuthConfig(authConfig).exec(new PushImageResultCallback()).awaitSuccess();
41+
} finally {
42+
closeQuietly(dockerClient, logger);
43+
}
44+
}
45+
46+
/**
47+
* Gets the docker java client.
48+
*
49+
* @param host - Docker daemon ip.
50+
* @param envVars - System env variables.
51+
* @return
52+
*/
53+
public static DockerClient getDockerClient(String host, Map<String, String> envVars) {
54+
if (envVars == null) {
55+
throw new IllegalStateException("envVars must not be null");
56+
}
57+
DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder();
58+
if (envVars.containsKey(DefaultDockerClientConfig.DOCKER_HOST)) {
59+
configBuilder.withDockerHost(envVars.get(DefaultDockerClientConfig.DOCKER_HOST));
60+
} else {
61+
// If open JDK is used and the host is null
62+
// then instead of a null reference, the host is the string "null".
63+
if (!StringUtils.isEmpty(host) && !host.equalsIgnoreCase("null")) {
64+
configBuilder.withDockerHost(host);
65+
}
66+
}
67+
if (envVars.containsKey(DefaultDockerClientConfig.DOCKER_TLS_VERIFY)) {
68+
configBuilder.withDockerTlsVerify(envVars.get(DefaultDockerClientConfig.DOCKER_TLS_VERIFY));
69+
}
70+
if (envVars.containsKey(DefaultDockerClientConfig.DOCKER_CERT_PATH)) {
71+
configBuilder.withDockerCertPath(envVars.get(DefaultDockerClientConfig.DOCKER_CERT_PATH));
72+
}
73+
74+
DockerClientConfig config = configBuilder.build();
75+
return DockerClientBuilder.getInstance(config).withDockerCmdExecFactory(new NettyDockerCmdExecFactory()).build();
76+
}
77+
78+
/**
79+
* Get image Id from imageTag using DockerClient.
80+
*
81+
* @param imageTag
82+
* @param host
83+
* @param envVars
84+
* @return
85+
*/
86+
public static String getImageIdFromTag(String imageTag, String host, Map<String, String> envVars, Log logger) {
87+
DockerClient dockerClient = null;
88+
try {
89+
dockerClient = getDockerClient(host, envVars);
90+
return dockerClient.inspectImageCmd(imageTag).exec().getId();
91+
} finally {
92+
closeQuietly(dockerClient, logger);
93+
}
94+
}
95+
96+
private static void closeQuietly(DockerClient dockerClient, Log logger) {
97+
if (dockerClient != null) {
98+
try {
99+
dockerClient.close();
100+
} catch (IOException e) {
101+
logger.error("Closes docker client failed.");
102+
}
103+
}
104+
}
105+
106+
/**
107+
* Execute pull docker image on agent.
108+
*
109+
* @param imageTag
110+
* @param username
111+
* @param password
112+
* @param host
113+
* @param envVars
114+
*/
115+
public static void pullImage(final String imageTag, String username, String password, String host, Map<String, String> envVars, Log logger) {
116+
final AuthConfig authConfig = new AuthConfig();
117+
authConfig.withUsername(username);
118+
authConfig.withPassword(password);
119+
DockerClient dockerClient = null;
120+
try {
121+
dockerClient = getDockerClient(host, envVars);
122+
dockerClient.pullImageCmd(imageTag).withAuthConfig(authConfig).exec(new PullImageResultCallback()).awaitSuccess();
123+
} finally {
124+
closeQuietly(dockerClient, logger);
125+
}
126+
}
127+
128+
/**
129+
* Build a docker image from docker file.
130+
*
131+
* @param imageName - The image ID of the result docker build
132+
* @param host - Docker daemon ip.
133+
* @param envVars - System env variables.
134+
* @param projectPath - Location of the docker file
135+
*/
136+
public static void buildImage(String imageName, String host, Map<String, String> envVars, String projectPath) {
137+
DockerClient dockerClient = DockerJavaWrapper.getDockerClient(host, envVars);
138+
// Build the docker image with the name provided from env.
139+
BuildImageCmd buildImageCmd = dockerClient.buildImageCmd(Paths.get(projectPath).toFile()).withTags(new HashSet<>(Arrays.asList(imageName)));
140+
buildImageCmd.exec(new BuildImageResultCallback()).awaitImageId();
141+
}
142+
}

0 commit comments

Comments
 (0)