Skip to content

Commit 1e8e7da

Browse files
committed
Add a utility for copying files.
1 parent 17fb01a commit 1e8e7da

File tree

3 files changed

+98
-22
lines changed

3 files changed

+98
-22
lines changed

examples/src/main/java/io/kubernetes/client/examples/CopyExample.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
import io.kubernetes.client.Configuration;
1919
import io.kubernetes.client.Copy;
2020
import io.kubernetes.client.util.Config;
21-
2221
import java.io.IOException;
2322
import java.io.InputStream;
23+
import java.nio.file.Paths;
2424

2525
/**
2626
* A simple example of how to use the Java API
@@ -39,8 +39,11 @@ public static void main(String[] args) throws IOException, ApiException, Interru
3939
Configuration.setDefaultApiClient(client);
4040

4141
Copy copy = new Copy();
42-
InputStream dataStream = copy.copyFile(namespace, podName, "/etc/motd");
43-
42+
InputStream dataStream = copy.copyFileFromPod(namespace, podName, "/etc/motd");
4443
ByteStreams.copy(dataStream, System.out);
44+
45+
copy.copyDirectoryFromPod(namespace, podName, null, "/etc", Paths.get("/tmp/etc"));
46+
47+
System.out.println("Done!");
4548
}
4649
}

util/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
<artifactId>commons-codec</artifactId>
3333
<version>1.11</version>
3434
</dependency>
35+
<dependency>
36+
<groupId>org.apache.commons</groupId>
37+
<artifactId>commons-compress</artifactId>
38+
<version>1.18</version>
39+
</dependency>
3540
<dependency>
3641
<groupId>org.apache.commons</groupId>
3742
<artifactId>commons-lang3</artifactId>

util/src/main/java/io/kubernetes/client/Copy.java

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@
1414

1515
import com.google.common.io.ByteStreams;
1616
import io.kubernetes.client.models.V1Pod;
17-
import java.io.ByteArrayInputStream;
18-
import java.io.ByteArrayOutputStream;
17+
import java.io.BufferedInputStream;
18+
import java.io.File;
1919
import java.io.FileOutputStream;
2020
import java.io.IOException;
2121
import java.io.InputStream;
22+
import java.io.OutputStream;
2223
import java.nio.file.Path;
23-
import org.apache.commons.codec.binary.Base64;
24+
import org.apache.commons.codec.binary.Base64InputStream;
25+
import org.apache.commons.compress.archivers.ArchiveEntry;
26+
import org.apache.commons.compress.archivers.ArchiveInputStream;
27+
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
2428
import org.slf4j.Logger;
2529
import org.slf4j.LoggerFactory;
2630

@@ -41,22 +45,22 @@ public Copy(ApiClient apiClient) {
4145
super(apiClient);
4246
}
4347

44-
public InputStream copyFile(String namespace, String pod, String srcPath)
48+
public InputStream copyFileFromPod(String namespace, String pod, String srcPath)
4549
throws ApiException, IOException {
46-
return copyFile(namespace, pod, null, srcPath);
50+
return copyFileFromPod(namespace, pod, null, srcPath);
4751
}
4852

49-
public InputStream copyFile(V1Pod pod, String srcPath) throws ApiException, IOException {
50-
return copyFile(pod, null, srcPath);
53+
public InputStream copyFileFromPod(V1Pod pod, String srcPath) throws ApiException, IOException {
54+
return copyFileFromPod(pod, null, srcPath);
5155
}
5256

53-
public InputStream copyFile(V1Pod pod, String container, String srcPath)
57+
public InputStream copyFileFromPod(V1Pod pod, String container, String srcPath)
5458
throws ApiException, IOException {
55-
return copyFile(
59+
return copyFileFromPod(
5660
pod.getMetadata().getNamespace(), pod.getMetadata().getName(), container, srcPath);
5761
}
5862

59-
public InputStream copyFile(String namespace, String pod, String container, String srcPath)
63+
public InputStream copyFileFromPod(String namespace, String pod, String container, String srcPath)
6064
throws ApiException, IOException {
6165
Process proc =
6266
this.exec(
@@ -66,21 +70,85 @@ public InputStream copyFile(String namespace, String pod, String container, Stri
6670
container,
6771
false,
6872
false);
69-
try {
70-
proc.waitFor();
71-
} catch (InterruptedException ex) {
72-
log.warn("Interrupted waiting for copy to complete", ex);
73+
return new Base64InputStream(proc.getInputStream());
74+
}
75+
76+
public void copyFileFromPod(
77+
String namespace, String name, String container, String srcPath, Path destination)
78+
throws ApiException, IOException {
79+
try (InputStream is = copyFileFromPod(namespace, name, srcPath);
80+
FileOutputStream fos = new FileOutputStream(destination.toFile())) {
81+
ByteStreams.copy(is, fos);
82+
fos.flush();
7383
}
74-
ByteArrayOutputStream bos = new ByteArrayOutputStream();
75-
ByteStreams.copy(proc.getInputStream(), bos);
84+
}
7685

77-
return new ByteArrayInputStream(Base64.decodeBase64(bos.toByteArray()));
86+
public void copyDirectoryFromPod(V1Pod pod, String srcPath, Path destination)
87+
throws ApiException, IOException {
88+
copyDirectoryFromPod(pod, null, srcPath, destination);
89+
}
90+
91+
public void copyDirectoryFromPod(V1Pod pod, String container, String srcPath, Path destination)
92+
throws ApiException, IOException {
93+
copyDirectoryFromPod(
94+
pod.getMetadata().getNamespace(),
95+
pod.getMetadata().getName(),
96+
container,
97+
srcPath,
98+
destination);
99+
}
100+
101+
public void copyDirectoryFromPod(String namespace, String pod, String srcPath, Path destination)
102+
throws ApiException, IOException {
103+
copyDirectoryFromPod(namespace, pod, null, srcPath, destination);
104+
}
105+
106+
public void copyDirectoryFromPod(
107+
String namespace, String pod, String container, String srcPath, Path destination)
108+
throws ApiException, IOException {
109+
// TODO: Test that 'tar' is present in the container?
110+
final Process proc =
111+
this.exec(
112+
namespace,
113+
pod,
114+
new String[] {"sh", "-c", "tar cf - " + srcPath + " | base64"},
115+
container,
116+
false,
117+
false);
118+
InputStream is = new Base64InputStream(new BufferedInputStream(proc.getInputStream()));
119+
try (ArchiveInputStream archive =
120+
new TarArchiveInputStream(is)) { // new GzipCompressorInputStream(is))) {
121+
for (ArchiveEntry entry = archive.getNextEntry();
122+
entry != null;
123+
entry = archive.getNextEntry()) {
124+
if (!archive.canReadEntryData(entry)) {
125+
log.error("Can't read: " + entry);
126+
continue;
127+
}
128+
File f = new File(destination.toFile(), entry.getName());
129+
if (entry.isDirectory()) {
130+
if (!f.isDirectory() && !f.mkdirs()) {
131+
throw new IOException("create directory failed: " + f);
132+
}
133+
} else {
134+
File parent = f.getParentFile();
135+
if (!parent.isDirectory() && !parent.mkdirs()) {
136+
throw new IOException("create directory failed: " + parent);
137+
}
138+
try (OutputStream fs = new FileOutputStream(f)) {
139+
System.out.println("Writing: " + f.getCanonicalPath());
140+
ByteStreams.copy(archive, fs);
141+
fs.flush();
142+
}
143+
}
144+
}
145+
}
78146
}
79147

80-
public static void copyFile(String namespace, String pod, String srcPath, Path dest)
148+
public static void copyFileFromPod(String namespace, String pod, String srcPath, Path dest)
81149
throws ApiException, IOException {
82150
Copy c = new Copy();
83-
InputStream is = c.copyFile(namespace, pod, null, srcPath);
151+
InputStream is = c.copyFileFromPod(namespace, pod, null, srcPath);
84152
FileOutputStream os = new FileOutputStream(dest.toFile());
85153
ByteStreams.copy(is, os);
86154
os.flush();

0 commit comments

Comments
 (0)