-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor configuration build/push/tar build steps to reduce duplicate code #269
Conversation
…lLoadDockerSteps, and PushImageStep; allow adding blobs to TarStreamBuilder
@@ -32,7 +30,7 @@ | |||
import java.util.concurrent.Future; | |||
|
|||
/** Builds the container configuration. */ | |||
class BuildContainerConfigurationStep implements Callable<ListenableFuture<Blob>> { | |||
class BuildContainerConfigurationStep implements Callable<ListenableFuture<Image>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BuildImageStep
now?
pushBaseImageLayerFuturesFuture, pushContainerConfigurationFutureFuture) | ||
pushBaseImageLayerFuturesFuture, | ||
pushContainerConfigurationFutureFuture, | ||
buildContainerConfigurationFutureFuture) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dependency on buildContainerConfigurationFutureFuture
shouldn't be necessary since pushContainerConfigurationFutureFuture
already depends on it.
@@ -61,6 +68,17 @@ public void addEntry(TarArchiveEntry entry) { | |||
entries.add(entry); | |||
} | |||
|
|||
/** Adds a blob to the archive. */ | |||
public void addEntry(Blob blob, String name) throws IOException { | |||
// TODO: Efficiency? We're writing blob contents twice (once here to get entry size, once when |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think you could do it by creating a class that encompasses either a file or a blob and a name, and it has a method to write it to a TarArchiveOutputStream with the right TarArchiveEntry and contents.
@@ -29,8 +29,8 @@ | |||
import java.util.concurrent.ExecutionException; | |||
import java.util.concurrent.Future; | |||
|
|||
/** Builds the container configuration. */ | |||
class BuildContainerConfigurationStep implements Callable<ListenableFuture<Image>> { | |||
/** Builds the container image. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually the {@link Image}
class, which is a model for the container image.
@@ -87,18 +87,19 @@ private Void afterPushBaseImageLayerFuturesFuture() | |||
DockerLoadManifestTemplate manifestTemplate = new DockerLoadManifestTemplate(); | |||
for (Layer layer : image.getLayers()) { | |||
String layerName = layer.getBlobDescriptor().getDigest() + ".tar.gz"; | |||
tarStreamBuilder.addEntry(layer.getBlob(), layerName); | |||
tarStreamBuilder.addEntry(Blobs.writeToByteArray(layer.getBlob()), layerName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should use the cached content file so that we're not storing the files in memory.
// TODO: Efficiency? We're writing blob contents twice (once here to get entry size, once when | ||
// writing to TarArchiveOutputStream). | ||
byte[] bytes = Blobs.writeToByteArray(blob); | ||
public void addEntry(byte[] contents, String name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we generally want to avoid using a raw byte[]
, so String would prob be better here.
@@ -145,10 +144,10 @@ public void run() | |||
|
|||
timer2.lap("Setting up build container configuration"); | |||
// Builds the container configuration. | |||
ListenableFuture<ListenableFuture<Blob>> buildContainerConfigurationFutureFuture = | |||
ListenableFuture<ListenableFuture<Image>> buildContainerConfigurationFutureFuture = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/buildContainerConfigurationFutureFuture/buildImageFutureFuture
private final BuildConfiguration buildConfiguration; | ||
private final ListeningExecutorService listeningExecutorService; | ||
private final ListenableFuture<List<ListenableFuture<CachedLayer>>> | ||
pullBaseImageLayerFuturesFuture; | ||
private final List<ListenableFuture<CachedLayer>> buildApplicationLayerFutures; | ||
private final ListenableFuture<ListenableFuture<Blob>> buildConfigurationFutureFuture; | ||
private final ListenableFuture<ListenableFuture<Image>> buildConfigurationFutureFuture; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buildImageFutureFuture
|
||
BuildTarballAndLoadDockerStep( | ||
BuildConfiguration buildConfiguration, | ||
ListeningExecutorService listeningExecutorService, | ||
ListenableFuture<List<ListenableFuture<CachedLayer>>> pullBaseImageLayerFuturesFuture, | ||
List<ListenableFuture<CachedLayer>> buildApplicationLayerFutures, | ||
ListenableFuture<ListenableFuture<Blob>> buildConfigurationFutureFuture) { | ||
ListenableFuture<ListenableFuture<Image>> buildConfigurationFutureFuture) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buildImageFutureFuture
@@ -124,10 +123,10 @@ public void run() | |||
|
|||
timer2.lap("Setting up build container configuration"); | |||
// Builds the container configuration. | |||
ListenableFuture<ListenableFuture<Blob>> buildContainerConfigurationFutureFuture = | |||
ListenableFuture<ListenableFuture<Image>> buildContainerConfigurationFutureFuture = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buildImageFutureFuture
DockerLoadManifestTemplate manifestTemplate = new DockerLoadManifestTemplate(); | ||
|
||
for (Layer layer : image.getLayers()) { | ||
Path cachedFile = ((CachedLayer) layer).getContentFile(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like we should actually change Image
to only hold and return CachedLayer
s so that we don't have to do the cast here, but that change could prob go in a TODO/separate issue/PR.
/** Writes each entry in the filesystem to the tarball archive stream. */ | ||
private static void writeEntriesAsTarArchive( | ||
List<TarArchiveEntry> entries, OutputStream tarByteStream) throws IOException { | ||
/** Map of TarArchiveEntries and their corresponding content as output stream consumers. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe phrase like:
Maps from {@link TarArchiveEntry} to function that outputs the entry onto a {@link TarArchiveOutputStream}. The order of the entries is the order they belong in the tarball.
private static void writeEntriesAsTarArchive( | ||
List<TarArchiveEntry> entries, OutputStream tarByteStream) throws IOException { | ||
/** Map of TarArchiveEntries and their corresponding content as output stream consumers. */ | ||
private final LinkedHashMap<TarArchiveEntry, TarArchiveOutputStreamConsumer> blobContents = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
archiveMap
?
tarArchiveOutputStream -> { | ||
if (entry.isFile()) { | ||
try (InputStream contentStream = | ||
new BufferedInputStream(new FileInputStream(entry.getFile()))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Files.newInputStream
} | ||
|
||
/** Adds a blob to the archive. */ | ||
public void addEntry(String contents, String name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should add a test for this case.
tarStreamBuilder.addEntry( | ||
new TarArchiveEntry(layerFile.toFile(), layerFile.getFileName().toString())); | ||
} | ||
DockerLoadManifestTemplate manifestTemplate = new DockerLoadManifestTemplate(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prob make a TODO/file an issue to refactor this tar building to a separate class specifically for building a Docker image tar so that it is unit-testable. Generally, these async steps should be kept as minimal as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like #261 is this.
public void testToBlob_tarArchiveEntries() throws IOException { | ||
setUpWithTarEntries(); | ||
|
||
Blob blob = testTarStreamBuilder.toBlob(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like all these verification methods are the same for each test - can put right into verifyTarArchive
.
} | ||
|
||
/** Creates a TarStreamBuilder using Strings. */ | ||
private void setUpWithStrings() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more with both files and strings would be good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to go! 👍
} | ||
|
||
/** Creates a compressed blob from the TarStreamBuilder and verifies it. */ | ||
private void verifyBlobWithCompression() throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine since it's just a test helper, but since theres only two line difference between these functions, it could just be one function with a parameter "compress". Then, like line 140 could be blob.writeTo(compress?new GZIPOutputStream(tarByteOutputStream):tarByteOutputStream)
.
Part of #262 (refactors
BuildContainerConfigurationStep
,BuildTarballLoadDockerStep
, andPushImageStep
).Fixes #263 (adds ability to add blobs to
TarStreamBuilder
without temp files).