From 0b82cf67d37d7996fcd1846f421a7090dad6eb38 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Wed, 20 Jun 2018 16:20:18 -0400 Subject: [PATCH 01/30] Add core changes for exposed port configuration --- .../tools/jib/builder/BuildConfiguration.java | 78 +++++++++++++++++++ .../jib/builder/steps/BuildImageStep.java | 1 + .../google/cloud/tools/jib/image/Image.java | 29 ++++++- .../json/ContainerConfigurationTemplate.java | 15 ++++ .../jib/image/json/ImageToJsonTranslator.java | 3 + .../jib/image/json/JsonToImageTranslator.java | 4 + .../cloud/tools/jib/json/EmptyStruct.java | 38 +++++++++ .../jib/builder/BuildConfigurationTest.java | 46 +++++++++++ .../jib/builder/steps/BuildImageStepTest.java | 2 + .../cloud/tools/jib/image/ImageTest.java | 7 ++ .../ContainerConfigurationTemplateTest.java | 15 ++++ .../image/json/ImageToJsonTranslatorTest.java | 11 +++ .../image/json/JsonToImageTranslatorTest.java | 11 +++ .../test/resources/json/containerconfig.json | 2 +- .../json/translated_ocimanifest.json | 2 +- .../json/translated_v22manifest.json | 2 +- 16 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 jib-core/src/main/java/com/google/cloud/tools/jib/json/EmptyStruct.java diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java index 4cf6996472..0d4a37ae79 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java @@ -19,14 +19,19 @@ import com.google.cloud.tools.jib.image.ImageReference; import com.google.cloud.tools.jib.image.json.BuildableManifestTemplate; import com.google.cloud.tools.jib.image.json.V22ManifestTemplate; +import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.registry.credentials.RegistryCredentials; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; import javax.annotation.Nullable; import javax.lang.model.SourceVersion; @@ -46,6 +51,7 @@ public static class Builder { private List javaArguments = new ArrayList<>(); private List jvmFlags = new ArrayList<>(); private Map environmentMap = new HashMap<>(); + private List exposedPorts = new ArrayList<>(); private Class targetFormat = V22ManifestTemplate.class; private BuildLogger buildLogger; @@ -112,6 +118,13 @@ public Builder setEnvironment(@Nullable Map environmentMap) { return this; } + public Builder setExposedPorts(@Nullable List exposedPorts) { + if (exposedPorts != null) { + this.exposedPorts = exposedPorts; + } + return this; + } + public Builder setTargetFormat(Class targetFormat) { this.targetFormat = targetFormat; return this; @@ -131,6 +144,15 @@ public BuildConfiguration build() { errorMessages.add("main class is required but not set"); } + ImmutableSortedMap exposedPortsMap = ImmutableSortedMap.of(); + try { + exposedPortsMap = portListToPortMap(exposedPorts); + } catch (NumberFormatException ex) { + errorMessages.add( + "exposed ports are configured in an invalid format (must be a single " + + "port number or a range of port number)"); + } + switch (errorMessages.size()) { case 0: // No errors if (baseImageReference == null || targetImageReference == null || mainClass == null) { @@ -154,6 +176,7 @@ public BuildConfiguration build() { ImmutableList.copyOf(javaArguments), ImmutableList.copyOf(jvmFlags), ImmutableMap.copyOf(environmentMap), + ImmutableSortedMap.copyOf(exposedPortsMap), targetFormat); case 1: @@ -193,6 +216,54 @@ public static boolean isValidJavaClass(String className) { return true; } + /** + * Converts a list of port numbers to the corresponding ExposedPorts map format. + * + *

Example: [1000, 2000-2002] -> {"1000/tcp":{}, "2000/tcp":{}, "2001/tcp":{}, "2002/tcp":{}}) + * + * @return the map + */ + @VisibleForTesting + static ImmutableSortedMap portListToPortMap(List ports) + throws NumberFormatException { + SortedMap result = new TreeMap<>(); + + for (String port : ports) { + // Remove all spaces + port = port.trim().replace(" ", ""); + + if (port.matches("\\d+")) { + // Port is a single number + int portNum = Integer.parseInt(port); + if (portNum < 1 || portNum > 65535) { + throw new NumberFormatException("Invalid port number " + port); + } + result.put(port + "/tcp", EmptyStruct.get()); + + } else if (port.matches("\\d+-\\d+")) { + // Port is a range + List range = Splitter.on('-').splitToList(port); + int min = Integer.parseInt(range.get(0)); + int max = Integer.parseInt(range.get(1)); + + // Make sure range is valid (min-max, within port range) + if (min > max || min < 1 || max > 65535) { + throw new NumberFormatException("Invalid port range " + port); + } + + for (int portNum = min; portNum <= max; portNum++) { + result.put(portNum + "/tcp", EmptyStruct.get()); + } + + } else { + // Port is neither a single number nor a range + throw new NumberFormatException("Invalid port number " + port); + } + } + + return ImmutableSortedMap.copyOf(result); + } + private final BuildLogger buildLogger; private final ImageReference baseImageReference; @Nullable private final String baseImageCredentialHelperName; @@ -204,6 +275,7 @@ public static boolean isValidJavaClass(String className) { private final ImmutableList javaArguments; private final ImmutableList jvmFlags; private final ImmutableMap environmentMap; + private final ImmutableSortedMap exposedPorts; private final Class targetFormat; public static Builder builder(BuildLogger buildLogger) { @@ -223,6 +295,7 @@ private BuildConfiguration( ImmutableList javaArguments, ImmutableList jvmFlags, ImmutableMap environmentMap, + ImmutableSortedMap exposedPorts, Class targetFormat) { this.buildLogger = buildLogger; this.baseImageReference = baseImageReference; @@ -235,6 +308,7 @@ private BuildConfiguration( this.javaArguments = javaArguments; this.jvmFlags = jvmFlags; this.environmentMap = environmentMap; + this.exposedPorts = exposedPorts; this.targetFormat = targetFormat; } @@ -310,6 +384,10 @@ public ImmutableMap getEnvironment() { return environmentMap; } + public ImmutableSortedMap getExposedPorts() { + return exposedPorts; + } + public Class getTargetFormat() { return targetFormat; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java index e4f9db7310..ddddd6181a 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java @@ -102,6 +102,7 @@ private Image afterCachedLayersSteps() imageBuilder.setEnvironment(buildConfiguration.getEnvironment()); imageBuilder.setEntrypoint(entrypoint); imageBuilder.setJavaArguments(buildConfiguration.getJavaArguments()); + imageBuilder.setExposedPorts(buildConfiguration.getExposedPorts()); // Gets the container configuration content descriptor. return imageBuilder.build(); diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java index 78d2e88337..cb2000f205 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java @@ -16,7 +16,9 @@ package com.google.cloud.tools.jib.image; +import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; import java.util.List; import java.util.Map; @@ -31,6 +33,7 @@ public static class Builder { private ImmutableList entrypoint = ImmutableList.of(); private ImmutableList javaArguments = ImmutableList.of(); + private ImmutableSortedMap exposedPorts = ImmutableSortedMap.of(); /** * Sets the environment with a map from environment variable names to values. @@ -90,6 +93,18 @@ public Builder setJavaArguments(List javaArguments) { return this; } + /** + * Sets the items in the "ExposedPorts" field in the container configuration. + * + * @param exposedPorts the map of exposed ports to add, with the key in the format it would + * appear in the configuration json (e.g. "portNum/tcp") + * @return this + */ + public Builder setExposedPorts(Map exposedPorts) { + this.exposedPorts = ImmutableSortedMap.copyOf(exposedPorts); + return this; + } + /** * Adds a layer to the image. * @@ -107,7 +122,8 @@ public Image build() { imageLayersBuilder.build(), environmentBuilder.build(), ImmutableList.copyOf(entrypoint), - ImmutableList.copyOf(javaArguments)); + ImmutableList.copyOf(javaArguments), + ImmutableSortedMap.copyOf(exposedPorts)); } } @@ -127,15 +143,20 @@ public static Builder builder() { /** Arguments to pass into main when running the image. */ private final ImmutableList javaArguments; + /** Ports that the container listens on. */ + private final ImmutableSortedMap exposedPorts; + private Image( ImageLayers layers, ImmutableList environment, ImmutableList entrypoint, - ImmutableList javaArguments) { + ImmutableList javaArguments, + ImmutableSortedMap exposedPorts) { this.layers = layers; this.environmentBuilder = environment; this.entrypoint = entrypoint; this.javaArguments = javaArguments; + this.exposedPorts = exposedPorts; } public ImmutableList getEnvironment() { @@ -150,6 +171,10 @@ public ImmutableList getJavaArguments() { return javaArguments; } + public ImmutableSortedMap getExposedPorts() { + return exposedPorts; + } + public ImmutableList getLayers() { return layers.getLayers(); } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java index 2dff5c0b05..36bdad95d0 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java @@ -18,10 +18,12 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.google.cloud.tools.jib.image.DescriptorDigest; +import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.json.JsonTemplate; import com.google.common.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.List; +import java.util.SortedMap; import javax.annotation.Nullable; /** @@ -38,6 +40,7 @@ * "Env": ["/usr/bin/java"], * "Entrypoint": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], * "Cmd": ["arg1", "arg2"] + * "ExposedPorts": { "6000/tcp":{}, "8000/tcp":{}, "9000/tcp":{} } * }, * "rootfs": { * "diff_ids": [ @@ -88,6 +91,9 @@ private static class ConfigurationObjectTemplate implements JsonTemplate { /** Arguments to pass into main. */ @Nullable private List Cmd; + + /** Network ports the container listens on. */ + @Nullable private SortedMap ExposedPorts; } /** @@ -118,6 +124,10 @@ public void setContainerCmd(List cmd) { config.Cmd = cmd; } + public void setContainerExposedPorts(SortedMap exposedPorts) { + config.ExposedPorts = exposedPorts; + } + public void addLayerDiffId(DescriptorDigest diffId) { rootfs.diff_ids.add(diffId); } @@ -141,6 +151,11 @@ List getContainerCmd() { return config.Cmd; } + @Nullable + SortedMap getContainerExposedPorts() { + return config.ExposedPorts; + } + @VisibleForTesting DescriptorDigest getLayerDiffId(int index) { return rootfs.diff_ids.get(index); diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java index f3afc66518..43a135c592 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java @@ -72,6 +72,9 @@ public Blob getContainerConfigurationBlob() { // Sets the main method arguments. template.setContainerCmd(image.getJavaArguments()); + // Sets the exposed ports. + template.setContainerExposedPorts(image.getExposedPorts()); + // Serializes into JSON. return JsonTemplateMapper.toBlob(template); } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java index b8ded35c93..fe468b3461 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java @@ -102,6 +102,10 @@ public static Image toImage( imageBuilder.setJavaArguments(containerConfigurationTemplate.getContainerCmd()); } + if (containerConfigurationTemplate.getContainerExposedPorts() != null) { + imageBuilder.setExposedPorts(containerConfigurationTemplate.getContainerExposedPorts()); + } + if (containerConfigurationTemplate.getContainerEnvironment() != null) { for (String environmentVariable : containerConfigurationTemplate.getContainerEnvironment()) { imageBuilder.addEnvironmentVariableDefinition(environmentVariable); diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/json/EmptyStruct.java b/jib-core/src/main/java/com/google/cloud/tools/jib/json/EmptyStruct.java new file mode 100644 index 0000000000..b7314e8781 --- /dev/null +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/json/EmptyStruct.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.cloud.tools.jib.json; + +/** Empty class used for empty "{}" blocks in json. */ +public class EmptyStruct implements JsonTemplate { + private static final EmptyStruct SINGLETON = new EmptyStruct(); + + public static EmptyStruct get() { + return SINGLETON; + } + + @Override + public boolean equals(Object other) { + return other != null && other.getClass() == EmptyStruct.class; + } + + @Override + public int hashCode() { + return 0; + } + + private EmptyStruct() {} +} diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java index 0cdb740c55..2f241ec77e 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java @@ -20,8 +20,10 @@ import com.google.cloud.tools.jib.image.json.BuildableManifestTemplate; import com.google.cloud.tools.jib.image.json.OCIManifestTemplate; import com.google.cloud.tools.jib.image.json.V22ManifestTemplate; +import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.registry.credentials.RegistryCredentials; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -50,6 +52,9 @@ public void testBuilder() { List expectedJavaArguments = Arrays.asList("arg1", "arg2"); List expectedJvmFlags = Arrays.asList("some", "jvm", "flags"); Map expectedEnvironment = ImmutableMap.of("key", "value"); + List exposedPorts = Arrays.asList("1000", "2000"); + ImmutableSortedMap expectedExposedPorts = + ImmutableSortedMap.of("1000/tcp", EmptyStruct.get(), "2000/tcp", EmptyStruct.get()); Class expectedTargetFormat = OCIManifestTemplate.class; BuildConfiguration.Builder buildConfigurationBuilder = @@ -68,6 +73,7 @@ public void testBuilder() { .setJavaArguments(expectedJavaArguments) .setJvmFlags(expectedJvmFlags) .setEnvironment(expectedEnvironment) + .setExposedPorts(exposedPorts) .setTargetFormat(OCIManifestTemplate.class); BuildConfiguration buildConfiguration = buildConfigurationBuilder.build(); @@ -87,6 +93,7 @@ public void testBuilder() { Assert.assertEquals(expectedJavaArguments, buildConfiguration.getJavaArguments()); Assert.assertEquals(expectedJvmFlags, buildConfiguration.getJvmFlags()); Assert.assertEquals(expectedEnvironment, buildConfiguration.getEnvironment()); + Assert.assertEquals(expectedExposedPorts, buildConfiguration.getExposedPorts()); Assert.assertEquals(expectedTargetFormat, buildConfiguration.getTargetFormat()); } @@ -119,6 +126,7 @@ public void testBuilder_default() { Assert.assertEquals(Collections.emptyList(), buildConfiguration.getJavaArguments()); Assert.assertEquals(Collections.emptyList(), buildConfiguration.getJvmFlags()); Assert.assertEquals(Collections.emptyMap(), buildConfiguration.getEnvironment()); + Assert.assertEquals(Collections.emptyMap(), buildConfiguration.getExposedPorts()); Assert.assertEquals(V22ManifestTemplate.class, buildConfiguration.getTargetFormat()); } @@ -172,4 +180,42 @@ public void testValidJavaClassRegex() { Assert.assertFalse(BuildConfiguration.isValidJavaClass("{class}")); Assert.assertFalse(BuildConfiguration.isValidJavaClass("not valid")); } + + @Test + public void testPortListToPortMap() { + List input = Arrays.asList("1000", "2000-2003", "3000 - 3000"); + ImmutableSortedMap expected = + new ImmutableSortedMap.Builder(String::compareTo) + .put("1000/tcp", EmptyStruct.get()) + .put("2000/tcp", EmptyStruct.get()) + .put("2001/tcp", EmptyStruct.get()) + .put("2002/tcp", EmptyStruct.get()) + .put("2003/tcp", EmptyStruct.get()) + .put("3000/tcp", EmptyStruct.get()) + .build(); + ImmutableSortedMap result = BuildConfiguration.portListToPortMap(input); + Assert.assertEquals(expected, result); + + List badNumbers = Arrays.asList("1000abc", "-1", "0", "70000"); + for (String badInput : badNumbers) { + input = Collections.singletonList(badInput); + try { + BuildConfiguration.portListToPortMap(input); + Assert.fail(); + } catch (NumberFormatException ex) { + Assert.assertEquals("Invalid port number " + badInput, ex.getMessage()); + } + } + + List badRanges = Arrays.asList("4000-2000", "0-4000", "500-65536"); + for (String badInput : badRanges) { + input = Collections.singletonList(badInput); + try { + BuildConfiguration.portListToPortMap(input); + Assert.fail(); + } catch (NumberFormatException ex) { + Assert.assertEquals("Invalid port range " + badInput, ex.getMessage()); + } + } + } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java index 096d10d662..c318f2798c 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java @@ -24,6 +24,7 @@ import com.google.cloud.tools.jib.image.Image; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import java.nio.file.Paths; @@ -62,6 +63,7 @@ public void setUp() throws DigestException { Mockito.when(mockBuildConfiguration.getBuildLogger()).thenReturn(mockBuildLogger); Mockito.when(mockBuildConfiguration.getEnvironment()).thenReturn(ImmutableMap.of()); Mockito.when(mockBuildConfiguration.getJavaArguments()).thenReturn(ImmutableList.of()); + Mockito.when(mockBuildConfiguration.getExposedPorts()).thenReturn(ImmutableSortedMap.of()); Mockito.when(mockPullAndCacheBaseImageLayersStep.getFuture()) .thenReturn( diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java index 23041b3d3c..fa75888a72 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java @@ -17,7 +17,9 @@ package com.google.cloud.tools.jib.image; import com.google.cloud.tools.jib.blob.BlobDescriptor; +import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedMap; import java.util.Arrays; import org.junit.Assert; import org.junit.Before; @@ -51,6 +53,8 @@ public void test_smokeTest() throws LayerPropertyNotFoundException { .setEnvironmentVariable("VARIABLE", "VALUE") .setEntrypoint(Arrays.asList("some", "command")) .setJavaArguments(Arrays.asList("arg1", "arg2")) + .setExposedPorts( + ImmutableSortedMap.of("port1", EmptyStruct.get(), "port2", EmptyStruct.get())) .addLayer(mockLayer) .build(); @@ -59,5 +63,8 @@ public void test_smokeTest() throws LayerPropertyNotFoundException { Assert.assertEquals(expectedEnvironment, image.getEnvironment()); Assert.assertEquals(Arrays.asList("some", "command"), image.getEntrypoint()); Assert.assertEquals(Arrays.asList("arg1", "arg2"), image.getJavaArguments()); + Assert.assertEquals( + ImmutableSortedMap.of("port1", EmptyStruct.get(), "port2", EmptyStruct.get()), + image.getExposedPorts()); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java index 4c9414ba0a..4d6c0d282a 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java @@ -17,6 +17,7 @@ package com.google.cloud.tools.jib.image.json; import com.google.cloud.tools.jib.image.DescriptorDigest; +import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.json.JsonTemplateMapper; import com.google.common.io.Resources; import java.io.ByteArrayOutputStream; @@ -28,12 +29,25 @@ import java.nio.file.Paths; import java.security.DigestException; import java.util.Arrays; +import java.util.SortedMap; +import java.util.TreeMap; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; /** Tests for {@link ContainerConfigurationTemplate}. */ public class ContainerConfigurationTemplateTest { + private SortedMap exposedPorts; + + @Before + public void setup() { + exposedPorts = new TreeMap<>(); + exposedPorts.put("1000/tcp", EmptyStruct.get()); + exposedPorts.put("2000/tcp", EmptyStruct.get()); + exposedPorts.put("3000/tcp", EmptyStruct.get()); + } + @Test public void testToJson() throws IOException, URISyntaxException, DigestException { // Loads the expected JSON string. @@ -46,6 +60,7 @@ public void testToJson() throws IOException, URISyntaxException, DigestException containerConfigJson.setContainerEnvironment(Arrays.asList("VAR1=VAL1", "VAR2=VAL2")); containerConfigJson.setContainerEntrypoint(Arrays.asList("some", "entrypoint", "command")); containerConfigJson.setContainerCmd(Arrays.asList("arg1", "arg2")); + containerConfigJson.setContainerExposedPorts(exposedPorts); containerConfigJson.addLayerDiffId( DescriptorDigest.fromDigest( diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java index 5f49598e16..a355993771 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java @@ -22,7 +22,9 @@ import com.google.cloud.tools.jib.image.DescriptorDigest; import com.google.cloud.tools.jib.image.Image; import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException; +import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.json.JsonTemplateMapper; +import com.google.common.collect.ImmutableSortedMap; import com.google.common.io.ByteStreams; import com.google.common.io.Resources; import java.io.ByteArrayOutputStream; @@ -55,6 +57,15 @@ public void setUp() throws DigestException, LayerPropertyNotFoundException { testImageBuilder.setJavaArguments(Arrays.asList("arg1", "arg2")); + testImageBuilder.setExposedPorts( + ImmutableSortedMap.of( + "1000/tcp", + EmptyStruct.get(), + "2000/tcp", + EmptyStruct.get(), + "3000/tcp", + EmptyStruct.get())); + DescriptorDigest fakeDigest = DescriptorDigest.fromDigest( "sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"); diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java index faa1632611..0688c42ab6 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java @@ -22,7 +22,9 @@ import com.google.cloud.tools.jib.image.Layer; import com.google.cloud.tools.jib.image.LayerCountMismatchException; import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException; +import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.json.JsonTemplateMapper; +import com.google.common.collect.ImmutableSortedMap; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Path; @@ -105,5 +107,14 @@ private void testToImage_buildable( layers.get(0).getDiffId()); Assert.assertEquals(Arrays.asList("some", "entrypoint", "command"), image.getEntrypoint()); Assert.assertEquals(Arrays.asList("VAR1=VAL1", "VAR2=VAL2"), image.getEnvironment()); + Assert.assertEquals( + ImmutableSortedMap.of( + "1000/tcp", + EmptyStruct.get(), + "2000/tcp", + EmptyStruct.get(), + "3000/tcp", + EmptyStruct.get()), + image.getExposedPorts()); } } diff --git a/jib-core/src/test/resources/json/containerconfig.json b/jib-core/src/test/resources/json/containerconfig.json index 46865a35dd..f4aca7bbf0 100644 --- a/jib-core/src/test/resources/json/containerconfig.json +++ b/jib-core/src/test/resources/json/containerconfig.json @@ -1 +1 @@ -{"created":"1970-01-01T00:00:00Z","architecture":"amd64","os":"linux","config":{"Env":["VAR1=VAL1","VAR2=VAL2"],"Entrypoint":["some","entrypoint","command"],"Cmd":["arg1","arg2"]},"rootfs":{"type":"layers","diff_ids":["sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"]}} \ No newline at end of file +{"created":"1970-01-01T00:00:00Z","architecture":"amd64","os":"linux","config":{"Env":["VAR1=VAL1","VAR2=VAL2"],"Entrypoint":["some","entrypoint","command"],"Cmd":["arg1","arg2"],"ExposedPorts":{"1000/tcp":{},"2000/tcp":{},"3000/tcp":{}}},"rootfs":{"type":"layers","diff_ids":["sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"]}} \ No newline at end of file diff --git a/jib-core/src/test/resources/json/translated_ocimanifest.json b/jib-core/src/test/resources/json/translated_ocimanifest.json index 3fa9663038..b457ed8ec2 100644 --- a/jib-core/src/test/resources/json/translated_ocimanifest.json +++ b/jib-core/src/test/resources/json/translated_ocimanifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:e5260ce6926191331709d45da3467888a59585aa2c88689fb6a7565cedac718c","size":294},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:d05f4301080b44cf4a4e63e69d9f269d0d07cf0d0d613cacdfe93fb777c4f3a2","size":353},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file diff --git a/jib-core/src/test/resources/json/translated_v22manifest.json b/jib-core/src/test/resources/json/translated_v22manifest.json index bca5af3a92..beb0968b0d 100644 --- a/jib-core/src/test/resources/json/translated_v22manifest.json +++ b/jib-core/src/test/resources/json/translated_v22manifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:e5260ce6926191331709d45da3467888a59585aa2c88689fb6a7565cedac718c","size":294},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:d05f4301080b44cf4a4e63e69d9f269d0d07cf0d0d613cacdfe93fb777c4f3a2","size":353},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file From dd44f8b01e498e45cdff6fa503880f7555c5581c Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Wed, 20 Jun 2018 16:34:47 -0400 Subject: [PATCH 02/30] Update integration tests --- .../builder/BuildStepsIntegrationTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java index aa33f810a9..00bb11febf 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java @@ -21,7 +21,9 @@ import com.google.cloud.tools.jib.image.ImageReference; import com.google.cloud.tools.jib.registry.LocalRegistry; import java.nio.file.Path; +import java.util.Arrays; import java.util.Collections; +import org.hamcrest.CoreMatchers; import org.junit.Assert; import org.junit.ClassRule; import org.junit.Rule; @@ -46,6 +48,7 @@ public void testSteps_forBuildToDockerRegistry() throws Exception { .setTargetImage(ImageReference.of("localhost:5000", "testimage", "testtag")) .setMainClass("HelloWorld") .setJavaArguments(Collections.singletonList("An argument.")) + .setExposedPorts(Arrays.asList("1000", "2000-2003")) .build(); Path cacheDirectory = temporaryCacheDirectory.newFolder().toPath(); @@ -64,6 +67,15 @@ public void testSteps_forBuildToDockerRegistry() throws Exception { String imageReference = "localhost:5000/testimage:testtag"; new Command("docker", "pull", imageReference).run(); + Assert.assertThat( + new Command("docker", "inspect", imageReference).run(), + CoreMatchers.containsString( + " \"ExposedPorts\": {\n" + + " \"1000/tcp\": {},\n" + + " \"2000/tcp\": {},\n" + + " \"2001/tcp\": {},\n" + + " \"2002/tcp\": {},\n" + + " \"2003/tcp\": {}")); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", imageReference).run()); } @@ -77,6 +89,7 @@ public void testSteps_forBuildToDockerDaemon() throws Exception { .setTargetImage(ImageReference.of(null, "testdocker", null)) .setMainClass("HelloWorld") .setJavaArguments(Collections.singletonList("An argument.")) + .setExposedPorts(Arrays.asList("1000", "2000-2003")) .build(); Path cacheDirectory = temporaryCacheDirectory.newFolder().toPath(); @@ -87,6 +100,15 @@ public void testSteps_forBuildToDockerDaemon() throws Exception { Caches.newInitializer(cacheDirectory).setBaseCacheDirectory(cacheDirectory)); buildDockerSteps.run(); + Assert.assertThat( + new Command("docker", "inspect", "testdocker").run(), + CoreMatchers.containsString( + " \"ExposedPorts\": {\n" + + " \"1000/tcp\": {},\n" + + " \"2000/tcp\": {},\n" + + " \"2001/tcp\": {},\n" + + " \"2002/tcp\": {},\n" + + " \"2003/tcp\": {}")); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", "testdocker").run()); } From fcfa21a0506ca5531c878dd4252ac09afa2b5ca3 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Wed, 20 Jun 2018 16:39:52 -0400 Subject: [PATCH 03/30] Javadoc --- .../com/google/cloud/tools/jib/builder/BuildConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java index 0d4a37ae79..ab9d0903f2 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java @@ -221,7 +221,9 @@ public static boolean isValidJavaClass(String className) { * *

Example: [1000, 2000-2002] -> {"1000/tcp":{}, "2000/tcp":{}, "2001/tcp":{}, "2002/tcp":{}}) * + * @param ports the list of port numbers/ranges * @return the map + * @throws NumberFormatException if any of the ports are in an invalid format or out of range */ @VisibleForTesting static ImmutableSortedMap portListToPortMap(List ports) From 218bce133606afd7a762d28cf673e347cdf2613b Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 10:03:19 -0400 Subject: [PATCH 04/30] Feedback --- .../tools/jib/builder/BuildConfiguration.java | 54 +++++++-------- .../google/cloud/tools/jib/image/Image.java | 16 ++--- .../json/ContainerConfigurationTemplate.java | 31 ++++++--- .../jib/builder/BuildConfigurationTest.java | 65 ++++++++----------- .../jib/builder/steps/BuildImageStepTest.java | 3 +- .../cloud/tools/jib/image/ImageTest.java | 9 +-- .../ContainerConfigurationTemplateTest.java | 15 ++--- .../image/json/ImageToJsonTranslatorTest.java | 11 +--- .../image/json/JsonToImageTranslatorTest.java | 12 +--- 9 files changed, 88 insertions(+), 128 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java index ab9d0903f2..3d5570587f 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java @@ -19,19 +19,12 @@ import com.google.cloud.tools.jib.image.ImageReference; import com.google.cloud.tools.jib.image.json.BuildableManifestTemplate; import com.google.cloud.tools.jib.image.json.V22ManifestTemplate; -import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.registry.credentials.RegistryCredentials; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSortedMap; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.*; import javax.annotation.Nullable; import javax.lang.model.SourceVersion; @@ -144,15 +137,6 @@ public BuildConfiguration build() { errorMessages.add("main class is required but not set"); } - ImmutableSortedMap exposedPortsMap = ImmutableSortedMap.of(); - try { - exposedPortsMap = portListToPortMap(exposedPorts); - } catch (NumberFormatException ex) { - errorMessages.add( - "exposed ports are configured in an invalid format (must be a single " - + "port number or a range of port number)"); - } - switch (errorMessages.size()) { case 0: // No errors if (baseImageReference == null || targetImageReference == null || mainClass == null) { @@ -176,7 +160,7 @@ public BuildConfiguration build() { ImmutableList.copyOf(javaArguments), ImmutableList.copyOf(jvmFlags), ImmutableMap.copyOf(environmentMap), - ImmutableSortedMap.copyOf(exposedPortsMap), + expandPortRanges(exposedPorts, buildLogger), targetFormat); case 1: @@ -226,21 +210,20 @@ public static boolean isValidJavaClass(String className) { * @throws NumberFormatException if any of the ports are in an invalid format or out of range */ @VisibleForTesting - static ImmutableSortedMap portListToPortMap(List ports) - throws NumberFormatException { - SortedMap result = new TreeMap<>(); + static ImmutableList expandPortRanges(List ports, BuildLogger logger) { + List result = new ArrayList<>(); for (String port : ports) { // Remove all spaces - port = port.trim().replace(" ", ""); + port = port.replace(" ", ""); if (port.matches("\\d+")) { // Port is a single number int portNum = Integer.parseInt(port); if (portNum < 1 || portNum > 65535) { - throw new NumberFormatException("Invalid port number " + port); + logger.warn("Port number '" + port + "' is out of range (1-65535)"); } - result.put(port + "/tcp", EmptyStruct.get()); + result.add(port); } else if (port.matches("\\d+-\\d+")) { // Port is a range @@ -248,22 +231,29 @@ static ImmutableSortedMap portListToPortMap(List po int min = Integer.parseInt(range.get(0)); int max = Integer.parseInt(range.get(1)); + // Reverse range if configured as 'max-min' instead of 'min-max' + if (min > max) { + int swapTemp = max; + max = min; + min = swapTemp; + } + // Make sure range is valid (min-max, within port range) - if (min > max || min < 1 || max > 65535) { - throw new NumberFormatException("Invalid port range " + port); + if (min < 1 || max > 65535) { + logger.warn("Port range '" + port + "' exceeds normal port range (1-65535)"); } for (int portNum = min; portNum <= max; portNum++) { - result.put(portNum + "/tcp", EmptyStruct.get()); + result.add("" + portNum); } } else { // Port is neither a single number nor a range - throw new NumberFormatException("Invalid port number " + port); + logger.warn("Port '" + port + "' is not a port number"); } } - return ImmutableSortedMap.copyOf(result); + return ImmutableList.copyOf(result); } private final BuildLogger buildLogger; @@ -277,7 +267,7 @@ static ImmutableSortedMap portListToPortMap(List po private final ImmutableList javaArguments; private final ImmutableList jvmFlags; private final ImmutableMap environmentMap; - private final ImmutableSortedMap exposedPorts; + private final ImmutableList exposedPorts; private final Class targetFormat; public static Builder builder(BuildLogger buildLogger) { @@ -297,7 +287,7 @@ private BuildConfiguration( ImmutableList javaArguments, ImmutableList jvmFlags, ImmutableMap environmentMap, - ImmutableSortedMap exposedPorts, + ImmutableList exposedPorts, Class targetFormat) { this.buildLogger = buildLogger; this.baseImageReference = baseImageReference; @@ -386,7 +376,7 @@ public ImmutableMap getEnvironment() { return environmentMap; } - public ImmutableSortedMap getExposedPorts() { + public ImmutableList getExposedPorts() { return exposedPorts; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java index cb2000f205..58771637a6 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java @@ -16,9 +16,7 @@ package com.google.cloud.tools.jib.image; -import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSortedMap; import java.util.List; import java.util.Map; @@ -33,7 +31,7 @@ public static class Builder { private ImmutableList entrypoint = ImmutableList.of(); private ImmutableList javaArguments = ImmutableList.of(); - private ImmutableSortedMap exposedPorts = ImmutableSortedMap.of(); + private ImmutableList exposedPorts = ImmutableList.of(); /** * Sets the environment with a map from environment variable names to values. @@ -100,8 +98,8 @@ public Builder setJavaArguments(List javaArguments) { * appear in the configuration json (e.g. "portNum/tcp") * @return this */ - public Builder setExposedPorts(Map exposedPorts) { - this.exposedPorts = ImmutableSortedMap.copyOf(exposedPorts); + public Builder setExposedPorts(List exposedPorts) { + this.exposedPorts = ImmutableList.copyOf(exposedPorts); return this; } @@ -123,7 +121,7 @@ public Image build() { environmentBuilder.build(), ImmutableList.copyOf(entrypoint), ImmutableList.copyOf(javaArguments), - ImmutableSortedMap.copyOf(exposedPorts)); + ImmutableList.copyOf(exposedPorts)); } } @@ -144,14 +142,14 @@ public static Builder builder() { private final ImmutableList javaArguments; /** Ports that the container listens on. */ - private final ImmutableSortedMap exposedPorts; + private final ImmutableList exposedPorts; private Image( ImageLayers layers, ImmutableList environment, ImmutableList entrypoint, ImmutableList javaArguments, - ImmutableSortedMap exposedPorts) { + ImmutableList exposedPorts) { this.layers = layers; this.environmentBuilder = environment; this.entrypoint = entrypoint; @@ -171,7 +169,7 @@ public ImmutableList getJavaArguments() { return javaArguments; } - public ImmutableSortedMap getExposedPorts() { + public ImmutableList getExposedPorts() { return exposedPorts; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java index 36bdad95d0..95d22b0385 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java @@ -18,12 +18,11 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.google.cloud.tools.jib.image.DescriptorDigest; -import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.json.JsonTemplate; import com.google.common.annotations.VisibleForTesting; -import java.util.ArrayList; -import java.util.List; -import java.util.SortedMap; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSortedMap; +import java.util.*; import javax.annotation.Nullable; /** @@ -92,8 +91,8 @@ private static class ConfigurationObjectTemplate implements JsonTemplate { /** Arguments to pass into main. */ @Nullable private List Cmd; - /** Network ports the container listens on. */ - @Nullable private SortedMap ExposedPorts; + /** Network ports the container exposes. */ + @Nullable private SortedMap> ExposedPorts; } /** @@ -124,8 +123,12 @@ public void setContainerCmd(List cmd) { config.Cmd = cmd; } - public void setContainerExposedPorts(SortedMap exposedPorts) { - config.ExposedPorts = exposedPorts; + public void setContainerExposedPorts(List exposedPorts) { + SortedMap> result = new TreeMap<>(); + for (String port : exposedPorts) { + result.put(port + "/tcp", Collections.emptyMap()); + } + config.ExposedPorts = ImmutableSortedMap.copyOf(result); } public void addLayerDiffId(DescriptorDigest diffId) { @@ -152,8 +155,16 @@ List getContainerCmd() { } @Nullable - SortedMap getContainerExposedPorts() { - return config.ExposedPorts; + List getContainerExposedPorts() { + if (config.ExposedPorts == null) { + return null; + } + List ports = new ArrayList<>(); + for (Map.Entry> entry : config.ExposedPorts.entrySet()) { + // Remove the "/tcp" + ports.add(Splitter.on('/').splitToList(entry.getKey()).get(0)); + } + return ports; } @VisibleForTesting diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java index 2f241ec77e..ecf486cdc8 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java @@ -20,20 +20,25 @@ import com.google.cloud.tools.jib.image.json.BuildableManifestTemplate; import com.google.cloud.tools.jib.image.json.OCIManifestTemplate; import com.google.cloud.tools.jib.image.json.V22ManifestTemplate; -import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.registry.credentials.RegistryCredentials; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSortedMap; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import org.junit.Assert; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +@RunWith(MockitoJUnitRunner.class) public class BuildConfigurationTest { + @Mock private BuildLogger mockLogger; + @Test public void testBuilder() { String expectedBaseImageServerUrl = "someserver"; @@ -52,9 +57,7 @@ public void testBuilder() { List expectedJavaArguments = Arrays.asList("arg1", "arg2"); List expectedJvmFlags = Arrays.asList("some", "jvm", "flags"); Map expectedEnvironment = ImmutableMap.of("key", "value"); - List exposedPorts = Arrays.asList("1000", "2000"); - ImmutableSortedMap expectedExposedPorts = - ImmutableSortedMap.of("1000/tcp", EmptyStruct.get(), "2000/tcp", EmptyStruct.get()); + List expectedExposedPorts = Arrays.asList("1000", "2000"); Class expectedTargetFormat = OCIManifestTemplate.class; BuildConfiguration.Builder buildConfigurationBuilder = @@ -73,7 +76,7 @@ public void testBuilder() { .setJavaArguments(expectedJavaArguments) .setJvmFlags(expectedJvmFlags) .setEnvironment(expectedEnvironment) - .setExposedPorts(exposedPorts) + .setExposedPorts(expectedExposedPorts) .setTargetFormat(OCIManifestTemplate.class); BuildConfiguration buildConfiguration = buildConfigurationBuilder.build(); @@ -126,7 +129,7 @@ public void testBuilder_default() { Assert.assertEquals(Collections.emptyList(), buildConfiguration.getJavaArguments()); Assert.assertEquals(Collections.emptyList(), buildConfiguration.getJvmFlags()); Assert.assertEquals(Collections.emptyMap(), buildConfiguration.getEnvironment()); - Assert.assertEquals(Collections.emptyMap(), buildConfiguration.getExposedPorts()); + Assert.assertEquals(Collections.emptyList(), buildConfiguration.getExposedPorts()); Assert.assertEquals(V22ManifestTemplate.class, buildConfiguration.getTargetFormat()); } @@ -182,40 +185,26 @@ public void testValidJavaClassRegex() { } @Test - public void testPortListToPortMap() { - List input = Arrays.asList("1000", "2000-2003", "3000 - 3000"); - ImmutableSortedMap expected = - new ImmutableSortedMap.Builder(String::compareTo) - .put("1000/tcp", EmptyStruct.get()) - .put("2000/tcp", EmptyStruct.get()) - .put("2001/tcp", EmptyStruct.get()) - .put("2002/tcp", EmptyStruct.get()) - .put("2003/tcp", EmptyStruct.get()) - .put("3000/tcp", EmptyStruct.get()) + public void testExpandPortList() { + List input = Arrays.asList("1000", "2000-2003", "3000 - 3000", "4002-4000"); + ImmutableList expected = + new ImmutableList.Builder() + .add("1000", "2000", "2001", "2002", "2003", "3000", "4000", "4001", "4002") .build(); - ImmutableSortedMap result = BuildConfiguration.portListToPortMap(input); + ImmutableList result = BuildConfiguration.expandPortRanges(input, mockLogger); Assert.assertEquals(expected, result); - List badNumbers = Arrays.asList("1000abc", "-1", "0", "70000"); - for (String badInput : badNumbers) { - input = Collections.singletonList(badInput); - try { - BuildConfiguration.portListToPortMap(input); - Assert.fail(); - } catch (NumberFormatException ex) { - Assert.assertEquals("Invalid port number " + badInput, ex.getMessage()); - } - } + BuildConfiguration.expandPortRanges(Collections.singletonList("abc"), mockLogger); + Mockito.verify(mockLogger).warn("Port 'abc' is not a port number"); - List badRanges = Arrays.asList("4000-2000", "0-4000", "500-65536"); - for (String badInput : badRanges) { - input = Collections.singletonList(badInput); - try { - BuildConfiguration.portListToPortMap(input); - Assert.fail(); - } catch (NumberFormatException ex) { - Assert.assertEquals("Invalid port range " + badInput, ex.getMessage()); - } - } + BuildConfiguration.expandPortRanges(Collections.singletonList("0"), mockLogger); + Mockito.verify(mockLogger).warn("Port number '0' is out of range (1-65535)"); + BuildConfiguration.expandPortRanges(Collections.singletonList("70000"), mockLogger); + Mockito.verify(mockLogger).warn("Port number '70000' is out of range (1-65535)"); + + BuildConfiguration.expandPortRanges(Collections.singletonList("0-400"), mockLogger); + Mockito.verify(mockLogger).warn("Port range '0-400' exceeds normal port range (1-65535)"); + BuildConfiguration.expandPortRanges(Collections.singletonList("500-70000"), mockLogger); + Mockito.verify(mockLogger).warn("Port range '500-70000' exceeds normal port range (1-65535)"); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java index c03c904953..3ae274f153 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java @@ -25,7 +25,6 @@ import com.google.cloud.tools.jib.image.Image; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSortedMap; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import java.nio.file.Paths; @@ -66,7 +65,7 @@ public void setUp() throws DigestException { Mockito.when(mockBuildConfiguration.getBuildLogger()).thenReturn(mockBuildLogger); Mockito.when(mockBuildConfiguration.getEnvironment()).thenReturn(ImmutableMap.of()); Mockito.when(mockBuildConfiguration.getJavaArguments()).thenReturn(ImmutableList.of()); - Mockito.when(mockBuildConfiguration.getExposedPorts()).thenReturn(ImmutableSortedMap.of()); + Mockito.when(mockBuildConfiguration.getExposedPorts()).thenReturn(ImmutableList.of()); Mockito.when(mockPullAndCacheBaseImageLayersStep.getFuture()) .thenReturn( diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java index fa75888a72..1b63e3ea4c 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java @@ -17,9 +17,7 @@ package com.google.cloud.tools.jib.image; import com.google.cloud.tools.jib.blob.BlobDescriptor; -import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSortedMap; import java.util.Arrays; import org.junit.Assert; import org.junit.Before; @@ -53,8 +51,7 @@ public void test_smokeTest() throws LayerPropertyNotFoundException { .setEnvironmentVariable("VARIABLE", "VALUE") .setEntrypoint(Arrays.asList("some", "command")) .setJavaArguments(Arrays.asList("arg1", "arg2")) - .setExposedPorts( - ImmutableSortedMap.of("port1", EmptyStruct.get(), "port2", EmptyStruct.get())) + .setExposedPorts(Arrays.asList("port1", "port2")) .addLayer(mockLayer) .build(); @@ -63,8 +60,6 @@ public void test_smokeTest() throws LayerPropertyNotFoundException { Assert.assertEquals(expectedEnvironment, image.getEnvironment()); Assert.assertEquals(Arrays.asList("some", "command"), image.getEntrypoint()); Assert.assertEquals(Arrays.asList("arg1", "arg2"), image.getJavaArguments()); - Assert.assertEquals( - ImmutableSortedMap.of("port1", EmptyStruct.get(), "port2", EmptyStruct.get()), - image.getExposedPorts()); + Assert.assertEquals(Arrays.asList("port1", "port2"), image.getExposedPorts()); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java index 4d6c0d282a..3cdfeb3801 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java @@ -17,7 +17,6 @@ package com.google.cloud.tools.jib.image.json; import com.google.cloud.tools.jib.image.DescriptorDigest; -import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.json.JsonTemplateMapper; import com.google.common.io.Resources; import java.io.ByteArrayOutputStream; @@ -28,9 +27,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.DigestException; -import java.util.Arrays; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.*; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -38,14 +35,14 @@ /** Tests for {@link ContainerConfigurationTemplate}. */ public class ContainerConfigurationTemplateTest { - private SortedMap exposedPorts; + private List exposedPorts; @Before public void setup() { - exposedPorts = new TreeMap<>(); - exposedPorts.put("1000/tcp", EmptyStruct.get()); - exposedPorts.put("2000/tcp", EmptyStruct.get()); - exposedPorts.put("3000/tcp", EmptyStruct.get()); + exposedPorts = new ArrayList<>(); + exposedPorts.add("1000"); + exposedPorts.add("2000"); + exposedPorts.add("3000"); } @Test diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java index a355993771..2f510d3370 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java @@ -22,9 +22,7 @@ import com.google.cloud.tools.jib.image.DescriptorDigest; import com.google.cloud.tools.jib.image.Image; import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException; -import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.json.JsonTemplateMapper; -import com.google.common.collect.ImmutableSortedMap; import com.google.common.io.ByteStreams; import com.google.common.io.Resources; import java.io.ByteArrayOutputStream; @@ -57,14 +55,7 @@ public void setUp() throws DigestException, LayerPropertyNotFoundException { testImageBuilder.setJavaArguments(Arrays.asList("arg1", "arg2")); - testImageBuilder.setExposedPorts( - ImmutableSortedMap.of( - "1000/tcp", - EmptyStruct.get(), - "2000/tcp", - EmptyStruct.get(), - "3000/tcp", - EmptyStruct.get())); + testImageBuilder.setExposedPorts(Arrays.asList("1000", "2000", "3000")); DescriptorDigest fakeDigest = DescriptorDigest.fromDigest( diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java index 0688c42ab6..00be6bbfd7 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java @@ -22,9 +22,7 @@ import com.google.cloud.tools.jib.image.Layer; import com.google.cloud.tools.jib.image.LayerCountMismatchException; import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException; -import com.google.cloud.tools.jib.json.EmptyStruct; import com.google.cloud.tools.jib.json.JsonTemplateMapper; -import com.google.common.collect.ImmutableSortedMap; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Path; @@ -107,14 +105,6 @@ private void testToImage_buildable( layers.get(0).getDiffId()); Assert.assertEquals(Arrays.asList("some", "entrypoint", "command"), image.getEntrypoint()); Assert.assertEquals(Arrays.asList("VAR1=VAL1", "VAR2=VAL2"), image.getEnvironment()); - Assert.assertEquals( - ImmutableSortedMap.of( - "1000/tcp", - EmptyStruct.get(), - "2000/tcp", - EmptyStruct.get(), - "3000/tcp", - EmptyStruct.get()), - image.getExposedPorts()); + Assert.assertEquals(Arrays.asList("1000", "2000", "3000"), image.getExposedPorts()); } } From 5e68c1b630a14c68e47f1794eeb50bbdde32a7e5 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 10:05:25 -0400 Subject: [PATCH 05/30] Add core exportPorts functionality to docker context exporter --- .../jib/docker/DockerContextGenerator.java | 28 +++++++++++++++++++ .../src/main/resources/DockerfileTemplate | 2 +- .../docker/DockerContextGeneratorTest.java | 11 +++++++- jib-core/src/test/resources/sampleDockerfile | 2 ++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 530113fa27..c76d9a6055 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -52,6 +52,7 @@ public class DockerContextGenerator { private List jvmFlags = Collections.emptyList(); private String mainClass = ""; private List javaArguments = Collections.emptyList(); + private List exposedPorts = Collections.emptyList(); public DockerContextGenerator(SourceFilesConfiguration sourceFilesConfiguration) { this.sourceFilesConfiguration = sourceFilesConfiguration; @@ -102,6 +103,17 @@ public DockerContextGenerator setJavaArguments(List javaArguments) { return this; } + /** + * Sets the exposed ports. + * + * @param exposedPorts the list of port numbers/port ranges to expose + * @return this + */ + public DockerContextGenerator setExposedPorts(List exposedPorts) { + this.exposedPorts = exposedPorts; + return this; + } + /** * Creates the Docker context in {@code #targetDirectory}. * @@ -159,6 +171,7 @@ String makeDockerfile() throws IOException { "@@DEPENDENCIES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getDependenciesPathOnImage()) .replace("@@RESOURCES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getResourcesPathOnImage()) .replace("@@CLASSES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getClassesPathOnImage()) + .replace("@@EXPOSED_PORTS@@", makeExposeItems(exposedPorts)) .replace( "@@ENTRYPOINT@@", joinAsJsonArray( @@ -193,4 +206,19 @@ static String joinAsJsonArray(List items) { return resultString.toString(); } + + /** + * Builds a list of Dockerfile "EXPOSE" items. + * + * @param exposedPorts the list of ports numbers/ranges to expose + * @return a string containing an EXPOSE command for each of the entries + */ + @VisibleForTesting + static String makeExposeItems(List exposedPorts) { + StringBuilder resultString = new StringBuilder(); + for (String port : exposedPorts) { + resultString.append("EXPOSE ").append(port).append("\n"); + } + return resultString.toString(); + } } diff --git a/jib-core/src/main/resources/DockerfileTemplate b/jib-core/src/main/resources/DockerfileTemplate index 2086e7f10f..5e87095d01 100644 --- a/jib-core/src/main/resources/DockerfileTemplate +++ b/jib-core/src/main/resources/DockerfileTemplate @@ -4,5 +4,5 @@ COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@ COPY resources @@RESOURCES_PATH_ON_IMAGE@@ COPY classes @@CLASSES_PATH_ON_IMAGE@@ -ENTRYPOINT @@ENTRYPOINT@@ +@@EXPOSED_PORTS@@ENTRYPOINT @@ENTRYPOINT@@ CMD @@CMD@@ diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 2078523c1e..90c59ec4fc 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -113,7 +113,7 @@ public void testGenerate() throws IOException, URISyntaxException { } @Test - public void testMakeDockerList() { + public void testJoinAsJsonArray() { Assert.assertEquals( "[\"java\",\"-cp\",\"/app/libs/*:/app/resources/:/app/classes/\",\"\"]", DockerContextGenerator.joinAsJsonArray( @@ -128,12 +128,20 @@ public void testMakeDockerList() { "AnotherMainClass"))); } + @Test + public void testMakeExposeItems() { + Assert.assertEquals( + "EXPOSE 1000\nEXPOSE 2000-2010\n", + DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); + } + @Test public void testMakeDockerfile() throws IOException, URISyntaxException { String expectedBaseImage = "somebaseimage"; List expectedJvmFlags = Arrays.asList("-flag", "another\"Flag"); String expectedMainClass = "SomeMainClass"; List expectedJavaArguments = Arrays.asList("arg1", "arg2"); + List exposedPorts = Arrays.asList("1000", "2000-2010"); String dockerfile = new DockerContextGenerator(mockSourceFilesConfiguration) @@ -141,6 +149,7 @@ public void testMakeDockerfile() throws IOException, URISyntaxException { .setJvmFlags(expectedJvmFlags) .setMainClass(expectedMainClass) .setJavaArguments(expectedJavaArguments) + .setExposedPorts(exposedPorts) .makeDockerfile(); Path sampleDockerfile = Paths.get(Resources.getResource("sampleDockerfile").toURI()); diff --git a/jib-core/src/test/resources/sampleDockerfile b/jib-core/src/test/resources/sampleDockerfile index 27d7ba9d34..8de7285c1f 100644 --- a/jib-core/src/test/resources/sampleDockerfile +++ b/jib-core/src/test/resources/sampleDockerfile @@ -4,5 +4,7 @@ COPY libs /app/libs/ COPY resources /app/resources/ COPY classes /app/classes/ +EXPOSE 1000 +EXPOSE 2000-2010 ENTRYPOINT ["java","-flag","another\"Flag","-cp","/app/libs/*:/app/resources/:/app/classes/","SomeMainClass"] CMD ["arg1","arg2"] From d60d7ebe651ca8fd9990d12c326d1b5e52662faf Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 10:08:10 -0400 Subject: [PATCH 06/30] Remove EmptyStruct --- .../cloud/tools/jib/json/EmptyStruct.java | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 jib-core/src/main/java/com/google/cloud/tools/jib/json/EmptyStruct.java diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/json/EmptyStruct.java b/jib-core/src/main/java/com/google/cloud/tools/jib/json/EmptyStruct.java deleted file mode 100644 index b7314e8781..0000000000 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/json/EmptyStruct.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018 Google LLC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.cloud.tools.jib.json; - -/** Empty class used for empty "{}" blocks in json. */ -public class EmptyStruct implements JsonTemplate { - private static final EmptyStruct SINGLETON = new EmptyStruct(); - - public static EmptyStruct get() { - return SINGLETON; - } - - @Override - public boolean equals(Object other) { - return other != null && other.getClass() == EmptyStruct.class; - } - - @Override - public int hashCode() { - return 0; - } - - private EmptyStruct() {} -} From 6b7fba56a643463771c9d7c270c35413103487c3 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 11:42:47 -0400 Subject: [PATCH 07/30] Feedback --- .../builder/BuildStepsIntegrationTest.java | 20 +-- .../tools/jib/builder/BuildConfiguration.java | 119 +++++++++--------- .../google/cloud/tools/jib/image/Image.java | 14 +-- .../json/ContainerConfigurationTemplate.java | 14 +-- .../jib/image/json/JsonToImageTranslator.java | 4 +- .../jib/builder/BuildConfigurationTest.java | 50 +++++--- .../cloud/tools/jib/image/ImageTest.java | 4 +- .../ContainerConfigurationTemplateTest.java | 8 +- .../image/json/ImageToJsonTranslatorTest.java | 3 +- .../image/json/JsonToImageTranslatorTest.java | 3 +- .../test/resources/json/containerconfig.json | 2 +- .../json/translated_ocimanifest.json | 2 +- .../json/translated_v22manifest.json | 2 +- 13 files changed, 130 insertions(+), 115 deletions(-) diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java index 00bb11febf..d4b2478291 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java @@ -71,11 +71,11 @@ public void testSteps_forBuildToDockerRegistry() throws Exception { new Command("docker", "inspect", imageReference).run(), CoreMatchers.containsString( " \"ExposedPorts\": {\n" - + " \"1000/tcp\": {},\n" - + " \"2000/tcp\": {},\n" - + " \"2001/tcp\": {},\n" - + " \"2002/tcp\": {},\n" - + " \"2003/tcp\": {}")); + + " \"1000\": {},\n" + + " \"2000\": {},\n" + + " \"2001\": {},\n" + + " \"2002\": {},\n" + + " \"2003\": {}")); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", imageReference).run()); } @@ -104,11 +104,11 @@ public void testSteps_forBuildToDockerDaemon() throws Exception { new Command("docker", "inspect", "testdocker").run(), CoreMatchers.containsString( " \"ExposedPorts\": {\n" - + " \"1000/tcp\": {},\n" - + " \"2000/tcp\": {},\n" - + " \"2001/tcp\": {},\n" - + " \"2002/tcp\": {},\n" - + " \"2003/tcp\": {}")); + + " \"1000\": {},\n" + + " \"2000\": {},\n" + + " \"2001\": {},\n" + + " \"2002\": {},\n" + + " \"2003\": {}")); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", "testdocker").run()); } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java index 3d5570587f..0c3aea094d 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java @@ -24,7 +24,10 @@ import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import javax.annotation.Nullable; import javax.lang.model.SourceVersion; @@ -160,7 +163,7 @@ public BuildConfiguration build() { ImmutableList.copyOf(javaArguments), ImmutableList.copyOf(jvmFlags), ImmutableMap.copyOf(environmentMap), - expandPortRanges(exposedPorts, buildLogger), + expandPortRanges(exposedPorts), targetFormat); case 1: @@ -185,75 +188,75 @@ public BuildConfiguration build() { throw new IllegalStateException(errorMessage.toString()); } } - } - /** - * @param className the class name to check - * @return {@code true} if {@code className} is a valid Java class name; {@code false} otherwise - */ - public static boolean isValidJavaClass(String className) { - for (String part : Splitter.on('.').split(className)) { - if (!SourceVersion.isIdentifier(part)) { - return false; - } - } - return true; - } - - /** - * Converts a list of port numbers to the corresponding ExposedPorts map format. - * - *

Example: [1000, 2000-2002] -> {"1000/tcp":{}, "2000/tcp":{}, "2001/tcp":{}, "2002/tcp":{}}) - * - * @param ports the list of port numbers/ranges - * @return the map - * @throws NumberFormatException if any of the ports are in an invalid format or out of range - */ - @VisibleForTesting - static ImmutableList expandPortRanges(List ports, BuildLogger logger) { - List result = new ArrayList<>(); - - for (String port : ports) { - // Remove all spaces - port = port.replace(" ", ""); - - if (port.matches("\\d+")) { - // Port is a single number - int portNum = Integer.parseInt(port); - if (portNum < 1 || portNum > 65535) { - logger.warn("Port number '" + port + "' is out of range (1-65535)"); + /** + * Converts a list of port number/range strings to a list of integers + * + *

Example: ["1000", "2000-2002"] -> [1000, 2000, 2001, 2002] + * + * @param ports the list of port numbers/ranges + * @return the ports as a list of integers + * @throws NumberFormatException if any of the ports are in an invalid format or out of range + */ + @VisibleForTesting + ImmutableList expandPortRanges(List ports) throws NumberFormatException { + ImmutableList.Builder result = new ImmutableList.Builder<>(); + + for (String port : ports) { + // Make sure configuration is a single number or a range + if (!port.matches("\\d+") && !port.matches("\\d+-\\d+")) { + throw new NumberFormatException( + "Invalid port configuration: '" + + port + + "'. Make sure the port is a single number or a range of two numbers separated " + + "with a '-'."); } - result.add(port); - } else if (port.matches("\\d+-\\d+")) { - // Port is a range + // Parse range (or treat as range of min-min if only single port configuration) List range = Splitter.on('-').splitToList(port); int min = Integer.parseInt(range.get(0)); - int max = Integer.parseInt(range.get(1)); + int max = min; + if (range.size() > 1) { + max = Integer.parseInt(range.get(1)); + } - // Reverse range if configured as 'max-min' instead of 'min-max' + // Error if configured as 'max-min' instead of 'min-max' if (min > max) { - int swapTemp = max; - max = min; - min = swapTemp; + throw new NumberFormatException( + "Invalid port range '" + port + "'; smaller number must come first."); } - // Make sure range is valid (min-max, within port range) + // Warn for possibly invalid port numbers if (min < 1 || max > 65535) { - logger.warn("Port range '" + port + "' exceeds normal port range (1-65535)"); + // TODO: Add details/use HelpfulSuggestions for these warnings + buildLogger.warn("Port number '" + port + "' is out of usual range (1-65535)."); } + // Add all numbers in range to list for (int portNum = min; portNum <= max; portNum++) { - result.add("" + portNum); + result.add(portNum); } + } - } else { - // Port is neither a single number nor a range - logger.warn("Port '" + port + "' is not a port number"); + return result.build(); + } + } + + /** + * @param className the class name to check + * @return {@code true} if {@code className} is a valid Java class name; {@code false} otherwise + */ + public static boolean isValidJavaClass(String className) { + for (String part : Splitter.on('.').split(className)) { + if (!SourceVersion.isIdentifier(part)) { + return false; } } + return true; + } - return ImmutableList.copyOf(result); + public static Builder builder(BuildLogger buildLogger) { + return new Builder(buildLogger); } private final BuildLogger buildLogger; @@ -267,13 +270,9 @@ static ImmutableList expandPortRanges(List ports, BuildLogger lo private final ImmutableList javaArguments; private final ImmutableList jvmFlags; private final ImmutableMap environmentMap; - private final ImmutableList exposedPorts; + private final ImmutableList exposedPorts; private final Class targetFormat; - public static Builder builder(BuildLogger buildLogger) { - return new Builder(buildLogger); - } - /** Instantiate with {@link Builder#build}. */ private BuildConfiguration( BuildLogger buildLogger, @@ -287,7 +286,7 @@ private BuildConfiguration( ImmutableList javaArguments, ImmutableList jvmFlags, ImmutableMap environmentMap, - ImmutableList exposedPorts, + ImmutableList exposedPorts, Class targetFormat) { this.buildLogger = buildLogger; this.baseImageReference = baseImageReference; @@ -376,7 +375,7 @@ public ImmutableMap getEnvironment() { return environmentMap; } - public ImmutableList getExposedPorts() { + public ImmutableList getExposedPorts() { return exposedPorts; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java index 58771637a6..fb2ab3d9dc 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java @@ -31,7 +31,7 @@ public static class Builder { private ImmutableList entrypoint = ImmutableList.of(); private ImmutableList javaArguments = ImmutableList.of(); - private ImmutableList exposedPorts = ImmutableList.of(); + private ImmutableList exposedPorts = ImmutableList.of(); /** * Sets the environment with a map from environment variable names to values. @@ -98,8 +98,8 @@ public Builder setJavaArguments(List javaArguments) { * appear in the configuration json (e.g. "portNum/tcp") * @return this */ - public Builder setExposedPorts(List exposedPorts) { - this.exposedPorts = ImmutableList.copyOf(exposedPorts); + public Builder setExposedPorts(ImmutableList exposedPorts) { + this.exposedPorts = exposedPorts; return this; } @@ -121,7 +121,7 @@ public Image build() { environmentBuilder.build(), ImmutableList.copyOf(entrypoint), ImmutableList.copyOf(javaArguments), - ImmutableList.copyOf(exposedPorts)); + exposedPorts); } } @@ -142,14 +142,14 @@ public static Builder builder() { private final ImmutableList javaArguments; /** Ports that the container listens on. */ - private final ImmutableList exposedPorts; + private final ImmutableList exposedPorts; private Image( ImageLayers layers, ImmutableList environment, ImmutableList entrypoint, ImmutableList javaArguments, - ImmutableList exposedPorts) { + ImmutableList exposedPorts) { this.layers = layers; this.environmentBuilder = environment; this.entrypoint = entrypoint; @@ -169,7 +169,7 @@ public ImmutableList getJavaArguments() { return javaArguments; } - public ImmutableList getExposedPorts() { + public ImmutableList getExposedPorts() { return exposedPorts; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java index 95d22b0385..2c89f0e98f 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java @@ -20,7 +20,6 @@ import com.google.cloud.tools.jib.image.DescriptorDigest; import com.google.cloud.tools.jib.json.JsonTemplate; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSortedMap; import java.util.*; import javax.annotation.Nullable; @@ -123,10 +122,10 @@ public void setContainerCmd(List cmd) { config.Cmd = cmd; } - public void setContainerExposedPorts(List exposedPorts) { + public void setContainerExposedPorts(List exposedPorts) { SortedMap> result = new TreeMap<>(); - for (String port : exposedPorts) { - result.put(port + "/tcp", Collections.emptyMap()); + for (Integer port : exposedPorts) { + result.put(port.toString(), Collections.emptyMap()); } config.ExposedPorts = ImmutableSortedMap.copyOf(result); } @@ -155,14 +154,13 @@ List getContainerCmd() { } @Nullable - List getContainerExposedPorts() { + List getContainerExposedPorts() { if (config.ExposedPorts == null) { return null; } - List ports = new ArrayList<>(); + List ports = new ArrayList<>(); for (Map.Entry> entry : config.ExposedPorts.entrySet()) { - // Remove the "/tcp" - ports.add(Splitter.on('/').splitToList(entry.getKey()).get(0)); + ports.add(Integer.parseInt(entry.getKey())); } return ports; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java index fe468b3461..5f6b676eac 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java @@ -25,6 +25,7 @@ import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException; import com.google.cloud.tools.jib.image.ReferenceLayer; import com.google.cloud.tools.jib.image.ReferenceNoDiffIdLayer; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; @@ -103,7 +104,8 @@ public static Image toImage( } if (containerConfigurationTemplate.getContainerExposedPorts() != null) { - imageBuilder.setExposedPorts(containerConfigurationTemplate.getContainerExposedPorts()); + imageBuilder.setExposedPorts( + ImmutableList.copyOf(containerConfigurationTemplate.getContainerExposedPorts())); } if (containerConfigurationTemplate.getContainerEnvironment() != null) { diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java index ecf486cdc8..97329d466f 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java @@ -57,7 +57,8 @@ public void testBuilder() { List expectedJavaArguments = Arrays.asList("arg1", "arg2"); List expectedJvmFlags = Arrays.asList("some", "jvm", "flags"); Map expectedEnvironment = ImmutableMap.of("key", "value"); - List expectedExposedPorts = Arrays.asList("1000", "2000"); + List inputPorts = ImmutableList.of("1000", "2000"); + ImmutableList expectedExposedPorts = ImmutableList.of(1000, 2000); Class expectedTargetFormat = OCIManifestTemplate.class; BuildConfiguration.Builder buildConfigurationBuilder = @@ -76,7 +77,7 @@ public void testBuilder() { .setJavaArguments(expectedJavaArguments) .setJvmFlags(expectedJvmFlags) .setEnvironment(expectedEnvironment) - .setExposedPorts(expectedExposedPorts) + .setExposedPorts(inputPorts) .setTargetFormat(OCIManifestTemplate.class); BuildConfiguration buildConfiguration = buildConfigurationBuilder.build(); @@ -186,25 +187,38 @@ public void testValidJavaClassRegex() { @Test public void testExpandPortList() { - List input = Arrays.asList("1000", "2000-2003", "3000 - 3000", "4002-4000"); - ImmutableList expected = - new ImmutableList.Builder() - .add("1000", "2000", "2001", "2002", "2003", "3000", "4000", "4001", "4002") - .build(); - ImmutableList result = BuildConfiguration.expandPortRanges(input, mockLogger); + List input = Arrays.asList("1000", "2000-2003", "3000-3000"); + ImmutableList expected = + new ImmutableList.Builder().add(1000, 2000, 2001, 2002, 2003, 3000).build(); + BuildConfiguration.Builder builder = BuildConfiguration.builder(mockLogger); + ImmutableList result = builder.expandPortRanges(input); Assert.assertEquals(expected, result); - BuildConfiguration.expandPortRanges(Collections.singletonList("abc"), mockLogger); - Mockito.verify(mockLogger).warn("Port 'abc' is not a port number"); + try { + builder.expandPortRanges(Collections.singletonList("abc")); + Assert.fail(); + } catch (NumberFormatException ex) { + Assert.assertEquals( + "Invalid port configuration: 'abc'. Make sure the port is a single number or a range of " + + "two numbers separated with a '-'.", + ex.getMessage()); + } - BuildConfiguration.expandPortRanges(Collections.singletonList("0"), mockLogger); - Mockito.verify(mockLogger).warn("Port number '0' is out of range (1-65535)"); - BuildConfiguration.expandPortRanges(Collections.singletonList("70000"), mockLogger); - Mockito.verify(mockLogger).warn("Port number '70000' is out of range (1-65535)"); + try { + builder.expandPortRanges(Collections.singletonList("4002-4000")); + Assert.fail(); + } catch (NumberFormatException ex) { + Assert.assertEquals( + "Invalid port range '4002-4000'; smaller number must come first.", ex.getMessage()); + } - BuildConfiguration.expandPortRanges(Collections.singletonList("0-400"), mockLogger); - Mockito.verify(mockLogger).warn("Port range '0-400' exceeds normal port range (1-65535)"); - BuildConfiguration.expandPortRanges(Collections.singletonList("500-70000"), mockLogger); - Mockito.verify(mockLogger).warn("Port range '500-70000' exceeds normal port range (1-65535)"); + builder.expandPortRanges(Collections.singletonList("0")); + Mockito.verify(mockLogger).warn("Port number '0' is out of usual range (1-65535)."); + builder.expandPortRanges(Collections.singletonList("70000")); + Mockito.verify(mockLogger).warn("Port number '70000' is out of usual range (1-65535)."); + builder.expandPortRanges(Collections.singletonList("0-400")); + Mockito.verify(mockLogger).warn("Port number '0-400' is out of usual range (1-65535)."); + builder.expandPortRanges(Collections.singletonList("1-70000")); + Mockito.verify(mockLogger).warn("Port number '1-70000' is out of usual range (1-65535)."); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java index 1b63e3ea4c..dfde0cce79 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java @@ -51,7 +51,7 @@ public void test_smokeTest() throws LayerPropertyNotFoundException { .setEnvironmentVariable("VARIABLE", "VALUE") .setEntrypoint(Arrays.asList("some", "command")) .setJavaArguments(Arrays.asList("arg1", "arg2")) - .setExposedPorts(Arrays.asList("port1", "port2")) + .setExposedPorts(ImmutableList.of(1000, 2000)) .addLayer(mockLayer) .build(); @@ -60,6 +60,6 @@ public void test_smokeTest() throws LayerPropertyNotFoundException { Assert.assertEquals(expectedEnvironment, image.getEnvironment()); Assert.assertEquals(Arrays.asList("some", "command"), image.getEntrypoint()); Assert.assertEquals(Arrays.asList("arg1", "arg2"), image.getJavaArguments()); - Assert.assertEquals(Arrays.asList("port1", "port2"), image.getExposedPorts()); + Assert.assertEquals(ImmutableList.of(1000, 2000), image.getExposedPorts()); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java index 3cdfeb3801..5d2141112c 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java @@ -35,14 +35,14 @@ /** Tests for {@link ContainerConfigurationTemplate}. */ public class ContainerConfigurationTemplateTest { - private List exposedPorts; + private List exposedPorts; @Before public void setup() { exposedPorts = new ArrayList<>(); - exposedPorts.add("1000"); - exposedPorts.add("2000"); - exposedPorts.add("3000"); + exposedPorts.add(1000); + exposedPorts.add(2000); + exposedPorts.add(3000); } @Test diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java index 2f510d3370..ea7e6e652f 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java @@ -23,6 +23,7 @@ import com.google.cloud.tools.jib.image.Image; import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException; import com.google.cloud.tools.jib.json.JsonTemplateMapper; +import com.google.common.collect.ImmutableList; import com.google.common.io.ByteStreams; import com.google.common.io.Resources; import java.io.ByteArrayOutputStream; @@ -55,7 +56,7 @@ public void setUp() throws DigestException, LayerPropertyNotFoundException { testImageBuilder.setJavaArguments(Arrays.asList("arg1", "arg2")); - testImageBuilder.setExposedPorts(Arrays.asList("1000", "2000", "3000")); + testImageBuilder.setExposedPorts(ImmutableList.of(1000, 2000, 3000)); DescriptorDigest fakeDigest = DescriptorDigest.fromDigest( diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java index 00be6bbfd7..e815e95dd6 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java @@ -23,6 +23,7 @@ import com.google.cloud.tools.jib.image.LayerCountMismatchException; import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException; import com.google.cloud.tools.jib.json.JsonTemplateMapper; +import com.google.common.collect.ImmutableList; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Path; @@ -105,6 +106,6 @@ private void testToImage_buildable( layers.get(0).getDiffId()); Assert.assertEquals(Arrays.asList("some", "entrypoint", "command"), image.getEntrypoint()); Assert.assertEquals(Arrays.asList("VAR1=VAL1", "VAR2=VAL2"), image.getEnvironment()); - Assert.assertEquals(Arrays.asList("1000", "2000", "3000"), image.getExposedPorts()); + Assert.assertEquals(ImmutableList.of(1000, 2000, 3000), image.getExposedPorts()); } } diff --git a/jib-core/src/test/resources/json/containerconfig.json b/jib-core/src/test/resources/json/containerconfig.json index f4aca7bbf0..c8f8ed3896 100644 --- a/jib-core/src/test/resources/json/containerconfig.json +++ b/jib-core/src/test/resources/json/containerconfig.json @@ -1 +1 @@ -{"created":"1970-01-01T00:00:00Z","architecture":"amd64","os":"linux","config":{"Env":["VAR1=VAL1","VAR2=VAL2"],"Entrypoint":["some","entrypoint","command"],"Cmd":["arg1","arg2"],"ExposedPorts":{"1000/tcp":{},"2000/tcp":{},"3000/tcp":{}}},"rootfs":{"type":"layers","diff_ids":["sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"]}} \ No newline at end of file +{"created":"1970-01-01T00:00:00Z","architecture":"amd64","os":"linux","config":{"Env":["VAR1=VAL1","VAR2=VAL2"],"Entrypoint":["some","entrypoint","command"],"Cmd":["arg1","arg2"],"ExposedPorts":{"1000":{},"2000":{},"3000":{}}},"rootfs":{"type":"layers","diff_ids":["sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"]}} \ No newline at end of file diff --git a/jib-core/src/test/resources/json/translated_ocimanifest.json b/jib-core/src/test/resources/json/translated_ocimanifest.json index b457ed8ec2..6b6d7a2e6d 100644 --- a/jib-core/src/test/resources/json/translated_ocimanifest.json +++ b/jib-core/src/test/resources/json/translated_ocimanifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:d05f4301080b44cf4a4e63e69d9f269d0d07cf0d0d613cacdfe93fb777c4f3a2","size":353},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:2eacce6965972e94786c884de633c2a20efcb2547bbe9cc4a9c355494696ee97","size":341},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file diff --git a/jib-core/src/test/resources/json/translated_v22manifest.json b/jib-core/src/test/resources/json/translated_v22manifest.json index beb0968b0d..83e4f4ab36 100644 --- a/jib-core/src/test/resources/json/translated_v22manifest.json +++ b/jib-core/src/test/resources/json/translated_v22manifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:d05f4301080b44cf4a4e63e69d9f269d0d07cf0d0d613cacdfe93fb777c4f3a2","size":353},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:2eacce6965972e94786c884de633c2a20efcb2547bbe9cc4a9c355494696ee97","size":341},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file From fefd342fc3040c1c4c56c696f0cfed7584deaada Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 12:21:41 -0400 Subject: [PATCH 08/30] Add support for udp --- .../builder/BuildStepsIntegrationTest.java | 20 ++++---- .../tools/jib/builder/BuildConfiguration.java | 41 ++++++++++------ .../google/cloud/tools/jib/image/Image.java | 10 ++-- .../json/ContainerConfigurationTemplate.java | 12 ++--- .../jib/builder/BuildConfigurationTest.java | 49 +++++++++++++------ .../cloud/tools/jib/image/ImageTest.java | 4 +- .../ContainerConfigurationTemplateTest.java | 8 +-- .../image/json/ImageToJsonTranslatorTest.java | 2 +- .../image/json/JsonToImageTranslatorTest.java | 2 +- .../test/resources/json/containerconfig.json | 2 +- .../json/translated_ocimanifest.json | 2 +- .../json/translated_v22manifest.json | 2 +- 12 files changed, 92 insertions(+), 62 deletions(-) diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java index d4b2478291..578ba6a1f4 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java @@ -48,7 +48,7 @@ public void testSteps_forBuildToDockerRegistry() throws Exception { .setTargetImage(ImageReference.of("localhost:5000", "testimage", "testtag")) .setMainClass("HelloWorld") .setJavaArguments(Collections.singletonList("An argument.")) - .setExposedPorts(Arrays.asList("1000", "2000-2003")) + .setExposedPorts(Arrays.asList("1000", "2000-2002/tcp", "3000/udp")) .build(); Path cacheDirectory = temporaryCacheDirectory.newFolder().toPath(); @@ -72,10 +72,10 @@ public void testSteps_forBuildToDockerRegistry() throws Exception { CoreMatchers.containsString( " \"ExposedPorts\": {\n" + " \"1000\": {},\n" - + " \"2000\": {},\n" - + " \"2001\": {},\n" - + " \"2002\": {},\n" - + " \"2003\": {}")); + + " \"2000/tcp\": {},\n" + + " \"2001/tcp\": {},\n" + + " \"2002/tcp\": {},\n" + + " \"3000/udp\": {}")); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", imageReference).run()); } @@ -89,7 +89,7 @@ public void testSteps_forBuildToDockerDaemon() throws Exception { .setTargetImage(ImageReference.of(null, "testdocker", null)) .setMainClass("HelloWorld") .setJavaArguments(Collections.singletonList("An argument.")) - .setExposedPorts(Arrays.asList("1000", "2000-2003")) + .setExposedPorts(Arrays.asList("1000", "2000-2002/tcp", "3000/udp")) .build(); Path cacheDirectory = temporaryCacheDirectory.newFolder().toPath(); @@ -105,10 +105,10 @@ public void testSteps_forBuildToDockerDaemon() throws Exception { CoreMatchers.containsString( " \"ExposedPorts\": {\n" + " \"1000\": {},\n" - + " \"2000\": {},\n" - + " \"2001\": {},\n" - + " \"2002\": {},\n" - + " \"2003\": {}")); + + " \"2000/tcp\": {},\n" + + " \"2001/tcp\": {},\n" + + " \"2002/tcp\": {},\n" + + " \"3000/udp\": {}")); Assert.assertEquals( "Hello, world. An argument.\n", new Command("docker", "run", "testdocker").run()); } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java index 0c3aea094d..dfb5601baf 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java @@ -190,34 +190,45 @@ public BuildConfiguration build() { } /** - * Converts a list of port number/range strings to a list of integers + * Converts/validates a list of ports with ranges to an expanded form without ranges. * - *

Example: ["1000", "2000-2002"] -> [1000, 2000, 2001, 2002] + *

Example: ["1000/tcp", "2000-2002/tcp"] -> ["1000/tcp", "2000/tcp", "2001/tcp", "2002/tcp"] * * @param ports the list of port numbers/ranges * @return the ports as a list of integers * @throws NumberFormatException if any of the ports are in an invalid format or out of range */ @VisibleForTesting - ImmutableList expandPortRanges(List ports) throws NumberFormatException { - ImmutableList.Builder result = new ImmutableList.Builder<>(); + ImmutableList expandPortRanges(List ports) throws NumberFormatException { + ImmutableList.Builder result = new ImmutableList.Builder<>(); for (String port : ports) { - // Make sure configuration is a single number or a range - if (!port.matches("\\d+") && !port.matches("\\d+-\\d+")) { + // Make sure configuration is a single number or a range, with an optional protocol + // Examples: + // 100 + // 200-210 + // 1000/tcp + // 2000/udp + // 500-600/tcp + if (!port.matches("^\\d+(-\\d+)?(\\/tcp|\\/udp)?$")) { throw new NumberFormatException( "Invalid port configuration: '" + port + "'. Make sure the port is a single number or a range of two numbers separated " - + "with a '-'."); + + "with a '-', with or without protocol specified (e.g. '/tcp' or " + + "'/udp')."); } + // Parse protocol + List splitProtocol = Splitter.on("/").splitToList(port); + String protocol = splitProtocol.size() > 1 ? "/" + splitProtocol.get(1) : ""; + // Parse range (or treat as range of min-min if only single port configuration) - List range = Splitter.on('-').splitToList(port); - int min = Integer.parseInt(range.get(0)); + List splitRange = Splitter.on("-").splitToList(splitProtocol.get(0)); + int min = Integer.parseInt(splitRange.get(0)); int max = min; - if (range.size() > 1) { - max = Integer.parseInt(range.get(1)); + if (splitRange.size() > 1) { + max = Integer.parseInt(splitRange.get(1)); } // Error if configured as 'max-min' instead of 'min-max' @@ -234,7 +245,7 @@ ImmutableList expandPortRanges(List ports) throws NumberFormatE // Add all numbers in range to list for (int portNum = min; portNum <= max; portNum++) { - result.add(portNum); + result.add(portNum + protocol); } } @@ -270,7 +281,7 @@ public static Builder builder(BuildLogger buildLogger) { private final ImmutableList javaArguments; private final ImmutableList jvmFlags; private final ImmutableMap environmentMap; - private final ImmutableList exposedPorts; + private final ImmutableList exposedPorts; private final Class targetFormat; /** Instantiate with {@link Builder#build}. */ @@ -286,7 +297,7 @@ private BuildConfiguration( ImmutableList javaArguments, ImmutableList jvmFlags, ImmutableMap environmentMap, - ImmutableList exposedPorts, + ImmutableList exposedPorts, Class targetFormat) { this.buildLogger = buildLogger; this.baseImageReference = baseImageReference; @@ -375,7 +386,7 @@ public ImmutableMap getEnvironment() { return environmentMap; } - public ImmutableList getExposedPorts() { + public ImmutableList getExposedPorts() { return exposedPorts; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java index fb2ab3d9dc..94ac660bec 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java @@ -31,7 +31,7 @@ public static class Builder { private ImmutableList entrypoint = ImmutableList.of(); private ImmutableList javaArguments = ImmutableList.of(); - private ImmutableList exposedPorts = ImmutableList.of(); + private ImmutableList exposedPorts = ImmutableList.of(); /** * Sets the environment with a map from environment variable names to values. @@ -98,7 +98,7 @@ public Builder setJavaArguments(List javaArguments) { * appear in the configuration json (e.g. "portNum/tcp") * @return this */ - public Builder setExposedPorts(ImmutableList exposedPorts) { + public Builder setExposedPorts(ImmutableList exposedPorts) { this.exposedPorts = exposedPorts; return this; } @@ -142,14 +142,14 @@ public static Builder builder() { private final ImmutableList javaArguments; /** Ports that the container listens on. */ - private final ImmutableList exposedPorts; + private final ImmutableList exposedPorts; private Image( ImageLayers layers, ImmutableList environment, ImmutableList entrypoint, ImmutableList javaArguments, - ImmutableList exposedPorts) { + ImmutableList exposedPorts) { this.layers = layers; this.environmentBuilder = environment; this.entrypoint = entrypoint; @@ -169,7 +169,7 @@ public ImmutableList getJavaArguments() { return javaArguments; } - public ImmutableList getExposedPorts() { + public ImmutableList getExposedPorts() { return exposedPorts; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java index 2c89f0e98f..8a10ffb2fe 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java @@ -122,10 +122,10 @@ public void setContainerCmd(List cmd) { config.Cmd = cmd; } - public void setContainerExposedPorts(List exposedPorts) { + public void setContainerExposedPorts(List exposedPorts) { SortedMap> result = new TreeMap<>(); - for (Integer port : exposedPorts) { - result.put(port.toString(), Collections.emptyMap()); + for (String port : exposedPorts) { + result.put(port, Collections.emptyMap()); } config.ExposedPorts = ImmutableSortedMap.copyOf(result); } @@ -154,13 +154,13 @@ List getContainerCmd() { } @Nullable - List getContainerExposedPorts() { + List getContainerExposedPorts() { if (config.ExposedPorts == null) { return null; } - List ports = new ArrayList<>(); + List ports = new ArrayList<>(); for (Map.Entry> entry : config.ExposedPorts.entrySet()) { - ports.add(Integer.parseInt(entry.getKey())); + ports.add(entry.getKey()); } return ports; } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java index 97329d466f..9269f633a0 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/BuildConfigurationTest.java @@ -57,8 +57,7 @@ public void testBuilder() { List expectedJavaArguments = Arrays.asList("arg1", "arg2"); List expectedJvmFlags = Arrays.asList("some", "jvm", "flags"); Map expectedEnvironment = ImmutableMap.of("key", "value"); - List inputPorts = ImmutableList.of("1000", "2000"); - ImmutableList expectedExposedPorts = ImmutableList.of(1000, 2000); + ImmutableList expectedExposedPorts = ImmutableList.of("1000", "2000"); Class expectedTargetFormat = OCIManifestTemplate.class; BuildConfiguration.Builder buildConfigurationBuilder = @@ -77,7 +76,7 @@ public void testBuilder() { .setJavaArguments(expectedJavaArguments) .setJvmFlags(expectedJvmFlags) .setEnvironment(expectedEnvironment) - .setExposedPorts(inputPorts) + .setExposedPorts(expectedExposedPorts) .setTargetFormat(OCIManifestTemplate.class); BuildConfiguration buildConfiguration = buildConfigurationBuilder.build(); @@ -187,21 +186,41 @@ public void testValidJavaClassRegex() { @Test public void testExpandPortList() { - List input = Arrays.asList("1000", "2000-2003", "3000-3000"); - ImmutableList expected = - new ImmutableList.Builder().add(1000, 2000, 2001, 2002, 2003, 3000).build(); + List goodInputs = + Arrays.asList("1000", "2000-2003", "3000-3000", "4000/tcp", "5000/udp", "6000-6002/tcp"); + ImmutableList expected = + new ImmutableList.Builder() + .add( + "1000", + "2000", + "2001", + "2002", + "2003", + "3000", + "4000/tcp", + "5000/udp", + "6000/tcp", + "6001/tcp", + "6002/tcp") + .build(); BuildConfiguration.Builder builder = BuildConfiguration.builder(mockLogger); - ImmutableList result = builder.expandPortRanges(input); + ImmutableList result = builder.expandPortRanges(goodInputs); Assert.assertEquals(expected, result); - try { - builder.expandPortRanges(Collections.singletonList("abc")); - Assert.fail(); - } catch (NumberFormatException ex) { - Assert.assertEquals( - "Invalid port configuration: 'abc'. Make sure the port is a single number or a range of " - + "two numbers separated with a '-'.", - ex.getMessage()); + List badInputs = Arrays.asList("abc", "/udp", "1000/abc", "a100/tcp", "20/udpabc"); + for (String input : badInputs) { + try { + builder.expandPortRanges(Collections.singletonList(input)); + Assert.fail(); + } catch (NumberFormatException ex) { + Assert.assertEquals( + "Invalid port configuration: '" + + input + + "'. Make sure the port is a single number or a range of two numbers separated " + + "with a '-', with or without protocol specified (e.g. '/tcp' or " + + "'/udp').", + ex.getMessage()); + } } try { diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java index dfde0cce79..a3cb99c3d7 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/ImageTest.java @@ -51,7 +51,7 @@ public void test_smokeTest() throws LayerPropertyNotFoundException { .setEnvironmentVariable("VARIABLE", "VALUE") .setEntrypoint(Arrays.asList("some", "command")) .setJavaArguments(Arrays.asList("arg1", "arg2")) - .setExposedPorts(ImmutableList.of(1000, 2000)) + .setExposedPorts(ImmutableList.of("1000", "2000")) .addLayer(mockLayer) .build(); @@ -60,6 +60,6 @@ public void test_smokeTest() throws LayerPropertyNotFoundException { Assert.assertEquals(expectedEnvironment, image.getEnvironment()); Assert.assertEquals(Arrays.asList("some", "command"), image.getEntrypoint()); Assert.assertEquals(Arrays.asList("arg1", "arg2"), image.getJavaArguments()); - Assert.assertEquals(ImmutableList.of(1000, 2000), image.getExposedPorts()); + Assert.assertEquals(ImmutableList.of("1000", "2000"), image.getExposedPorts()); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java index 5d2141112c..899c8c6de4 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java @@ -35,14 +35,14 @@ /** Tests for {@link ContainerConfigurationTemplate}. */ public class ContainerConfigurationTemplateTest { - private List exposedPorts; + private List exposedPorts; @Before public void setup() { exposedPorts = new ArrayList<>(); - exposedPorts.add(1000); - exposedPorts.add(2000); - exposedPorts.add(3000); + exposedPorts.add("1000"); + exposedPorts.add("2000/tcp"); + exposedPorts.add("3000/udp"); } @Test diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java index ea7e6e652f..fbabefc8bd 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java @@ -56,7 +56,7 @@ public void setUp() throws DigestException, LayerPropertyNotFoundException { testImageBuilder.setJavaArguments(Arrays.asList("arg1", "arg2")); - testImageBuilder.setExposedPorts(ImmutableList.of(1000, 2000, 3000)); + testImageBuilder.setExposedPorts(ImmutableList.of("1000", "2000/tcp", "3000/udp")); DescriptorDigest fakeDigest = DescriptorDigest.fromDigest( diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java index e815e95dd6..3097c6f123 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslatorTest.java @@ -106,6 +106,6 @@ private void testToImage_buildable( layers.get(0).getDiffId()); Assert.assertEquals(Arrays.asList("some", "entrypoint", "command"), image.getEntrypoint()); Assert.assertEquals(Arrays.asList("VAR1=VAL1", "VAR2=VAL2"), image.getEnvironment()); - Assert.assertEquals(ImmutableList.of(1000, 2000, 3000), image.getExposedPorts()); + Assert.assertEquals(ImmutableList.of("1000", "2000/tcp", "3000/udp"), image.getExposedPorts()); } } diff --git a/jib-core/src/test/resources/json/containerconfig.json b/jib-core/src/test/resources/json/containerconfig.json index c8f8ed3896..5a04548713 100644 --- a/jib-core/src/test/resources/json/containerconfig.json +++ b/jib-core/src/test/resources/json/containerconfig.json @@ -1 +1 @@ -{"created":"1970-01-01T00:00:00Z","architecture":"amd64","os":"linux","config":{"Env":["VAR1=VAL1","VAR2=VAL2"],"Entrypoint":["some","entrypoint","command"],"Cmd":["arg1","arg2"],"ExposedPorts":{"1000":{},"2000":{},"3000":{}}},"rootfs":{"type":"layers","diff_ids":["sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"]}} \ No newline at end of file +{"created":"1970-01-01T00:00:00Z","architecture":"amd64","os":"linux","config":{"Env":["VAR1=VAL1","VAR2=VAL2"],"Entrypoint":["some","entrypoint","command"],"Cmd":["arg1","arg2"],"ExposedPorts":{"1000":{},"2000/tcp":{},"3000/udp":{}}},"rootfs":{"type":"layers","diff_ids":["sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad"]}} \ No newline at end of file diff --git a/jib-core/src/test/resources/json/translated_ocimanifest.json b/jib-core/src/test/resources/json/translated_ocimanifest.json index 6b6d7a2e6d..0e96752886 100644 --- a/jib-core/src/test/resources/json/translated_ocimanifest.json +++ b/jib-core/src/test/resources/json/translated_ocimanifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:2eacce6965972e94786c884de633c2a20efcb2547bbe9cc4a9c355494696ee97","size":341},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:bd8e1e8905936a1492fdd86587ec6c2d6c557cbfdeaf28c6229e708e0454c79a","size":349},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file diff --git a/jib-core/src/test/resources/json/translated_v22manifest.json b/jib-core/src/test/resources/json/translated_v22manifest.json index 83e4f4ab36..91773a0b9f 100644 --- a/jib-core/src/test/resources/json/translated_v22manifest.json +++ b/jib-core/src/test/resources/json/translated_v22manifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:2eacce6965972e94786c884de633c2a20efcb2547bbe9cc4a9c355494696ee97","size":341},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:bd8e1e8905936a1492fdd86587ec6c2d6c557cbfdeaf28c6229e708e0454c79a","size":349},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:8c662931926fa990b41da3c9f42663a537ccd498130030f9149173a0493832ad","size":1000}]} \ No newline at end of file From 7fa64bbb9300cc3f724c0e8ef8c1516cc755e15f Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 12:32:30 -0400 Subject: [PATCH 09/30] Use builders and expand imports --- .../json/ContainerConfigurationTemplate.java | 18 ++++++++++++------ .../jib/image/json/JsonToImageTranslator.java | 4 +--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java index 8a10ffb2fe..a651abcb0e 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplate.java @@ -20,8 +20,13 @@ import com.google.cloud.tools.jib.image.DescriptorDigest; import com.google.cloud.tools.jib.json.JsonTemplate; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedMap; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; import javax.annotation.Nullable; /** @@ -123,11 +128,12 @@ public void setContainerCmd(List cmd) { } public void setContainerExposedPorts(List exposedPorts) { - SortedMap> result = new TreeMap<>(); + ImmutableSortedMap.Builder> result = + new ImmutableSortedMap.Builder<>(String::compareTo); for (String port : exposedPorts) { result.put(port, Collections.emptyMap()); } - config.ExposedPorts = ImmutableSortedMap.copyOf(result); + config.ExposedPorts = result.build(); } public void addLayerDiffId(DescriptorDigest diffId) { @@ -154,15 +160,15 @@ List getContainerCmd() { } @Nullable - List getContainerExposedPorts() { + ImmutableList getContainerExposedPorts() { if (config.ExposedPorts == null) { return null; } - List ports = new ArrayList<>(); + ImmutableList.Builder ports = new ImmutableList.Builder<>(); for (Map.Entry> entry : config.ExposedPorts.entrySet()) { ports.add(entry.getKey()); } - return ports; + return ports.build(); } @VisibleForTesting diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java index 5f6b676eac..fe468b3461 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java @@ -25,7 +25,6 @@ import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException; import com.google.cloud.tools.jib.image.ReferenceLayer; import com.google.cloud.tools.jib.image.ReferenceNoDiffIdLayer; -import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; @@ -104,8 +103,7 @@ public static Image toImage( } if (containerConfigurationTemplate.getContainerExposedPorts() != null) { - imageBuilder.setExposedPorts( - ImmutableList.copyOf(containerConfigurationTemplate.getContainerExposedPorts())); + imageBuilder.setExposedPorts(containerConfigurationTemplate.getContainerExposedPorts()); } if (containerConfigurationTemplate.getContainerEnvironment() != null) { From a71e7bb1e704c141e60f618b2ccd9160af97a1cf Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 12:34:23 -0400 Subject: [PATCH 10/30] i m p o r t s --- .../jib/image/json/ContainerConfigurationTemplateTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java index 899c8c6de4..40ce3ed1b5 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ContainerConfigurationTemplateTest.java @@ -27,7 +27,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.DigestException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.junit.Assert; import org.junit.Before; import org.junit.Test; From 901c7d8aceccbfc9a02487f75d0c80cadede96fc Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 14:30:46 -0400 Subject: [PATCH 11/30] Feedback/protocol test --- .../jib/docker/DockerContextGenerator.java | 86 +++++++++---------- .../docker/DockerContextGeneratorTest.java | 2 +- jib-core/src/test/resources/sampleDockerfile | 4 +- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index c76d9a6055..1a2725c62a 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -46,6 +46,49 @@ */ public class DockerContextGenerator { + /** + * Formats a list for the Dockerfile's ENTRYPOINT or CMD. + * + * @see https://docs.docker.com/engine/reference/builder/#exec-form-entrypoint-example + * @param items the list of items to join into an array. + * @return a string in the format: ["item1","item2",...] + */ + @VisibleForTesting + static String joinAsJsonArray(List items) { + StringBuilder resultString = new StringBuilder("["); + boolean firstComponent = true; + for (String item : items) { + if (!firstComponent) { + resultString.append(','); + } + + // Escapes quotes. + item = item.replaceAll("\"", Matcher.quoteReplacement("\\\"")); + + resultString.append('"').append(item).append('"'); + firstComponent = false; + } + resultString.append(']'); + + return resultString.toString(); + } + + /** + * Builds a list of Dockerfile "EXPOSE" instructions. + * + * @param exposedPorts the list of ports numbers/ranges to expose + * @return a string containing an EXPOSE instruction for each of the entries + */ + @VisibleForTesting + static String makeExposeItems(List exposedPorts) { + StringBuilder resultString = new StringBuilder(); + for (String port : exposedPorts) { + resultString.append("EXPOSE ").append(port).append('\n'); + } + return resultString.toString(); + } + private final SourceFilesConfiguration sourceFilesConfiguration; @Nullable private String baseImage; @@ -178,47 +221,4 @@ String makeDockerfile() throws IOException { EntrypointBuilder.makeEntrypoint(sourceFilesConfiguration, jvmFlags, mainClass))) .replace("@@CMD@@", joinAsJsonArray(javaArguments)); } - - /** - * Formats a list for the Dockerfile's ENTRYPOINT or CMD. - * - * @see https://docs.docker.com/engine/reference/builder/#exec-form-entrypoint-example - * @param items the list of items to join into an array. - * @return a string in the format: ["item1","item2",...] - */ - @VisibleForTesting - static String joinAsJsonArray(List items) { - StringBuilder resultString = new StringBuilder("["); - boolean firstComponent = true; - for (String item : items) { - if (!firstComponent) { - resultString.append(','); - } - - // Escapes quotes. - item = item.replaceAll("\"", Matcher.quoteReplacement("\\\"")); - - resultString.append('"').append(item).append('"'); - firstComponent = false; - } - resultString.append(']'); - - return resultString.toString(); - } - - /** - * Builds a list of Dockerfile "EXPOSE" items. - * - * @param exposedPorts the list of ports numbers/ranges to expose - * @return a string containing an EXPOSE command for each of the entries - */ - @VisibleForTesting - static String makeExposeItems(List exposedPorts) { - StringBuilder resultString = new StringBuilder(); - for (String port : exposedPorts) { - resultString.append("EXPOSE ").append(port).append("\n"); - } - return resultString.toString(); - } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 90c59ec4fc..7fb6e8f98c 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -141,7 +141,7 @@ public void testMakeDockerfile() throws IOException, URISyntaxException { List expectedJvmFlags = Arrays.asList("-flag", "another\"Flag"); String expectedMainClass = "SomeMainClass"; List expectedJavaArguments = Arrays.asList("arg1", "arg2"); - List exposedPorts = Arrays.asList("1000", "2000-2010"); + List exposedPorts = Arrays.asList("1000/tcp", "2000-2010/udp"); String dockerfile = new DockerContextGenerator(mockSourceFilesConfiguration) diff --git a/jib-core/src/test/resources/sampleDockerfile b/jib-core/src/test/resources/sampleDockerfile index 8de7285c1f..73d372b6d0 100644 --- a/jib-core/src/test/resources/sampleDockerfile +++ b/jib-core/src/test/resources/sampleDockerfile @@ -4,7 +4,7 @@ COPY libs /app/libs/ COPY resources /app/resources/ COPY classes /app/classes/ -EXPOSE 1000 -EXPOSE 2000-2010 +EXPOSE 1000/tcp +EXPOSE 2000-2010/udp ENTRYPOINT ["java","-flag","another\"Flag","-cp","/app/libs/*:/app/resources/:/app/classes/","SomeMainClass"] CMD ["arg1","arg2"] From cc25cd49247bda2373dfde575483b3bc2609424f Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 14:46:17 -0400 Subject: [PATCH 12/30] Use regex for splitting --- .../tools/jib/builder/BuildConfiguration.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java index dfb5601baf..20821630fa 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java @@ -28,6 +28,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.annotation.Nullable; import javax.lang.model.SourceVersion; @@ -201,6 +203,7 @@ public BuildConfiguration build() { @VisibleForTesting ImmutableList expandPortRanges(List ports) throws NumberFormatException { ImmutableList.Builder result = new ImmutableList.Builder<>(); + Pattern portPattern = Pattern.compile("(\\d+)(-\\d+|)(\\/tcp|\\/udp|)"); for (String port : ports) { // Make sure configuration is a single number or a range, with an optional protocol @@ -210,7 +213,9 @@ ImmutableList expandPortRanges(List ports) throws NumberFormatEx // 1000/tcp // 2000/udp // 500-600/tcp - if (!port.matches("^\\d+(-\\d+)?(\\/tcp|\\/udp)?$")) { + Matcher matcher = portPattern.matcher(port); + + if (!matcher.matches()) { throw new NumberFormatException( "Invalid port configuration: '" + port @@ -220,16 +225,13 @@ ImmutableList expandPortRanges(List ports) throws NumberFormatEx } // Parse protocol - List splitProtocol = Splitter.on("/").splitToList(port); - String protocol = splitProtocol.size() > 1 ? "/" + splitProtocol.get(1) : ""; - - // Parse range (or treat as range of min-min if only single port configuration) - List splitRange = Splitter.on("-").splitToList(splitProtocol.get(0)); - int min = Integer.parseInt(splitRange.get(0)); + int min = Integer.parseInt(matcher.group(1)); int max = min; - if (splitRange.size() > 1) { - max = Integer.parseInt(splitRange.get(1)); + if (!matcher.group(2).equals("")) { + // Skip over the hyphen + max = Integer.parseInt(matcher.group(2).substring(1)); } + String protocol = matcher.group(3); // Error if configured as 'max-min' instead of 'min-max' if (min > max) { @@ -245,6 +247,7 @@ ImmutableList expandPortRanges(List ports) throws NumberFormatEx // Add all numbers in range to list for (int portNum = min; portNum <= max; portNum++) { + // TODO: Use a class w/ port number and protocol instead of a string result.add(portNum + protocol); } } From 7c6f7f1c72a6f61f915f9b2493b06317d393519a Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 14:53:48 -0400 Subject: [PATCH 13/30] Stray newline stuff --- .../cloud/tools/jib/docker/DockerContextGenerator.java | 9 +++++++-- jib-core/src/main/resources/DockerfileTemplate | 3 ++- .../tools/jib/docker/DockerContextGeneratorTest.java | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 1a2725c62a..821810fcf8 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -83,8 +83,13 @@ static String joinAsJsonArray(List items) { @VisibleForTesting static String makeExposeItems(List exposedPorts) { StringBuilder resultString = new StringBuilder(); + boolean first = true; for (String port : exposedPorts) { - resultString.append("EXPOSE ").append(port).append('\n'); + if (!first) { + resultString.append('\n'); + } + resultString.append("EXPOSE ").append(port); + first = false; } return resultString.toString(); } @@ -214,7 +219,7 @@ String makeDockerfile() throws IOException { "@@DEPENDENCIES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getDependenciesPathOnImage()) .replace("@@RESOURCES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getResourcesPathOnImage()) .replace("@@CLASSES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getClassesPathOnImage()) - .replace("@@EXPOSED_PORTS@@", makeExposeItems(exposedPorts)) + .replace("@@EXPOSE_INSTRUCTIONS@@", makeExposeItems(exposedPorts)) .replace( "@@ENTRYPOINT@@", joinAsJsonArray( diff --git a/jib-core/src/main/resources/DockerfileTemplate b/jib-core/src/main/resources/DockerfileTemplate index 5e87095d01..d659b60675 100644 --- a/jib-core/src/main/resources/DockerfileTemplate +++ b/jib-core/src/main/resources/DockerfileTemplate @@ -4,5 +4,6 @@ COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@ COPY resources @@RESOURCES_PATH_ON_IMAGE@@ COPY classes @@CLASSES_PATH_ON_IMAGE@@ -@@EXPOSED_PORTS@@ENTRYPOINT @@ENTRYPOINT@@ +@@EXPOSE_INSTRUCTIONS@@ +ENTRYPOINT @@ENTRYPOINT@@ CMD @@CMD@@ diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 7fb6e8f98c..4c0dcb96f2 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -131,7 +131,7 @@ public void testJoinAsJsonArray() { @Test public void testMakeExposeItems() { Assert.assertEquals( - "EXPOSE 1000\nEXPOSE 2000-2010\n", + "EXPOSE 1000\nEXPOSE 2000-2010", DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); } From bfec9bd609f3f4a29c4be9f6b32c176770641710 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 16:25:30 -0400 Subject: [PATCH 14/30] ? --- .../com/google/cloud/tools/jib/builder/BuildConfiguration.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java index 0e28ea1a86..3d41aa7a6f 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/BuildConfiguration.java @@ -200,7 +200,6 @@ public BuildConfiguration build() { } /** - * TODO: Move this to a class in frontend * *

Converts/validates a list of ports with ranges to an expanded form without ranges. From fb2fc0b011832c6fa49a4de7cf8dd3527951795d Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Fri, 22 Jun 2018 16:47:21 -0400 Subject: [PATCH 15/30] ?? --- .../google/cloud/tools/jib/docker/DockerContextGenerator.java | 3 ++- .../cloud/tools/jib/docker/DockerContextGeneratorTest.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index f919ac7b94..d9a796ba8d 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -84,7 +84,8 @@ static String joinAsJsonArray(List items) { @VisibleForTesting static String makeExposeItems(List exposedPorts) { return String.join( - "\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); + System.getProperty("line.separator"), + exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); } private final SourceFilesConfiguration sourceFilesConfiguration; diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 4c0dcb96f2..e042b694f8 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -131,7 +131,7 @@ public void testJoinAsJsonArray() { @Test public void testMakeExposeItems() { Assert.assertEquals( - "EXPOSE 1000\nEXPOSE 2000-2010", + "EXPOSE 1000" + System.getProperty("line.separator") + "EXPOSE 2000-2010", DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); } From c8dc74dddf50c1ff845b218a1e19bfb723507509 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 10:30:39 -0400 Subject: [PATCH 16/30] Try generating dockerfile from string instead of template file --- .../jib/docker/DockerContextGenerator.java | 23 ++++++++++++------- .../src/main/resources/DockerfileTemplate | 9 -------- .../docker/DockerContextGeneratorTest.java | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) delete mode 100644 jib-core/src/main/resources/DockerfileTemplate diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index d9a796ba8d..e160ede439 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -22,7 +22,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.io.MoreFiles; -import com.google.common.io.Resources; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryNotEmptyException; @@ -47,6 +46,18 @@ */ public class DockerContextGenerator { + /** The template to generate the Dockerfile from. */ + private static final String DOCKERFILE_TEMPLATE = + "FROM @@BASE_IMAGE@@\n" + + "\n" + + "COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@\n" + + "COPY resources @@RESOURCES_PATH_ON_IMAGE@@\n" + + "COPY classes @@CLASSES_PATH_ON_IMAGE@@\n" + + "\n" + + "@@EXPOSE_INSTRUCTIONS@@\n" + + "ENTRYPOINT @@ENTRYPOINT@@\n" + + "CMD @@CMD@@\n"; + /** * Formats a list for the Dockerfile's ENTRYPOINT or CMD. * @@ -84,8 +95,7 @@ static String joinAsJsonArray(List items) { @VisibleForTesting static String makeExposeItems(List exposedPorts) { return String.join( - System.getProperty("line.separator"), - exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); + "\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); } private final SourceFilesConfiguration sourceFilesConfiguration; @@ -195,7 +205,7 @@ public void generate(Path targetDirectory) throws IOException { } /** - * Makes a {@code Dockerfile} from the {@code DockerfileTemplate}. + * Makes a {@code Dockerfile} from the {@code DOCKERFILE_TEMPLATE}. * * @return the {@code Dockerfile} contents. * @throws IOException if reading the Dockerfile template fails. @@ -204,10 +214,7 @@ public void generate(Path targetDirectory) throws IOException { String makeDockerfile() throws IOException { Preconditions.checkNotNull(baseImage); - String dockerfileTemplate = - Resources.toString(Resources.getResource("DockerfileTemplate"), StandardCharsets.UTF_8); - - return dockerfileTemplate + return DOCKERFILE_TEMPLATE .replace("@@BASE_IMAGE@@", baseImage) .replace( "@@DEPENDENCIES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getDependenciesPathOnImage()) diff --git a/jib-core/src/main/resources/DockerfileTemplate b/jib-core/src/main/resources/DockerfileTemplate deleted file mode 100644 index d659b60675..0000000000 --- a/jib-core/src/main/resources/DockerfileTemplate +++ /dev/null @@ -1,9 +0,0 @@ -FROM @@BASE_IMAGE@@ - -COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@ -COPY resources @@RESOURCES_PATH_ON_IMAGE@@ -COPY classes @@CLASSES_PATH_ON_IMAGE@@ - -@@EXPOSE_INSTRUCTIONS@@ -ENTRYPOINT @@ENTRYPOINT@@ -CMD @@CMD@@ diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index e042b694f8..4c0dcb96f2 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -131,7 +131,7 @@ public void testJoinAsJsonArray() { @Test public void testMakeExposeItems() { Assert.assertEquals( - "EXPOSE 1000" + System.getProperty("line.separator") + "EXPOSE 2000-2010", + "EXPOSE 1000\nEXPOSE 2000-2010", DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); } From 1a719190b8edb1e97631af1008905c1c05226c4f Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 11:07:19 -0400 Subject: [PATCH 17/30] Try specifying carriage return --- .../jib/docker/DockerContextGenerator.java | 23 +++++++++---------- .../docker/DockerContextGeneratorTest.java | 20 ++++++++++++---- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index e160ede439..6f4adcf470 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -48,15 +48,15 @@ public class DockerContextGenerator { /** The template to generate the Dockerfile from. */ private static final String DOCKERFILE_TEMPLATE = - "FROM @@BASE_IMAGE@@\n" - + "\n" - + "COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@\n" - + "COPY resources @@RESOURCES_PATH_ON_IMAGE@@\n" - + "COPY classes @@CLASSES_PATH_ON_IMAGE@@\n" - + "\n" - + "@@EXPOSE_INSTRUCTIONS@@\n" - + "ENTRYPOINT @@ENTRYPOINT@@\n" - + "CMD @@CMD@@\n"; + "FROM @@BASE_IMAGE@@\r\n" + + "\r\n" + + "COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@\r\n" + + "COPY resources @@RESOURCES_PATH_ON_IMAGE@@\r\n" + + "COPY classes @@CLASSES_PATH_ON_IMAGE@@\r\n" + + "\r\n" + + "@@EXPOSE_INSTRUCTIONS@@\r\n" + + "ENTRYPOINT @@ENTRYPOINT@@\r\n" + + "CMD @@CMD@@\r\n"; /** * Formats a list for the Dockerfile's ENTRYPOINT or CMD. @@ -95,7 +95,7 @@ static String joinAsJsonArray(List items) { @VisibleForTesting static String makeExposeItems(List exposedPorts) { return String.join( - "\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); + "\r\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); } private final SourceFilesConfiguration sourceFilesConfiguration; @@ -208,10 +208,9 @@ public void generate(Path targetDirectory) throws IOException { * Makes a {@code Dockerfile} from the {@code DOCKERFILE_TEMPLATE}. * * @return the {@code Dockerfile} contents. - * @throws IOException if reading the Dockerfile template fails. */ @VisibleForTesting - String makeDockerfile() throws IOException { + String makeDockerfile() { Preconditions.checkNotNull(baseImage); return DOCKERFILE_TEMPLATE diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 4c0dcb96f2..ea03254f23 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -45,6 +45,18 @@ @RunWith(MockitoJUnitRunner.class) public class DockerContextGeneratorTest { + private static final String SAMPLE_DOCKERFILE = + "FROM somebaseimage\r\n" + + "\r\n" + + "COPY libs /app/libs/\r\n" + + "COPY resources /app/resources/\r\n" + + "COPY classes /app/classes/\r\n" + + "\r\n" + + "EXPOSE 1000/tcp\r\n" + + "EXPOSE 2000-2010/udp\r\n" + + "ENTRYPOINT [\"java\",\"-flag\",\"another\\\"Flag\",\"-cp\",\"/app/libs/*:/app/resources/:/app/classes/\",\"SomeMainClass\"]\r\n" + + "CMD [\"arg1\",\"arg2\"]\r\n"; + private static void assertSameFiles(Path directory1, Path directory2) throws IOException { Deque directory1Paths = new ArrayDeque<>(new DirectoryWalker(directory1).walk()); @@ -131,12 +143,12 @@ public void testJoinAsJsonArray() { @Test public void testMakeExposeItems() { Assert.assertEquals( - "EXPOSE 1000\nEXPOSE 2000-2010", + "EXPOSE 1000\r\nEXPOSE 2000-2010", DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); } @Test - public void testMakeDockerfile() throws IOException, URISyntaxException { + public void testMakeDockerfile() { String expectedBaseImage = "somebaseimage"; List expectedJvmFlags = Arrays.asList("-flag", "another\"Flag"); String expectedMainClass = "SomeMainClass"; @@ -152,8 +164,8 @@ public void testMakeDockerfile() throws IOException, URISyntaxException { .setExposedPorts(exposedPorts) .makeDockerfile(); - Path sampleDockerfile = Paths.get(Resources.getResource("sampleDockerfile").toURI()); Assert.assertArrayEquals( - Files.readAllBytes(sampleDockerfile), dockerfile.getBytes(StandardCharsets.UTF_8)); + SAMPLE_DOCKERFILE.getBytes(StandardCharsets.UTF_8), + dockerfile.getBytes(StandardCharsets.UTF_8)); } } From ddf83369c31390b7e48cb9621e8763a4abff0e90 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 11:38:26 -0400 Subject: [PATCH 18/30] Revert "Try specifying carriage return" This reverts commit 1a719190b8edb1e97631af1008905c1c05226c4f. --- .../jib/docker/DockerContextGenerator.java | 23 ++++++++++--------- .../docker/DockerContextGeneratorTest.java | 20 ++++------------ 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 6f4adcf470..e160ede439 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -48,15 +48,15 @@ public class DockerContextGenerator { /** The template to generate the Dockerfile from. */ private static final String DOCKERFILE_TEMPLATE = - "FROM @@BASE_IMAGE@@\r\n" - + "\r\n" - + "COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@\r\n" - + "COPY resources @@RESOURCES_PATH_ON_IMAGE@@\r\n" - + "COPY classes @@CLASSES_PATH_ON_IMAGE@@\r\n" - + "\r\n" - + "@@EXPOSE_INSTRUCTIONS@@\r\n" - + "ENTRYPOINT @@ENTRYPOINT@@\r\n" - + "CMD @@CMD@@\r\n"; + "FROM @@BASE_IMAGE@@\n" + + "\n" + + "COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@\n" + + "COPY resources @@RESOURCES_PATH_ON_IMAGE@@\n" + + "COPY classes @@CLASSES_PATH_ON_IMAGE@@\n" + + "\n" + + "@@EXPOSE_INSTRUCTIONS@@\n" + + "ENTRYPOINT @@ENTRYPOINT@@\n" + + "CMD @@CMD@@\n"; /** * Formats a list for the Dockerfile's ENTRYPOINT or CMD. @@ -95,7 +95,7 @@ static String joinAsJsonArray(List items) { @VisibleForTesting static String makeExposeItems(List exposedPorts) { return String.join( - "\r\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); + "\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); } private final SourceFilesConfiguration sourceFilesConfiguration; @@ -208,9 +208,10 @@ public void generate(Path targetDirectory) throws IOException { * Makes a {@code Dockerfile} from the {@code DOCKERFILE_TEMPLATE}. * * @return the {@code Dockerfile} contents. + * @throws IOException if reading the Dockerfile template fails. */ @VisibleForTesting - String makeDockerfile() { + String makeDockerfile() throws IOException { Preconditions.checkNotNull(baseImage); return DOCKERFILE_TEMPLATE diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index ea03254f23..4c0dcb96f2 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -45,18 +45,6 @@ @RunWith(MockitoJUnitRunner.class) public class DockerContextGeneratorTest { - private static final String SAMPLE_DOCKERFILE = - "FROM somebaseimage\r\n" - + "\r\n" - + "COPY libs /app/libs/\r\n" - + "COPY resources /app/resources/\r\n" - + "COPY classes /app/classes/\r\n" - + "\r\n" - + "EXPOSE 1000/tcp\r\n" - + "EXPOSE 2000-2010/udp\r\n" - + "ENTRYPOINT [\"java\",\"-flag\",\"another\\\"Flag\",\"-cp\",\"/app/libs/*:/app/resources/:/app/classes/\",\"SomeMainClass\"]\r\n" - + "CMD [\"arg1\",\"arg2\"]\r\n"; - private static void assertSameFiles(Path directory1, Path directory2) throws IOException { Deque directory1Paths = new ArrayDeque<>(new DirectoryWalker(directory1).walk()); @@ -143,12 +131,12 @@ public void testJoinAsJsonArray() { @Test public void testMakeExposeItems() { Assert.assertEquals( - "EXPOSE 1000\r\nEXPOSE 2000-2010", + "EXPOSE 1000\nEXPOSE 2000-2010", DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); } @Test - public void testMakeDockerfile() { + public void testMakeDockerfile() throws IOException, URISyntaxException { String expectedBaseImage = "somebaseimage"; List expectedJvmFlags = Arrays.asList("-flag", "another\"Flag"); String expectedMainClass = "SomeMainClass"; @@ -164,8 +152,8 @@ public void testMakeDockerfile() { .setExposedPorts(exposedPorts) .makeDockerfile(); + Path sampleDockerfile = Paths.get(Resources.getResource("sampleDockerfile").toURI()); Assert.assertArrayEquals( - SAMPLE_DOCKERFILE.getBytes(StandardCharsets.UTF_8), - dockerfile.getBytes(StandardCharsets.UTF_8)); + Files.readAllBytes(sampleDockerfile), dockerfile.getBytes(StandardCharsets.UTF_8)); } } From aab244a207908a2e10cb643d6b7f28899dfdbffc Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 11:38:53 -0400 Subject: [PATCH 19/30] Revert "Try generating dockerfile from string instead of template file" This reverts commit c8dc74dddf50c1ff845b218a1e19bfb723507509. --- .../jib/docker/DockerContextGenerator.java | 23 +++++++------------ .../src/main/resources/DockerfileTemplate | 9 ++++++++ .../docker/DockerContextGeneratorTest.java | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 jib-core/src/main/resources/DockerfileTemplate diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index e160ede439..d9a796ba8d 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -22,6 +22,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.io.MoreFiles; +import com.google.common.io.Resources; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryNotEmptyException; @@ -46,18 +47,6 @@ */ public class DockerContextGenerator { - /** The template to generate the Dockerfile from. */ - private static final String DOCKERFILE_TEMPLATE = - "FROM @@BASE_IMAGE@@\n" - + "\n" - + "COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@\n" - + "COPY resources @@RESOURCES_PATH_ON_IMAGE@@\n" - + "COPY classes @@CLASSES_PATH_ON_IMAGE@@\n" - + "\n" - + "@@EXPOSE_INSTRUCTIONS@@\n" - + "ENTRYPOINT @@ENTRYPOINT@@\n" - + "CMD @@CMD@@\n"; - /** * Formats a list for the Dockerfile's ENTRYPOINT or CMD. * @@ -95,7 +84,8 @@ static String joinAsJsonArray(List items) { @VisibleForTesting static String makeExposeItems(List exposedPorts) { return String.join( - "\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); + System.getProperty("line.separator"), + exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); } private final SourceFilesConfiguration sourceFilesConfiguration; @@ -205,7 +195,7 @@ public void generate(Path targetDirectory) throws IOException { } /** - * Makes a {@code Dockerfile} from the {@code DOCKERFILE_TEMPLATE}. + * Makes a {@code Dockerfile} from the {@code DockerfileTemplate}. * * @return the {@code Dockerfile} contents. * @throws IOException if reading the Dockerfile template fails. @@ -214,7 +204,10 @@ public void generate(Path targetDirectory) throws IOException { String makeDockerfile() throws IOException { Preconditions.checkNotNull(baseImage); - return DOCKERFILE_TEMPLATE + String dockerfileTemplate = + Resources.toString(Resources.getResource("DockerfileTemplate"), StandardCharsets.UTF_8); + + return dockerfileTemplate .replace("@@BASE_IMAGE@@", baseImage) .replace( "@@DEPENDENCIES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getDependenciesPathOnImage()) diff --git a/jib-core/src/main/resources/DockerfileTemplate b/jib-core/src/main/resources/DockerfileTemplate new file mode 100644 index 0000000000..d659b60675 --- /dev/null +++ b/jib-core/src/main/resources/DockerfileTemplate @@ -0,0 +1,9 @@ +FROM @@BASE_IMAGE@@ + +COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@ +COPY resources @@RESOURCES_PATH_ON_IMAGE@@ +COPY classes @@CLASSES_PATH_ON_IMAGE@@ + +@@EXPOSE_INSTRUCTIONS@@ +ENTRYPOINT @@ENTRYPOINT@@ +CMD @@CMD@@ diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 4c0dcb96f2..e042b694f8 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -131,7 +131,7 @@ public void testJoinAsJsonArray() { @Test public void testMakeExposeItems() { Assert.assertEquals( - "EXPOSE 1000\nEXPOSE 2000-2010", + "EXPOSE 1000" + System.getProperty("line.separator") + "EXPOSE 2000-2010", DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); } From 964d85adbb8edbe89a417bf5ee2992f7821837fe Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 12:14:28 -0400 Subject: [PATCH 20/30] testing --- .../cloud/tools/jib/docker/DockerContextGenerator.java | 6 ++++-- .../cloud/tools/jib/docker/DockerContextGeneratorTest.java | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index d9a796ba8d..c57ca320fb 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -84,8 +84,7 @@ static String joinAsJsonArray(List items) { @VisibleForTesting static String makeExposeItems(List exposedPorts) { return String.join( - System.getProperty("line.separator"), - exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); + "\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); } private final SourceFilesConfiguration sourceFilesConfiguration; @@ -190,8 +189,11 @@ public void generate(Path targetDirectory) throws IOException { FileOperations.copy(sourceFilesConfiguration.getClassesFiles(), classesDir); // Creates the Dockerfile. + System.out.println( + "Length before write: " + makeDockerfile().getBytes(StandardCharsets.UTF_8).length); Files.write( targetDirectory.resolve("Dockerfile"), makeDockerfile().getBytes(StandardCharsets.UTF_8)); + System.out.println("Length after write: " + Files.size(targetDirectory.resolve("Dockerfile"))); } /** diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index e042b694f8..2a9fdfb6b2 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -131,7 +131,7 @@ public void testJoinAsJsonArray() { @Test public void testMakeExposeItems() { Assert.assertEquals( - "EXPOSE 1000" + System.getProperty("line.separator") + "EXPOSE 2000-2010", + "EXPOSE 1000\nEXPOSE 2000-2010", DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); } @@ -153,6 +153,8 @@ public void testMakeDockerfile() throws IOException, URISyntaxException { .makeDockerfile(); Path sampleDockerfile = Paths.get(Resources.getResource("sampleDockerfile").toURI()); + System.out.println("Length before read: " + Files.size(sampleDockerfile)); + System.out.println("Length after read: " + Files.readAllBytes(sampleDockerfile).length); Assert.assertArrayEquals( Files.readAllBytes(sampleDockerfile), dockerfile.getBytes(StandardCharsets.UTF_8)); } From 9185594c9d7d14e4b26b3afca562a0c9ee8a0336 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 12:24:57 -0400 Subject: [PATCH 21/30] Try another thing --- .../tools/jib/docker/DockerContextGenerator.java | 15 +++++++++------ .../jib/docker/DockerContextGeneratorTest.java | 2 -- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index c57ca320fb..9d11c0e1a0 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -24,10 +24,12 @@ import com.google.common.io.MoreFiles; import com.google.common.io.Resources; import java.io.IOException; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; @@ -160,8 +162,9 @@ public DockerContextGenerator setExposedPorts(List exposedPorts) { * * @param targetDirectory the directory to generate the Docker context in. * @throws IOException if the export fails. + * @throws URISyntaxException if {@code DockerfileTemplate} path cannot be resolved. */ - public void generate(Path targetDirectory) throws IOException { + public void generate(Path targetDirectory) throws IOException, URISyntaxException { Preconditions.checkNotNull(baseImage); // Deletes the targetDir if it exists. @@ -189,11 +192,8 @@ public void generate(Path targetDirectory) throws IOException { FileOperations.copy(sourceFilesConfiguration.getClassesFiles(), classesDir); // Creates the Dockerfile. - System.out.println( - "Length before write: " + makeDockerfile().getBytes(StandardCharsets.UTF_8).length); Files.write( targetDirectory.resolve("Dockerfile"), makeDockerfile().getBytes(StandardCharsets.UTF_8)); - System.out.println("Length after write: " + Files.size(targetDirectory.resolve("Dockerfile"))); } /** @@ -201,13 +201,16 @@ public void generate(Path targetDirectory) throws IOException { * * @return the {@code Dockerfile} contents. * @throws IOException if reading the Dockerfile template fails. + * @throws URISyntaxException if {@code DockerfileTemplate} path cannot be resolved. */ @VisibleForTesting - String makeDockerfile() throws IOException { + String makeDockerfile() throws IOException, URISyntaxException { Preconditions.checkNotNull(baseImage); String dockerfileTemplate = - Resources.toString(Resources.getResource("DockerfileTemplate"), StandardCharsets.UTF_8); + new String( + Files.readAllBytes(Paths.get(Resources.getResource("DockerfileTemplate").toURI())), + StandardCharsets.UTF_8); return dockerfileTemplate .replace("@@BASE_IMAGE@@", baseImage) diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 2a9fdfb6b2..4c0dcb96f2 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -153,8 +153,6 @@ public void testMakeDockerfile() throws IOException, URISyntaxException { .makeDockerfile(); Path sampleDockerfile = Paths.get(Resources.getResource("sampleDockerfile").toURI()); - System.out.println("Length before read: " + Files.size(sampleDockerfile)); - System.out.println("Length after read: " + Files.readAllBytes(sampleDockerfile).length); Assert.assertArrayEquals( Files.readAllBytes(sampleDockerfile), dockerfile.getBytes(StandardCharsets.UTF_8)); } From da15400c067f0fc6ace4384a417acf42f3345680 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 12:35:35 -0400 Subject: [PATCH 22/30] hm --- .../google/cloud/tools/jib/docker/DockerContextGenerator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 9d11c0e1a0..049f6e8a59 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -207,10 +207,14 @@ public void generate(Path targetDirectory) throws IOException, URISyntaxExceptio String makeDockerfile() throws IOException, URISyntaxException { Preconditions.checkNotNull(baseImage); + System.out.println( + "Template length before read: " + + Files.size(Paths.get(Resources.getResource("DockerfileTemplate").toURI()))); String dockerfileTemplate = new String( Files.readAllBytes(Paths.get(Resources.getResource("DockerfileTemplate").toURI())), StandardCharsets.UTF_8); + System.out.println("Template length after read: " + dockerfileTemplate.length()); return dockerfileTemplate .replace("@@BASE_IMAGE@@", baseImage) From 165a0d3a18436e95bb73b887ac57b991b627057b Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 13:24:01 -0400 Subject: [PATCH 23/30] maybe --- .../jib/docker/DockerContextGenerator.java | 18 ++++-------------- .../jib/docker/DockerContextGeneratorTest.java | 5 +++-- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 049f6e8a59..3bf0b8602b 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -24,7 +24,6 @@ import com.google.common.io.MoreFiles; import com.google.common.io.Resources; import java.io.IOException; -import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; @@ -162,9 +161,8 @@ public DockerContextGenerator setExposedPorts(List exposedPorts) { * * @param targetDirectory the directory to generate the Docker context in. * @throws IOException if the export fails. - * @throws URISyntaxException if {@code DockerfileTemplate} path cannot be resolved. */ - public void generate(Path targetDirectory) throws IOException, URISyntaxException { + public void generate(Path targetDirectory) throws IOException { Preconditions.checkNotNull(baseImage); // Deletes the targetDir if it exists. @@ -201,22 +199,14 @@ public void generate(Path targetDirectory) throws IOException, URISyntaxExceptio * * @return the {@code Dockerfile} contents. * @throws IOException if reading the Dockerfile template fails. - * @throws URISyntaxException if {@code DockerfileTemplate} path cannot be resolved. */ @VisibleForTesting - String makeDockerfile() throws IOException, URISyntaxException { + String makeDockerfile() throws IOException { Preconditions.checkNotNull(baseImage); - System.out.println( - "Template length before read: " - + Files.size(Paths.get(Resources.getResource("DockerfileTemplate").toURI()))); - String dockerfileTemplate = - new String( - Files.readAllBytes(Paths.get(Resources.getResource("DockerfileTemplate").toURI())), - StandardCharsets.UTF_8); - System.out.println("Template length after read: " + dockerfileTemplate.length()); + Path dockerfileTemplate = Paths.get(Resources.getResource("DockerfileTemplate").getPath()); - return dockerfileTemplate + return String.join("\n", Files.readAllLines(dockerfileTemplate)) .replace("@@BASE_IMAGE@@", baseImage) .replace( "@@DEPENDENCIES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getDependenciesPathOnImage()) diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 4c0dcb96f2..5fa4c9831f 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -153,7 +153,8 @@ public void testMakeDockerfile() throws IOException, URISyntaxException { .makeDockerfile(); Path sampleDockerfile = Paths.get(Resources.getResource("sampleDockerfile").toURI()); - Assert.assertArrayEquals( - Files.readAllBytes(sampleDockerfile), dockerfile.getBytes(StandardCharsets.UTF_8)); + Assert.assertEquals( + String.join("\n", Files.readAllLines(sampleDockerfile)), + new String(dockerfile.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)); } } From 213d32ce2fd6ed64c930b480cfc4cc0d821520cc Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 14:38:25 -0400 Subject: [PATCH 24/30] Try reading/writing line by line --- .../tools/jib/docker/DockerContextGenerator.java | 14 +++++++------- .../jib/docker/DockerContextGeneratorTest.java | 11 ++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 3bf0b8602b..994f6bc800 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -28,7 +28,6 @@ import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; @@ -159,8 +158,8 @@ public DockerContextGenerator setExposedPorts(List exposedPorts) { /** * Creates the Docker context in {@code #targetDirectory}. * - * @param targetDirectory the directory to generate the Docker context in. - * @throws IOException if the export fails. + * @param targetDirectory the directory to generate the Docker context in + * @throws IOException if the export fails */ public void generate(Path targetDirectory) throws IOException { Preconditions.checkNotNull(baseImage); @@ -197,16 +196,17 @@ public void generate(Path targetDirectory) throws IOException { /** * Makes a {@code Dockerfile} from the {@code DockerfileTemplate}. * - * @return the {@code Dockerfile} contents. - * @throws IOException if reading the Dockerfile template fails. + * @return the {@code Dockerfile} contents + * @throws IOException if reading the Dockerfile template fails */ @VisibleForTesting String makeDockerfile() throws IOException { Preconditions.checkNotNull(baseImage); - Path dockerfileTemplate = Paths.get(Resources.getResource("DockerfileTemplate").getPath()); + List dockerfileTemplate = + Resources.readLines(Resources.getResource("DockerfileTemplate"), StandardCharsets.UTF_8); - return String.join("\n", Files.readAllLines(dockerfileTemplate)) + return String.join("\n", dockerfileTemplate) .replace("@@BASE_IMAGE@@", baseImage) .replace( "@@DEPENDENCIES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getDependenciesPathOnImage()) diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 5fa4c9831f..722b08d1df 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -136,7 +136,7 @@ public void testMakeExposeItems() { } @Test - public void testMakeDockerfile() throws IOException, URISyntaxException { + public void testMakeDockerfile() throws IOException { String expectedBaseImage = "somebaseimage"; List expectedJvmFlags = Arrays.asList("-flag", "another\"Flag"); String expectedMainClass = "SomeMainClass"; @@ -152,9 +152,10 @@ public void testMakeDockerfile() throws IOException, URISyntaxException { .setExposedPorts(exposedPorts) .makeDockerfile(); - Path sampleDockerfile = Paths.get(Resources.getResource("sampleDockerfile").toURI()); - Assert.assertEquals( - String.join("\n", Files.readAllLines(sampleDockerfile)), - new String(dockerfile.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)); + List sampleDockerfile = + Resources.readLines(Resources.getResource("sampleDockerfile"), StandardCharsets.UTF_8); + Assert.assertArrayEquals( + String.join("\n", sampleDockerfile).getBytes(StandardCharsets.UTF_8), + dockerfile.getBytes(StandardCharsets.UTF_8)); } } From 8036cb35a14d8f856068d2a29a751d9bf27ba46c Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 14:55:25 -0400 Subject: [PATCH 25/30] Consolidate joinAsJsonArray --- .../jib/docker/DockerContextGenerator.java | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 994f6bc800..5453467e06 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -57,22 +57,14 @@ public class DockerContextGenerator { */ @VisibleForTesting static String joinAsJsonArray(List items) { - StringBuilder resultString = new StringBuilder("["); - boolean firstComponent = true; - for (String item : items) { - if (!firstComponent) { - resultString.append(','); - } - - // Escapes quotes. - item = item.replaceAll("\"", Matcher.quoteReplacement("\\\"")); - - resultString.append('"').append(item).append('"'); - firstComponent = false; - } - resultString.append(']'); - - return resultString.toString(); + return "[" + + String.join( + ",", + items + .stream() + .map(item -> "\"" + item.replaceAll("\"", Matcher.quoteReplacement("\\\"")) + "\"") + .collect(Collectors.toList())) + + "]"; } /** From 0324e2aeeee7f20ca048a37a1d3daf4467c6cb51 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 15:13:36 -0400 Subject: [PATCH 26/30] Remove template, cleanup --- .../jib/docker/DockerContextGenerator.java | 40 +++++++++---------- .../src/main/resources/DockerfileTemplate | 9 ----- .../docker/DockerContextGeneratorTest.java | 5 ++- 3 files changed, 21 insertions(+), 33 deletions(-) delete mode 100644 jib-core/src/main/resources/DockerfileTemplate diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 5453467e06..4daeb4c658 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -22,7 +22,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.io.MoreFiles; -import com.google.common.io.Resources; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryNotEmptyException; @@ -74,7 +73,7 @@ static String joinAsJsonArray(List items) { * @return a string containing an EXPOSE instruction for each of the entries */ @VisibleForTesting - static String makeExposeItems(List exposedPorts) { + static String makeExposeInstructions(List exposedPorts) { return String.join( "\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); } @@ -186,29 +185,26 @@ public void generate(Path targetDirectory) throws IOException { } /** - * Makes a {@code Dockerfile} from the {@code DockerfileTemplate}. + * Makes the contents of a {@code Dockerfile} using configuration data. * * @return the {@code Dockerfile} contents - * @throws IOException if reading the Dockerfile template fails */ @VisibleForTesting - String makeDockerfile() throws IOException { - Preconditions.checkNotNull(baseImage); - - List dockerfileTemplate = - Resources.readLines(Resources.getResource("DockerfileTemplate"), StandardCharsets.UTF_8); - - return String.join("\n", dockerfileTemplate) - .replace("@@BASE_IMAGE@@", baseImage) - .replace( - "@@DEPENDENCIES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getDependenciesPathOnImage()) - .replace("@@RESOURCES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getResourcesPathOnImage()) - .replace("@@CLASSES_PATH_ON_IMAGE@@", sourceFilesConfiguration.getClassesPathOnImage()) - .replace("@@EXPOSE_INSTRUCTIONS@@", makeExposeItems(exposedPorts)) - .replace( - "@@ENTRYPOINT@@", - joinAsJsonArray( - EntrypointBuilder.makeEntrypoint(sourceFilesConfiguration, jvmFlags, mainClass))) - .replace("@@CMD@@", joinAsJsonArray(javaArguments)); + String makeDockerfile() { + return "FROM " + + Preconditions.checkNotNull(baseImage) + + "\n\nCOPY libs " + + sourceFilesConfiguration.getDependenciesPathOnImage() + + "\nCOPY resources " + + sourceFilesConfiguration.getResourcesPathOnImage() + + "\nCOPY classes " + + sourceFilesConfiguration.getClassesPathOnImage() + + "\n\n" + + makeExposeInstructions(exposedPorts) + + "\nENTRYPOINT " + + joinAsJsonArray( + EntrypointBuilder.makeEntrypoint(sourceFilesConfiguration, jvmFlags, mainClass)) + + "\nCMD " + + joinAsJsonArray(javaArguments); } } diff --git a/jib-core/src/main/resources/DockerfileTemplate b/jib-core/src/main/resources/DockerfileTemplate deleted file mode 100644 index d659b60675..0000000000 --- a/jib-core/src/main/resources/DockerfileTemplate +++ /dev/null @@ -1,9 +0,0 @@ -FROM @@BASE_IMAGE@@ - -COPY libs @@DEPENDENCIES_PATH_ON_IMAGE@@ -COPY resources @@RESOURCES_PATH_ON_IMAGE@@ -COPY classes @@CLASSES_PATH_ON_IMAGE@@ - -@@EXPOSE_INSTRUCTIONS@@ -ENTRYPOINT @@ENTRYPOINT@@ -CMD @@CMD@@ diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 722b08d1df..a71c90217d 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -129,10 +129,10 @@ public void testJoinAsJsonArray() { } @Test - public void testMakeExposeItems() { + public void testMakeExposeInstructions() { Assert.assertEquals( "EXPOSE 1000\nEXPOSE 2000-2010", - DockerContextGenerator.makeExposeItems(ImmutableList.of("1000", "2000-2010"))); + DockerContextGenerator.makeExposeInstructions(ImmutableList.of("1000", "2000-2010"))); } @Test @@ -152,6 +152,7 @@ public void testMakeDockerfile() throws IOException { .setExposedPorts(exposedPorts) .makeDockerfile(); + // Need to split/rejoin the string here to avoid cross-platform troubles List sampleDockerfile = Resources.readLines(Resources.getResource("sampleDockerfile"), StandardCharsets.UTF_8); Assert.assertArrayEquals( From a0aed3d153e212fe31e364ccf9511bbab1fee044 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 16:05:50 -0400 Subject: [PATCH 27/30] Add javadoc example for makeDockerfile() --- .../tools/jib/docker/DockerContextGenerator.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 4daeb4c658..4518c5b393 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -185,7 +185,20 @@ public void generate(Path targetDirectory) throws IOException { } /** - * Makes the contents of a {@code Dockerfile} using configuration data. + * Makes the contents of a {@code Dockerfile} using configuration data, in the following format: + * + *

{@code
+   * FROM [base image]
+   *
+   * COPY libs [path/to/dependencies]
+   * COPY resources [path/to/resources]
+   * COPY classes [path/to/classes]
+   *
+   * EXPOSE [port]
+   * [More EXPOSE instructions, if necessary]
+   * ENTRYPOINT java [jvm flags] -cp [classpaths] [main class]
+   * CMD [main class args]
+   * }
* * @return the {@code Dockerfile} contents */ From 0c550c83b3c13527e7d11bbd9e9e0445b2b9d61d Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 16:11:33 -0400 Subject: [PATCH 28/30] Use ObjectMapper --- .../tools/jib/docker/DockerContextGenerator.java | 16 +++++----------- .../jib/docker/DockerContextGeneratorTest.java | 3 ++- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 4518c5b393..2ccbec2f1d 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -16,6 +16,8 @@ package com.google.cloud.tools.jib.docker; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.cloud.tools.jib.builder.EntrypointBuilder; import com.google.cloud.tools.jib.builder.SourceFilesConfiguration; import com.google.cloud.tools.jib.filesystem.FileOperations; @@ -29,7 +31,6 @@ import java.nio.file.Path; import java.util.Collections; import java.util.List; -import java.util.regex.Matcher; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -55,15 +56,8 @@ public class DockerContextGenerator { * @return a string in the format: ["item1","item2",...] */ @VisibleForTesting - static String joinAsJsonArray(List items) { - return "[" - + String.join( - ",", - items - .stream() - .map(item -> "\"" + item.replaceAll("\"", Matcher.quoteReplacement("\\\"")) + "\"") - .collect(Collectors.toList())) - + "]"; + static String joinAsJsonArray(List items) throws JsonProcessingException { + return new ObjectMapper().writeValueAsString(items); } /** @@ -203,7 +197,7 @@ public void generate(Path targetDirectory) throws IOException { * @return the {@code Dockerfile} contents */ @VisibleForTesting - String makeDockerfile() { + String makeDockerfile() throws JsonProcessingException { return "FROM " + Preconditions.checkNotNull(baseImage) + "\n\nCOPY libs " diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index a71c90217d..9966f58329 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -16,6 +16,7 @@ package com.google.cloud.tools.jib.docker; +import com.fasterxml.jackson.core.JsonProcessingException; import com.google.cloud.tools.jib.builder.EntrypointBuilder; import com.google.cloud.tools.jib.builder.SourceFilesConfiguration; import com.google.cloud.tools.jib.filesystem.DirectoryWalker; @@ -113,7 +114,7 @@ public void testGenerate() throws IOException, URISyntaxException { } @Test - public void testJoinAsJsonArray() { + public void testJoinAsJsonArray() throws JsonProcessingException { Assert.assertEquals( "[\"java\",\"-cp\",\"/app/libs/*:/app/resources/:/app/classes/\",\"\"]", DockerContextGenerator.joinAsJsonArray( From 5c19ef5732c3a50753a28f0c163d61e6096b72b2 Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 16:17:13 -0400 Subject: [PATCH 29/30] Remove one line function --- .../jib/docker/DockerContextGenerator.java | 18 +++--------------- .../jib/docker/DockerContextGeneratorTest.java | 18 ------------------ 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 2ccbec2f1d..c145661f3f 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -47,19 +47,6 @@ */ public class DockerContextGenerator { - /** - * Formats a list for the Dockerfile's ENTRYPOINT or CMD. - * - * @see https://docs.docker.com/engine/reference/builder/#exec-form-entrypoint-example - * @param items the list of items to join into an array. - * @return a string in the format: ["item1","item2",...] - */ - @VisibleForTesting - static String joinAsJsonArray(List items) throws JsonProcessingException { - return new ObjectMapper().writeValueAsString(items); - } - /** * Builds a list of Dockerfile "EXPOSE" instructions. * @@ -198,6 +185,7 @@ public void generate(Path targetDirectory) throws IOException { */ @VisibleForTesting String makeDockerfile() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); return "FROM " + Preconditions.checkNotNull(baseImage) + "\n\nCOPY libs " @@ -209,9 +197,9 @@ String makeDockerfile() throws JsonProcessingException { + "\n\n" + makeExposeInstructions(exposedPorts) + "\nENTRYPOINT " - + joinAsJsonArray( + + objectMapper.writeValueAsString( EntrypointBuilder.makeEntrypoint(sourceFilesConfiguration, jvmFlags, mainClass)) + "\nCMD " - + joinAsJsonArray(javaArguments); + + objectMapper.writeValueAsString(javaArguments); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 9966f58329..2ab416d331 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -16,8 +16,6 @@ package com.google.cloud.tools.jib.docker; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.cloud.tools.jib.builder.EntrypointBuilder; import com.google.cloud.tools.jib.builder.SourceFilesConfiguration; import com.google.cloud.tools.jib.filesystem.DirectoryWalker; import com.google.common.collect.ImmutableList; @@ -113,22 +111,6 @@ public void testGenerate() throws IOException, URISyntaxException { assertSameFiles(targetDirectory.resolve("classes"), testClasses); } - @Test - public void testJoinAsJsonArray() throws JsonProcessingException { - Assert.assertEquals( - "[\"java\",\"-cp\",\"/app/libs/*:/app/resources/:/app/classes/\",\"\"]", - DockerContextGenerator.joinAsJsonArray( - ImmutableList.of("java", "-cp", "/app/libs/*:/app/resources/:/app/classes/", ""))); - - Assert.assertEquals( - "[\"java\",\"-flag\",\"another\\\"Flag\",\"-cp\",\"/app/libs/*:/app/resources/:/app/classes/\",\"AnotherMainClass\"]", - DockerContextGenerator.joinAsJsonArray( - EntrypointBuilder.makeEntrypoint( - mockSourceFilesConfiguration, - Arrays.asList("-flag", "another\"Flag"), - "AnotherMainClass"))); - } - @Test public void testMakeExposeInstructions() { Assert.assertEquals( From b68aebb62eafcfb1ec710c62c91382a9d86009ed Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Mon, 25 Jun 2018 16:54:05 -0400 Subject: [PATCH 30/30] Move makeExposeInstructions to makeDockerfile --- .../jib/docker/DockerContextGenerator.java | 50 ++++++++----------- .../docker/DockerContextGeneratorTest.java | 7 --- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index c145661f3f..91bbafd809 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -31,7 +31,6 @@ import java.nio.file.Path; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import javax.annotation.Nullable; /** @@ -47,18 +46,6 @@ */ public class DockerContextGenerator { - /** - * Builds a list of Dockerfile "EXPOSE" instructions. - * - * @param exposedPorts the list of ports numbers/ranges to expose - * @return a string containing an EXPOSE instruction for each of the entries - */ - @VisibleForTesting - static String makeExposeInstructions(List exposedPorts) { - return String.join( - "\n", exposedPorts.stream().map(port -> "EXPOSE " + port).collect(Collectors.toList())); - } - private final SourceFilesConfiguration sourceFilesConfiguration; @Nullable private String baseImage; @@ -186,20 +173,27 @@ public void generate(Path targetDirectory) throws IOException { @VisibleForTesting String makeDockerfile() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); - return "FROM " - + Preconditions.checkNotNull(baseImage) - + "\n\nCOPY libs " - + sourceFilesConfiguration.getDependenciesPathOnImage() - + "\nCOPY resources " - + sourceFilesConfiguration.getResourcesPathOnImage() - + "\nCOPY classes " - + sourceFilesConfiguration.getClassesPathOnImage() - + "\n\n" - + makeExposeInstructions(exposedPorts) - + "\nENTRYPOINT " - + objectMapper.writeValueAsString( - EntrypointBuilder.makeEntrypoint(sourceFilesConfiguration, jvmFlags, mainClass)) - + "\nCMD " - + objectMapper.writeValueAsString(javaArguments); + StringBuilder dockerfile = new StringBuilder(); + dockerfile + .append("FROM ") + .append(Preconditions.checkNotNull(baseImage)) + .append("\n\nCOPY libs ") + .append(sourceFilesConfiguration.getDependenciesPathOnImage()) + .append("\nCOPY resources ") + .append(sourceFilesConfiguration.getResourcesPathOnImage()) + .append("\nCOPY classes ") + .append(sourceFilesConfiguration.getClassesPathOnImage()) + .append("\n"); + for (String port : exposedPorts) { + dockerfile.append("\nEXPOSE ").append(port); + } + dockerfile + .append("\nENTRYPOINT ") + .append( + objectMapper.writeValueAsString( + EntrypointBuilder.makeEntrypoint(sourceFilesConfiguration, jvmFlags, mainClass))) + .append("\nCMD ") + .append(objectMapper.writeValueAsString(javaArguments)); + return dockerfile.toString(); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 2ab416d331..89ac1936eb 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -111,13 +111,6 @@ public void testGenerate() throws IOException, URISyntaxException { assertSameFiles(targetDirectory.resolve("classes"), testClasses); } - @Test - public void testMakeExposeInstructions() { - Assert.assertEquals( - "EXPOSE 1000\nEXPOSE 2000-2010", - DockerContextGenerator.makeExposeInstructions(ImmutableList.of("1000", "2000-2010"))); - } - @Test public void testMakeDockerfile() throws IOException { String expectedBaseImage = "somebaseimage";