Support CNB builder platform API 0.3

This commit adds support for Cloud Native Buildpacks builder platform
API 0.3, which is the latest platform API available currently. Support
for platform API 0.1 has been removed, adopting the policy of the pack
CLI to support the current platform API version and one version prior.

Fixes gh-20757
This commit is contained in:
Scott Frederick
2020-04-01 17:18:46 -05:00
parent bb9e37e119
commit a01c8452cb
22 changed files with 289 additions and 758 deletions

View File

@@ -33,6 +33,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link BuilderMetadata}.
*
* @author Phillip Webb
* @author Scott Frederick
*/
class BuilderMetadataTests extends AbstractJsonTests {
@@ -40,14 +41,14 @@ class BuilderMetadataTests extends AbstractJsonTests {
void fromImageLoadsMetadata() throws IOException {
Image image = Image.of(getContent("image.json"));
BuilderMetadata metadata = BuilderMetadata.fromImage(image);
assertThat(metadata.getStack().getRunImage().getImage()).isEqualTo("cloudfoundry/run:full-cnb");
assertThat(metadata.getStack().getRunImage().getImage()).isEqualTo("cloudfoundry/run:base-cnb");
assertThat(metadata.getStack().getRunImage().getMirrors()).isEmpty();
assertThat(metadata.getLifecycle().getVersion()).isEqualTo("0.5.0");
assertThat(metadata.getLifecycle().getVersion()).isEqualTo("0.7.2");
assertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo("0.2");
assertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo("0.1");
assertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo("0.3");
assertThat(metadata.getCreatedBy().getName()).isEqualTo("Pack CLI");
assertThat(metadata.getCreatedBy().getVersion())
.isEqualTo("v0.5.0 (git sha: c9cfac75b49609524e1ea33f809c12071406547c)");
.isEqualTo("v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)");
}
@Test

View File

@@ -74,7 +74,7 @@ class BuilderTests {
Image runImage = loadImage("run-image.json");
given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
.willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any()))
.willAnswer(withPulledImage(runImage));
Builder builder = new Builder(BuildLog.to(out), docker);
BuildRequest request = getTestRequest();
@@ -84,7 +84,6 @@ class BuilderTests {
assertThat(out.toString()).contains("Running analyzer");
assertThat(out.toString()).contains("Running builder");
assertThat(out.toString()).contains("Running exporter");
assertThat(out.toString()).contains("Running cacher");
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
verify(docker.image()).load(archive.capture(), any());
@@ -99,12 +98,12 @@ class BuilderTests {
Image runImage = loadImage("run-image-with-bad-stack.json");
given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
.willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any()))
.willAnswer(withPulledImage(runImage));
Builder builder = new Builder(BuildLog.to(out), docker);
BuildRequest request = getTestRequest();
assertThatIllegalStateException().isThrownBy(() -> builder.build(request)).withMessage(
"Run image stack 'org.cloudfoundry.stacks.cfwindowsfs3' does not match builder stack 'org.cloudfoundry.stacks.cflinuxfs3'");
"Run image stack 'org.cloudfoundry.stacks.cfwindowsfs3' does not match builder stack 'io.buildpacks.stacks.bionic'");
}
@Test
@@ -115,7 +114,7 @@ class BuilderTests {
Image runImage = loadImage("run-image.json");
given(docker.image().pull(eq(ImageReference.of("docker.io/" + BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
.willAnswer(withPulledImage(builderImage));
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:full-cnb")), any()))
given(docker.image().pull(eq(ImageReference.of("docker.io/cloudfoundry/run:base-cnb")), any()))
.willAnswer(withPulledImage(runImage));
Builder builder = new Builder(BuildLog.to(out), docker);
BuildRequest request = getTestRequest();

View File

@@ -79,32 +79,16 @@ class LifecycleTests {
}
@Test
void executeExecutesPhasesWithCacherPhase() throws Exception {
void executeExecutesPhases() throws Exception {
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
createLifecycle("0.5").execute();
createLifecycle().execute();
assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json"));
assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-0.1.json"));
assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-0.1.json"));
assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer.json"));
assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer.json"));
assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json"));
assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-0.1.json"));
assertPhaseWasRun("cacher", withExpectedConfig("lifecycle-cacher.json"));
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
}
@Test
void executeExecutesPhasesWithEmbeddedCaching() throws Exception {
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
createLifecycle("0.6").execute();
assertPhaseWasRun("detector", withExpectedConfig("lifecycle-detector.json"));
assertPhaseWasRun("analyzer", withExpectedConfig("lifecycle-analyzer-0.2.json"));
assertPhaseWasRun("restorer", withExpectedConfig("lifecycle-restorer-0.2.json"));
assertPhaseWasRun("builder", withExpectedConfig("lifecycle-builder.json"));
assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter-0.2.json"));
assertPhaseWasNotRun("cacher");
assertPhaseWasRun("exporter", withExpectedConfig("lifecycle-exporter.json"));
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
}
@@ -173,27 +157,18 @@ class LifecycleTests {
}
private Lifecycle createLifecycle() throws IOException {
return createLifecycle("0.6");
}
private Lifecycle createLifecycle(String version) throws IOException {
return createLifecycle(getTestRequest(), version);
return createLifecycle(getTestRequest());
}
private Lifecycle createLifecycle(BuildRequest request) throws IOException {
return createLifecycle(request, "0.6");
}
private Lifecycle createLifecycle(BuildRequest request, String version) throws IOException {
EphemeralBuilder builder = mockEphemeralBuilder((version != null) ? version : "0.5");
EphemeralBuilder builder = mockEphemeralBuilder();
return new TestLifecycle(BuildLog.to(this.out), this.docker, request, ImageReference.of("cloudfoundry/run"),
builder);
}
private EphemeralBuilder mockEphemeralBuilder(String version) throws IOException {
private EphemeralBuilder mockEphemeralBuilder() throws IOException {
EphemeralBuilder builder = mock(EphemeralBuilder.class);
byte[] metadataContent = FileCopyUtils
.copyToByteArray(getClass().getResourceAsStream("builder-metadata-version-" + version + ".json"));
byte[] metadataContent = FileCopyUtils.copyToByteArray(getClass().getResourceAsStream("builder-metadata.json"));
BuilderMetadata metadata = BuilderMetadata.fromJson(new String(metadataContent, StandardCharsets.UTF_8));
given(builder.getName()).willReturn(ImageReference.of("pack.local/ephemeral-builder"));
given(builder.getBuilderMetadata()).willReturn(metadata);
@@ -226,11 +201,6 @@ class LifecycleTests {
configConsumer.accept(this.configs.get(containerReference.toString()));
}
private void assertPhaseWasNotRun(String name) {
ContainerReference containerReference = ContainerReference.of("lifecycle-" + name);
assertThat(this.configs.get(containerReference.toString())).isNull();
}
private IOConsumer<ContainerConfig> withExpectedConfig(String name) {
return (config) -> {
InputStream in = getClass().getResourceAsStream(name);

View File

@@ -1,222 +0,0 @@
{
"description": "Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang",
"buildpacks": [
{
"id": "org.cloudfoundry.debug",
"version": "v1.0.106",
"latest": true
},
{
"id": "org.cloudfoundry.go",
"version": "v0.0.2",
"latest": true
},
{
"id": "org.cloudfoundry.springautoreconfiguration",
"version": "v1.0.113",
"latest": true
},
{
"id": "org.cloudfoundry.buildsystem",
"version": "v1.0.133",
"latest": true
},
{
"id": "org.cloudfoundry.procfile",
"version": "v1.0.41",
"latest": true
},
{
"id": "org.cloudfoundry.nodejs",
"version": "v0.0.5",
"latest": true
},
{
"id": "org.cloudfoundry.distzip",
"version": "v1.0.101",
"latest": true
},
{
"id": "org.cloudfoundry.jdbc",
"version": "v1.0.107",
"latest": true
},
{
"id": "org.cloudfoundry.azureapplicationinsights",
"version": "v1.0.105",
"latest": true
},
{
"id": "org.cloudfoundry.springboot",
"version": "v1.0.112",
"latest": true
},
{
"id": "org.cloudfoundry.openjdk",
"version": "v1.0.58",
"latest": true
},
{
"id": "org.cloudfoundry.tomcat",
"version": "v1.1.24",
"latest": true
},
{
"id": "org.cloudfoundry.googlestackdriver",
"version": "v1.0.54",
"latest": true
},
{
"id": "org.cloudfoundry.jmx",
"version": "v1.0.107",
"latest": true
},
{
"id": "org.cloudfoundry.archiveexpanding",
"version": "v1.0.99",
"latest": true
},
{
"id": "org.cloudfoundry.jvmapplication",
"version": "v1.0.82",
"latest": true
},
{
"id": "org.cloudfoundry.dep",
"version": "0.0.64",
"latest": true
},
{
"id": "org.cloudfoundry.go-compiler",
"version": "0.0.55",
"latest": true
},
{
"id": "org.cloudfoundry.go-mod",
"version": "0.0.58",
"latest": true
},
{
"id": "org.cloudfoundry.node-engine",
"version": "0.0.102",
"latest": true
},
{
"id": "org.cloudfoundry.npm",
"version": "0.0.63",
"latest": true
},
{
"id": "org.cloudfoundry.yarn",
"version": "0.0.69",
"latest": true
}
],
"groups": [
{
"buildpacks": [
{
"id": "org.cloudfoundry.archiveexpanding",
"version": "v1.0.99",
"optional": true
},
{
"id": "org.cloudfoundry.openjdk",
"version": "v1.0.58"
},
{
"id": "org.cloudfoundry.buildsystem",
"version": "v1.0.133",
"optional": true
},
{
"id": "org.cloudfoundry.jvmapplication",
"version": "v1.0.82"
},
{
"id": "org.cloudfoundry.tomcat",
"version": "v1.1.24",
"optional": true
},
{
"id": "org.cloudfoundry.springboot",
"version": "v1.0.112",
"optional": true
},
{
"id": "org.cloudfoundry.distzip",
"version": "v1.0.101",
"optional": true
},
{
"id": "org.cloudfoundry.procfile",
"version": "v1.0.41",
"optional": true
},
{
"id": "org.cloudfoundry.azureapplicationinsights",
"version": "v1.0.105",
"optional": true
},
{
"id": "org.cloudfoundry.debug",
"version": "v1.0.106",
"optional": true
},
{
"id": "org.cloudfoundry.googlestackdriver",
"version": "v1.0.54",
"optional": true
},
{
"id": "org.cloudfoundry.jdbc",
"version": "v1.0.107",
"optional": true
},
{
"id": "org.cloudfoundry.jmx",
"version": "v1.0.107",
"optional": true
},
{
"id": "org.cloudfoundry.springautoreconfiguration",
"version": "v1.0.113",
"optional": true
}
]
},
{
"buildpacks": [
{
"id": "org.cloudfoundry.nodejs",
"version": "v0.0.5"
}
]
},
{
"buildpacks": [
{
"id": "org.cloudfoundry.go",
"version": "v0.0.2"
}
]
}
],
"stack": {
"runImage": {
"image": "cloudfoundry/run:base-cnb",
"mirrors": null
}
},
"lifecycle": {
"version": "0.5.0",
"api": {
"buildpack": "0.2",
"platform": "0.1"
}
},
"createdBy": {
"name": "Pack CLI",
"version": "dev-2019-11-19-22:34:59"
}
}

View File

@@ -1,222 +0,0 @@
{
"description": "Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang",
"buildpacks": [
{
"id": "org.cloudfoundry.debug",
"version": "v1.0.106",
"latest": true
},
{
"id": "org.cloudfoundry.go",
"version": "v0.0.2",
"latest": true
},
{
"id": "org.cloudfoundry.springautoreconfiguration",
"version": "v1.0.113",
"latest": true
},
{
"id": "org.cloudfoundry.buildsystem",
"version": "v1.0.133",
"latest": true
},
{
"id": "org.cloudfoundry.procfile",
"version": "v1.0.41",
"latest": true
},
{
"id": "org.cloudfoundry.nodejs",
"version": "v0.0.5",
"latest": true
},
{
"id": "org.cloudfoundry.distzip",
"version": "v1.0.101",
"latest": true
},
{
"id": "org.cloudfoundry.jdbc",
"version": "v1.0.107",
"latest": true
},
{
"id": "org.cloudfoundry.azureapplicationinsights",
"version": "v1.0.105",
"latest": true
},
{
"id": "org.cloudfoundry.springboot",
"version": "v1.0.112",
"latest": true
},
{
"id": "org.cloudfoundry.openjdk",
"version": "v1.0.58",
"latest": true
},
{
"id": "org.cloudfoundry.tomcat",
"version": "v1.1.24",
"latest": true
},
{
"id": "org.cloudfoundry.googlestackdriver",
"version": "v1.0.54",
"latest": true
},
{
"id": "org.cloudfoundry.jmx",
"version": "v1.0.107",
"latest": true
},
{
"id": "org.cloudfoundry.archiveexpanding",
"version": "v1.0.99",
"latest": true
},
{
"id": "org.cloudfoundry.jvmapplication",
"version": "v1.0.82",
"latest": true
},
{
"id": "org.cloudfoundry.dep",
"version": "0.0.64",
"latest": true
},
{
"id": "org.cloudfoundry.go-compiler",
"version": "0.0.55",
"latest": true
},
{
"id": "org.cloudfoundry.go-mod",
"version": "0.0.58",
"latest": true
},
{
"id": "org.cloudfoundry.node-engine",
"version": "0.0.102",
"latest": true
},
{
"id": "org.cloudfoundry.npm",
"version": "0.0.63",
"latest": true
},
{
"id": "org.cloudfoundry.yarn",
"version": "0.0.69",
"latest": true
}
],
"groups": [
{
"buildpacks": [
{
"id": "org.cloudfoundry.archiveexpanding",
"version": "v1.0.99",
"optional": true
},
{
"id": "org.cloudfoundry.openjdk",
"version": "v1.0.58"
},
{
"id": "org.cloudfoundry.buildsystem",
"version": "v1.0.133",
"optional": true
},
{
"id": "org.cloudfoundry.jvmapplication",
"version": "v1.0.82"
},
{
"id": "org.cloudfoundry.tomcat",
"version": "v1.1.24",
"optional": true
},
{
"id": "org.cloudfoundry.springboot",
"version": "v1.0.112",
"optional": true
},
{
"id": "org.cloudfoundry.distzip",
"version": "v1.0.101",
"optional": true
},
{
"id": "org.cloudfoundry.procfile",
"version": "v1.0.41",
"optional": true
},
{
"id": "org.cloudfoundry.azureapplicationinsights",
"version": "v1.0.105",
"optional": true
},
{
"id": "org.cloudfoundry.debug",
"version": "v1.0.106",
"optional": true
},
{
"id": "org.cloudfoundry.googlestackdriver",
"version": "v1.0.54",
"optional": true
},
{
"id": "org.cloudfoundry.jdbc",
"version": "v1.0.107",
"optional": true
},
{
"id": "org.cloudfoundry.jmx",
"version": "v1.0.107",
"optional": true
},
{
"id": "org.cloudfoundry.springautoreconfiguration",
"version": "v1.0.113",
"optional": true
}
]
},
{
"buildpacks": [
{
"id": "org.cloudfoundry.nodejs",
"version": "v0.0.5"
}
]
},
{
"buildpacks": [
{
"id": "org.cloudfoundry.go",
"version": "v0.0.2"
}
]
}
],
"stack": {
"runImage": {
"image": "cloudfoundry/run:base-cnb",
"mirrors": null
}
},
"lifecycle": {
"version": "0.6.0",
"api": {
"buildpack": "0.2",
"platform": "0.2"
}
},
"createdBy": {
"name": "Pack CLI",
"version": "dev-2019-11-19-22:34:59"
}
}

View File

@@ -0,0 +1,142 @@
{
"description": "Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang",
"buildpacks": [
{
"id": "org.cloudfoundry.googlestackdriver",
"version": "v1.1.11"
},
{
"id": "org.cloudfoundry.springboot",
"version": "v1.2.13"
},
{
"id": "org.cloudfoundry.debug",
"version": "v1.2.11"
},
{
"id": "org.cloudfoundry.tomcat",
"version": "v1.3.18"
},
{
"id": "org.cloudfoundry.go",
"version": "v0.0.4"
},
{
"id": "org.cloudfoundry.openjdk",
"version": "v1.2.14"
},
{
"id": "org.cloudfoundry.buildsystem",
"version": "v1.2.15"
},
{
"id": "org.cloudfoundry.jvmapplication",
"version": "v1.1.12"
},
{
"id": "org.cloudfoundry.springautoreconfiguration",
"version": "v1.1.11"
},
{
"id": "org.cloudfoundry.archiveexpanding",
"version": "v1.0.102"
},
{
"id": "org.cloudfoundry.jmx",
"version": "v1.1.12"
},
{
"id": "org.cloudfoundry.nodejs",
"version": "v2.0.8"
},
{
"id": "org.cloudfoundry.jdbc",
"version": "v1.1.14"
},
{
"id": "org.cloudfoundry.procfile",
"version": "v1.1.12"
},
{
"id": "org.cloudfoundry.dotnet-core",
"version": "v0.0.6"
},
{
"id": "org.cloudfoundry.azureapplicationinsights",
"version": "v1.1.12"
},
{
"id": "org.cloudfoundry.distzip",
"version": "v1.1.12"
},
{
"id": "org.cloudfoundry.dep",
"version": "0.0.101"
},
{
"id": "org.cloudfoundry.go-compiler",
"version": "0.0.105"
},
{
"id": "org.cloudfoundry.go-mod",
"version": "0.0.89"
},
{
"id": "org.cloudfoundry.node-engine",
"version": "0.0.163"
},
{
"id": "org.cloudfoundry.npm",
"version": "0.1.3"
},
{
"id": "org.cloudfoundry.yarn-install",
"version": "0.1.10"
},
{
"id": "org.cloudfoundry.dotnet-core-aspnet",
"version": "0.0.118"
},
{
"id": "org.cloudfoundry.dotnet-core-build",
"version": "0.0.68"
},
{
"id": "org.cloudfoundry.dotnet-core-conf",
"version": "0.0.115"
},
{
"id": "org.cloudfoundry.dotnet-core-runtime",
"version": "0.0.127"
},
{
"id": "org.cloudfoundry.dotnet-core-sdk",
"version": "0.0.122"
},
{
"id": "org.cloudfoundry.icu",
"version": "0.0.43"
},
{
"id": "org.cloudfoundry.node-engine",
"version": "0.0.158"
}
],
"stack": {
"runImage": {
"image": "cloudfoundry/run:base-cnb",
"mirrors": null
}
},
"lifecycle": {
"version": "0.7.2",
"api": {
"buildpack": "0.2",
"platform": "0.3"
}
},
"createdBy": {
"name": "Pack CLI",
"version": "v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)"
}
}

View File

@@ -1,11 +0,0 @@
{
"User" : "root",
"Image" : "pack.local/ephemeral-builder",
"Cmd" : [ "/lifecycle/analyzer", "-daemon", "-layers", "/layers", "docker.io/library/my-application:latest" ],
"Labels" : {
"author" : "spring-boot"
},
"HostConfig" : {
"Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace" ]
}
}

View File

@@ -1,11 +0,0 @@
{
"User" : "root",
"Image" : "pack.local/ephemeral-builder",
"Cmd" : [ "/lifecycle/exporter", "-image", "docker.io/cloudfoundry/run", "-layers", "/layers", "-app", "/workspace", "-daemon", "-launch-cache", "/launch-cache", "docker.io/library/my-application:latest" ],
"Labels" : {
"author" : "spring-boot"
},
"HostConfig" : {
"Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.launch:/launch-cache" ]
}
}

View File

@@ -1,11 +0,0 @@
{
"User" : "root",
"Image" : "pack.local/ephemeral-builder",
"Cmd" : [ "/lifecycle/restorer", "-path", "/cache", "-layers", "/layers" ],
"Labels" : {
"author" : "spring-boot"
},
"HostConfig" : {
"Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache" ]
}
}