Skip to content

Commit 465a935

Browse files
committed
Issue docker-java#2: fixed tarFile deleteOnExit. Now tmp tar file is removed after POST is completed
Now docker builder correctly parses ADD command in Dockerfile.
1 parent b81c6e4 commit 465a935

File tree

7 files changed

+193
-45
lines changed

7 files changed

+193
-45
lines changed

src/main/java/com/kpelykh/docker/client/DockerClient.java

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,9 @@
77
import com.sun.jersey.api.client.*;
88
import com.sun.jersey.api.client.config.ClientConfig;
99
import com.sun.jersey.api.client.config.DefaultClientConfig;
10-
import com.sun.jersey.api.client.filter.LoggingFilter;
1110
import com.sun.jersey.api.json.JSONConfiguration;
1211
import com.sun.jersey.client.apache4.ApacheHttpClient4;
1312
import com.sun.jersey.core.util.MultivaluedMapImpl;
14-
import com.sun.jersey.multipart.FormDataMultiPart;
15-
import com.sun.jersey.multipart.file.FileDataBodyPart;
1613
import org.apache.commons.io.FileUtils;
1714
import org.apache.commons.lang.StringUtils;
1815
import org.codehaus.jettison.json.JSONException;
@@ -427,13 +424,18 @@ public ClientResponse logContainer(String containerId) throws DockerException {
427424
params.add("logs", "1");
428425
params.add("stdout", "1");
429426
params.add("stderr", "1");
427+
//params.add("stream", "1");
428+
429+
Client client = Client.create();
430+
ClientConfig clientConfig = new DefaultClientConfig();
431+
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
430432

431433
WebResource webResource = client.resource(restEndpointUrl + String.format("/containers/%s/attach", containerId))
432434
.queryParams(params);
433435

434436
try {
435437
LOGGER.trace("POST: " + webResource.toString());
436-
return webResource.accept("application/vnd.docker.raw-stream").post(ClientResponse.class, params);
438+
return webResource.accept(MediaType.APPLICATION_OCTET_STREAM_TYPE).post(ClientResponse.class, params);
437439
} catch (UniformInterfaceException exception) {
438440
if (exception.getResponse().getStatus() == 400) {
439441
throw new DockerException("bad parameter");
@@ -571,6 +573,9 @@ public ClientResponse build(File dockerFolder) throws DockerException {
571573
}
572574

573575
public ClientResponse build(File dockerFolder, String tag) throws DockerException {
576+
Preconditions.checkNotNull(dockerFolder, "Folder is null");
577+
Preconditions.checkArgument(dockerFolder.exists(), "Folder %s doesn't exist", dockerFolder);
578+
Preconditions.checkState(new File(dockerFolder, "Dockerfile").exists(), "Dockerfile doesn't exist in " + dockerFolder);
574579

575580
//We need to use Jersey HttpClient here, since ApacheHttpClient4 will not add boundary filed to
576581
//Content-Type: multipart/form-data; boundary=Boundary_1_372491238_1372806136625
@@ -579,19 +584,60 @@ public ClientResponse build(File dockerFolder, String tag) throws DockerExceptio
579584
ClientConfig clientConfig = new DefaultClientConfig();
580585
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
581586

582-
Preconditions.checkNotNull(dockerFolder, "Folder is null");
583-
Preconditions.checkArgument(dockerFolder.exists(), "Folder %s doesn't exist", dockerFolder);
584-
585587
MultivaluedMap<String,String> params = new MultivaluedMapImpl();
586588
params.add("t", tag);
587589

588590
// ARCHIVE TAR
589591
String archiveNameWithOutExtension = UUID.randomUUID().toString();
590-
File dockerFolderTar = CompressArchiveUtil.archiveTARFiles(dockerFolder, ".", archiveNameWithOutExtension);
591592

592-
WebResource webResource = client.resource(restEndpointUrl + "/build").queryParams(params);
593+
File dockerFolderTar = null;
594+
File tmpDockerContextFolder = null;
593595

594-
ClientResponse response;
596+
try {
597+
File dockerFile = new File(dockerFolder, "Dockerfile");
598+
List<String> dockerFileContent = FileUtils.readLines(dockerFile);
599+
600+
if (dockerFileContent.size() <= 0) {
601+
throw new DockerException(String.format("Dockerfile %s is empty", dockerFile));
602+
}
603+
604+
//Create tmp docker context folder
605+
tmpDockerContextFolder = new File(FileUtils.getTempDirectoryPath(), "docker-java-build" + archiveNameWithOutExtension);
606+
607+
FileUtils.copyFileToDirectory(dockerFile, tmpDockerContextFolder);
608+
609+
for (String cmd : dockerFileContent) {
610+
if (StringUtils.startsWithIgnoreCase(cmd.trim(), "ADD")) {
611+
String addArgs[] = StringUtils.split(cmd, " \t");
612+
if (addArgs.length != 3) {
613+
throw new DockerException(String.format("Wrong format on line [%s]", cmd));
614+
}
615+
616+
File src = new File(addArgs[1]);
617+
if (!src.isAbsolute()) {
618+
src = new File(dockerFolder, addArgs[1]).getCanonicalFile();
619+
}
620+
621+
if (!src.exists()) {
622+
throw new DockerException(String.format("Sorce file %s doesnt' exist", src));
623+
}
624+
if (src.isDirectory()) {
625+
FileUtils.copyDirectory(src, tmpDockerContextFolder);
626+
} else {
627+
FileUtils.copyFileToDirectory(src, tmpDockerContextFolder);
628+
}
629+
}
630+
}
631+
632+
dockerFolderTar = CompressArchiveUtil.archiveTARFiles(tmpDockerContextFolder, archiveNameWithOutExtension);
633+
634+
} catch (IOException ex) {
635+
FileUtils.deleteQuietly(dockerFolderTar);
636+
FileUtils.deleteQuietly(tmpDockerContextFolder);
637+
throw new DockerException("Error occurred while preparing Docker context folder.", ex);
638+
}
639+
640+
WebResource webResource = client.resource(restEndpointUrl + "/build").queryParams(params);
595641

596642
try {
597643
LOGGER.trace("POST: " + webResource.toString());
@@ -607,6 +653,9 @@ public ClientResponse build(File dockerFolder, String tag) throws DockerExceptio
607653
}
608654
} catch (IOException e) {
609655
throw new DockerException(e);
656+
} finally {
657+
FileUtils.deleteQuietly(dockerFolderTar);
658+
FileUtils.deleteQuietly(tmpDockerContextFolder);
610659
}
611660

612661
}

src/main/java/com/kpelykh/docker/client/utils/CompressArchiveUtil.java

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,58 @@
55
import java.io.FileInputStream;
66
import java.io.FileOutputStream;
77
import java.io.IOException;
8+
import java.util.Collection;
89

910
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
1011
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
1112
import org.apache.commons.io.FileUtils;
13+
import org.apache.commons.io.filefilter.RegexFileFilter;
14+
import org.apache.commons.lang.StringUtils;
15+
16+
import static org.apache.commons.io.filefilter.FileFilterUtils.*;
1217

1318
public class CompressArchiveUtil {
1419

15-
public static File archiveTARFiles(File baseDir, String dirToArchive, String archiveNameWithOutExtension) {
20+
public static File archiveTARFiles(File baseDir, String archiveNameWithOutExtension) throws IOException {
1621

1722
File tarFile = null;
1823

19-
try {
20-
File[] list = (new File(baseDir, dirToArchive)).listFiles();
21-
tarFile = new File(FileUtils.getTempDirectoryPath(), archiveNameWithOutExtension + ".tar");
22-
tarFile.deleteOnExit();
23-
24-
byte[] buf = new byte[1024];
25-
int len;
26-
27-
{
28-
TarArchiveOutputStream tos = new TarArchiveOutputStream(new FileOutputStream(tarFile));
29-
tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
30-
for (File file : list) {
31-
TarArchiveEntry tarEntry = new TarArchiveEntry(file.getName());
32-
tarEntry.setSize(file.length());
33-
34-
FileInputStream fin = new FileInputStream(file);
35-
BufferedInputStream in = new BufferedInputStream(fin);
36-
tos.putArchiveEntry(tarEntry);
37-
38-
while ((len = in.read(buf)) != -1) {
39-
tos.write(buf, 0, len);
40-
}
41-
42-
in.close();
43-
44-
tos.closeArchiveEntry();
45-
46-
}
47-
tos.close();
48-
}
49-
50-
} catch (IOException e) {
51-
e.printStackTrace();
52-
}
24+
tarFile = new File(FileUtils.getTempDirectoryPath(), archiveNameWithOutExtension + ".tar");
25+
26+
Collection<File> files =
27+
FileUtils.listFiles(
28+
baseDir,
29+
new RegexFileFilter("^(.*?)"),
30+
and(directoryFileFilter(), notFileFilter(nameFileFilter(baseDir.getName()))));
31+
32+
byte[] buf = new byte[1024];
33+
int len;
34+
35+
{
36+
TarArchiveOutputStream tos = new TarArchiveOutputStream(new FileOutputStream(tarFile));
37+
tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
38+
for (File file : files) {
39+
TarArchiveEntry tarEntry = new TarArchiveEntry(file);
40+
tarEntry.setName(StringUtils.substringAfter(file.toString(), baseDir.getPath()));
41+
42+
tos.putArchiveEntry(tarEntry);
43+
44+
if (!file.isDirectory()) {
45+
FileInputStream fin = new FileInputStream(file);
46+
BufferedInputStream in = new BufferedInputStream(fin);
47+
48+
while ((len = in.read(buf)) != -1) {
49+
tos.write(buf, 0, len);
50+
}
51+
52+
in.close();
53+
}
54+
tos.closeArchiveEntry();
55+
56+
}
57+
tos.close();
58+
}
59+
5360

5461
return tarFile;
5562
}

src/test/java/com/kpelykh/docker/client/test/DockerClientTest.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,18 @@ public void testNgixDockerfileBuilder() throws DockerException, IOException {
597597
assertThat(imageInspectResponse.author, equalTo("Guillaume J. Charmes \"guillaume@dotcloud.com\""));
598598
}
599599

600+
@Test
601+
public void testDockerBuilderAddFile() throws DockerException, IOException {
602+
File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddFile").getFile());
603+
dockerfileBuild(baseDir, "Successfully executed testrun.sh");
604+
}
605+
606+
@Test
607+
public void testDockerBuilderAddFolder() throws DockerException, IOException {
608+
File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("testAddFolder").getFile());
609+
dockerfileBuild(baseDir, "Successfully executed testAddFolder.sh");
610+
}
611+
600612
@Test
601613
public void testNetCatDockerfileBuilder() throws DockerException, IOException, InterruptedException {
602614
File baseDir = new File(Thread.currentThread().getContextClassLoader().getResource("netcat").getFile());
@@ -688,4 +700,58 @@ public static boolean available(int port) {
688700

689701
return false;
690702
}
703+
704+
private void dockerfileBuild(File baseDir, String expectedText) throws DockerException, IOException {
705+
706+
//Build image
707+
ClientResponse response = dockerClient.build(baseDir);
708+
709+
StringWriter logwriter = new StringWriter();
710+
711+
try {
712+
LineIterator itr = IOUtils.lineIterator(response.getEntityInputStream(), "UTF-8");
713+
while (itr.hasNext()) {
714+
String line = itr.next();
715+
logwriter.write(line + "\n");
716+
LOG.info(line);
717+
}
718+
} finally {
719+
IOUtils.closeQuietly(response.getEntityInputStream());
720+
}
721+
722+
String fullLog = logwriter.toString();
723+
assertThat(fullLog, containsString("Successfully built"));
724+
725+
String imageId = StringUtils.substringAfterLast(fullLog, "Successfully built ").trim();
726+
727+
//Create container based on image
728+
ContainerConfig containerConfig = new ContainerConfig();
729+
containerConfig.setImage(imageId);
730+
ContainerCreateResponse container = dockerClient.createContainer(containerConfig);
731+
LOG.info("Created container " + container.toString());
732+
assertThat(container.id, not(isEmptyString()));
733+
734+
dockerClient.startContainer(container.id);
735+
dockerClient.waitContainer(container.id);
736+
737+
tmpContainers.add(container.id);
738+
739+
//Log container
740+
ClientResponse logResponse = dockerClient.logContainer(container.id);
741+
742+
StringWriter logwriter2 = new StringWriter();
743+
744+
try {
745+
LineIterator itr = IOUtils.lineIterator(logResponse.getEntityInputStream(), "UTF-8");
746+
while (itr.hasNext()) {
747+
String line = itr.next();
748+
logwriter2.write(line + (itr.hasNext() ? "\n" : ""));
749+
LOG.info(line);
750+
}
751+
} finally {
752+
IOUtils.closeQuietly(logResponse.getEntityInputStream());
753+
}
754+
755+
assertThat(logwriter2.toString(), equalTo(expectedText));
756+
}
691757
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM ubuntu
2+
3+
# Copy testrun.sh files into the container
4+
5+
add ./testrun.sh /tmp/
6+
7+
run cp /tmp/testrun.sh /usr/local/bin/ && chmod +x /usr/local/bin/testrun.sh
8+
9+
CMD ["testrun.sh"]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
echo "Successfully executed testrun.sh"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM ubuntu
2+
3+
# Copy testrun.sh files into the container
4+
5+
add . /src/
6+
7+
run ls -la /src
8+
9+
run cp /src/folderA/testAddFolder.sh /usr/local/bin/ && chmod +x /usr/local/bin/testAddFolder.sh
10+
11+
CMD ["testAddFolder.sh"]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
echo "Successfully executed testAddFolder.sh"

0 commit comments

Comments
 (0)