This Knowledge Base (KB) article covers the scenario for leveraging the cf-java-client to push an app consisting of multiple buildpacks and a stack that differs from the cloud controller configured default.
The following behavior was discovered:
It can result in the following error:
CF-UnprocessableEntity(10008): Buildpack “java_buildpack_offline461” for stack “cflinuxfs3" must be an existing admin buildpack or a valid git URI org.cloudfoundry.client.v3.ClientV3Exception: CF-UnprocessableEntity(10008): Buildpack “java_buildpack_offline461” for stack “cflinuxfs3" must be an existing admin buildpack or a valid git URI
The reference to cflinuxfs3 in the above error is not expected, as cflinuxfs4 is specified in the manifest.
The specific API call that is being made which results in the above error:
PATCH "/v3/apps/<APP_GUID>"
with PATCH data:
{"lifecycle":{"data":{"buildpacks":["appdbuildpack","java_buildpack_offline461"]},"type":"buildpack"}}
When comparing this PATCH data to the same API call from a cf CLI cf push of the same manifest, the data sent from the client is:
{"lifecycle":{"type":"buildpack","data":{"buildpacks":["appdbuildpack","java_buildpack_offline461"],"stack":"cflinuxfs4"}}}
When the cf-java-client adds the buildpack to the application, the CAPI call (PATCH "/v3/apps/<APP_GUID>") does not include the desired stack, and due to this, cloud controller looks for the buildpack using the default stack. When cloud controller can not find the buildpack with the default stack (cflinuxfs3) then it results in the observed error.
Tanzu Application services for VMs
When pushing an application that includes multiple buildpacks and a stack that differs from the configured platform default, then cf-java-client v5.10.0 + must be used along with code updates to leverage the new v3 features.
To demonstrate this, consider the following environment/example:
$ cf buildpacks Getting buildpacks as admin... position name stack enabled locked filename 1 java_buildpack_offline461 cflinuxfs4 true false java-buildpack-offline-v4.61.0.zip 2 staticfile_buildpack cflinuxfs3 true false staticfile_buildpack-cached-cflinuxfs3-v1.6.0.zip 3 appdbuildpack4 cflinuxfs4 true false appdynamics_buildpack-v23.9.0-59.zip 4 java_buildpack_offline cflinuxfs3 true false java-buildpack-offline-cflinuxfs3-v4.56.zip 5 java_buildpack_offline cflinuxfs4 true false java-buildpack-offline-cflinuxfs4-v4.56.zip 6 ruby_buildpack cflinuxfs3 true false ruby_buildpack-cached-cflinuxfs3-v1.9.4.zip 7 ruby_buildpack cflinuxfs4 true false ruby_buildpack-cached-cflinuxfs4-v1.9.4.zip 8 binary_buildpack cflinuxfs3 true false binary_buildpack-cached-cflinuxfs3-v1.1.3.zip 9 dotnet_core_buildpack cflinuxfs4 true false dotnet-core_buildpack-cached-cflinuxfs4-v2.4.9.zip 10 dotnet_core_buildpack cflinuxfs3 true false dotnet-core_buildpack-cached-cflinuxfs3-v2.4.9.zip 11 appdbuildpack true false appdynamics_buildpack-v23.9.0-59.zip 12 nginx_buildpack cflinuxfs3 true false nginx_buildpack-cached-cflinuxfs3-v1.2.1.zip 13 nodejs_buildpack cflinuxfs3 true false nodejs_buildpack-cached-cflinuxfs3-v1.8.8.zip 14 nodejs_buildpack cflinuxfs4 true false nodejs_buildpack-cached-cflinuxfs4-v1.8.8.zip 15 go_buildpack cflinuxfs3 true false go_buildpack-cached-cflinuxfs3-v1.10.6.zip 16 go_buildpack cflinuxfs4 true false go_buildpack-cached-cflinuxfs4-v1.10.6.zip 17 r_buildpack cflinuxfs3 true false r_buildpack-cached-cflinuxfs3-v1.2.0.zip 18 python_buildpack cflinuxfs3 true false python_buildpack-cached-cflinuxfs3-v1.8.8.zip 19 python_buildpack cflinuxfs4 true false python_buildpack-cached-cflinuxfs4-v1.8.8.zip 20 php_buildpack cflinuxfs3 true false php_buildpack-cached-cflinuxfs3-v4.6.3.zip 21 binary_buildpack cflinuxfs4 true false binary_buildpack-cached-cflinuxfs4-v1.1.3.zip 22 binary_buildpack windows true false binary_buildpack-cached-windows-v1.1.3.zip
cf-java-client v5.10.0 is being used to push the following manifest file:
applications:
- name: loggerapp
memory: 1G
buildpacks:
- appdbuildpack
- java_buildpack_offline461
random-route: true
stack: cflinuxfs4
path: logger_app-0.0.1-SNAPSHOT.jar
With the following sample code:
public class CFops {
DefaultCloudFoundryOperations ops;
public CFops() {
ApplicationContext context = new AnnotationConfigApplicationContext(Configuration.class);
ops = (DefaultCloudFoundryOperations) context.getAutowireCapableBeanFactory().getBean("CFOperations");
}
public void pushApp(){
Path manifestPath = Paths.get("assets/manifest.yml");
ApplicationManifest manifest = ApplicationManifestUtils.read(manifestPath).get(0);
PushApplicationManifestRequest pushApplicationManifestRequest = PushApplicationManifestRequest.builder().manifest(manifest).build();
final Mono<Void> pushManifest = ops.applications().pushManifest(pushApplicationManifestRequest).doOnSubscribe(subscription -> System.out.println("pushing manifest for application."));
pushManifest.block();
}
public void pushAppv3(){
Path manifestPath = Paths.get("assets/manifest.yml");
ManifestV3 manifest = ApplicationManifestUtilsV3.read(manifestPath);
PushManifestV3Request pushApplicationManifestRequest = PushManifestV3Request.builder().manifest(manifest).build();
final Mono<Void> pushManifest = ops.applications().pushManifestV3(pushApplicationManifestRequest).doOnSubscribe(subscription -> System.out.println("pushing manifest for application."));
pushManifest.block();
}
}
Note that pushApp() leverages the client's pushManifest method while pushAppv3() leverages the client's pushManifestV3 method.