Add support for CNB platform API 0.4

This commit adds support for platform API 0.4 when invoking a CNB
builder in the Maven and Gradle plugins. If the builder advertises
that it supports platform API 0.4 then that version will be
requested when invoking lifecycle phases. Otherwise the plugins
will fall back to requesting platform API 0.3.

Requesting platform API 0.4 when invoking builder lifecycle phases
has the primary benefit of making it easier to pass command-line
arguments to the default process in the generated image.

Fixes gh-23692
pull/23762/head
Scott Frederick 4 years ago
parent 38b1954ab1
commit 38984985d4

@ -32,7 +32,7 @@ final class ApiVersions {
/** /**
* The platform API versions supported by this release. * The platform API versions supported by this release.
*/ */
static final ApiVersions SUPPORTED_PLATFORMS = new ApiVersions(ApiVersion.of(0, 3)); static final ApiVersions SUPPORTED_PLATFORMS = new ApiVersions(ApiVersion.of(0, 3), ApiVersion.of(0, 4));
private final ApiVersion[] apiVersions; private final ApiVersion[] apiVersions;

@ -134,6 +134,9 @@ class Lifecycle implements Closeable {
if (this.request.isCleanCache()) { if (this.request.isCleanCache()) {
phase.withArgs("-skip-restore"); phase.withArgs("-skip-restore");
} }
if (requiresProcessTypeDefault()) {
phase.withArgs("-process-type=web");
}
phase.withArgs(this.request.getName()); phase.withArgs(this.request.getName());
phase.withBinds(this.layersVolume, Directory.LAYERS); phase.withBinds(this.layersVolume, Directory.LAYERS);
phase.withBinds(this.applicationVolume, Directory.APPLICATION); phase.withBinds(this.applicationVolume, Directory.APPLICATION);
@ -147,6 +150,10 @@ class Lifecycle implements Closeable {
return this.request.isVerboseLogging() && this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION); return this.request.isVerboseLogging() && this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION);
} }
private boolean requiresProcessTypeDefault() {
return this.platformVersion.supports(ApiVersion.of(0, 4));
}
private void run(Phase phase) throws IOException { private void run(Phase phase) throws IOException {
Consumer<LogUpdateEvent> logConsumer = this.log.runningPhase(this.request, phase.getName()); Consumer<LogUpdateEvent> logConsumer = this.log.runningPhase(this.request, phase.getName());
ContainerConfig containerConfig = ContainerConfig.of(this.builder.getName(), phase::apply); ContainerConfig containerConfig = ContainerConfig.of(this.builder.getName(), phase::apply);

@ -87,7 +87,7 @@ class BuilderMetadataTests extends AbstractJsonTests {
assertThat(metadata.getStack().getRunImage().getMirrors()).isEmpty(); assertThat(metadata.getStack().getRunImage().getMirrors()).isEmpty();
assertThat(metadata.getLifecycle().getVersion()).isEqualTo("0.7.2"); assertThat(metadata.getLifecycle().getVersion()).isEqualTo("0.7.2");
assertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo("0.2"); assertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo("0.2");
assertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo("0.3"); assertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo("0.4");
assertThat(metadata.getLifecycle().getApis().getBuildpack()).isNull(); assertThat(metadata.getLifecycle().getApis().getBuildpack()).isNull();
assertThat(metadata.getLifecycle().getApis().getPlatform()).isNull(); assertThat(metadata.getLifecycle().getApis().getPlatform()).isNull();
} }

@ -88,6 +88,16 @@ class LifecycleTests {
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'"); assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
} }
@Test
void executeExecutesPhasesWithPlatformApi03() 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("builder-metadata-platform-api-0.3.json").execute();
assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-platform-api-0.3.json"));
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
}
@Test @Test
void executeOnlyUploadsContentOnce() throws Exception { void executeOnlyUploadsContentOnce() throws Exception {
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
@ -136,7 +146,7 @@ class LifecycleTests {
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(() -> createLifecycle("builder-metadata-unsupported-api.json").execute()) .isThrownBy(() -> createLifecycle("builder-metadata-unsupported-api.json").execute())
.withMessage("Detected platform API versions '0.2' are not included in supported versions '0.3'"); .withMessage("Detected platform API versions '0.2' are not included in supported versions '0.3,0.4'");
} }
@Test @Test
@ -145,8 +155,8 @@ class LifecycleTests {
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId()); given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null)); given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(() -> createLifecycle("builder-metadata-unsupported-apis.json").execute()) .isThrownBy(() -> createLifecycle("builder-metadata-unsupported-apis.json").execute()).withMessage(
.withMessage("Detected platform API versions '0.4,0.5' are not included in supported versions '0.3'"); "Detected platform API versions '0.5,0.6' are not included in supported versions '0.3,0.4'");
} }
@Test @Test

@ -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)"
}
}

@ -30,8 +30,8 @@
"platform": { "platform": {
"deprecated": [], "deprecated": [],
"supported": [ "supported": [
"0.4", "0.5",
"0.5" "0.6"
] ]
} }
} }

@ -132,7 +132,7 @@
"version": "0.7.2", "version": "0.7.2",
"api": { "api": {
"buildpack": "0.2", "buildpack": "0.2",
"platform": "0.3" "platform": "0.4"
} }
}, },
"createdBy": { "createdBy": {

@ -1,8 +1,8 @@
{ {
"User" : "root", "User" : "root",
"Image" : "pack.local/ephemeral-builder", "Image" : "pack.local/ephemeral-builder",
"Cmd" : [ "/cnb/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-skip-restore", "docker.io/library/my-application:latest" ], "Cmd" : [ "/cnb/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-skip-restore", "-process-type=web", "docker.io/library/my-application:latest" ],
"Env" : [ "CNB_PLATFORM_API=0.3" ], "Env" : [ "CNB_PLATFORM_API=0.4" ],
"Labels" : { "Labels" : {
"author" : "spring-boot" "author" : "spring-boot"
}, },

@ -0,0 +1,12 @@
{
"User" : "root",
"Image" : "pack.local/ephemeral-builder",
"Cmd" : [ "/cnb/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "docker.io/library/my-application:latest" ],
"Env" : [ "CNB_PLATFORM_API=0.3" ],
"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", "pack-cache-b35197ac41ea.launch:/launch-cache" ]
}
}

@ -1,8 +1,8 @@
{ {
"User" : "root", "User" : "root",
"Image" : "pack.local/ephemeral-builder", "Image" : "pack.local/ephemeral-builder",
"Cmd" : [ "/cnb/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "docker.io/library/my-application:latest" ], "Cmd" : [ "/cnb/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-process-type=web", "docker.io/library/my-application:latest" ],
"Env" : [ "CNB_PLATFORM_API=0.3" ], "Env" : [ "CNB_PLATFORM_API=0.4" ],
"Labels" : { "Labels" : {
"author" : "spring-boot" "author" : "spring-boot"
}, },

Loading…
Cancel
Save