diff --git a/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/CloudFoundryAcceptanceTest.java b/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/CloudFoundryAcceptanceTest.java index a7095e5..754685f 100644 --- a/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/CloudFoundryAcceptanceTest.java +++ b/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/CloudFoundryAcceptanceTest.java @@ -345,6 +345,13 @@ abstract class CloudFoundryAcceptanceTest { .blockOptional(); } + protected Optional getApplicationDetail(String appName) { + return cloudFoundryService + .getApplication(appName) + .filter(applicationSummary -> appName.equals(applicationSummary.getName())) + .blockOptional(); + } + protected Optional getApplicationSummary(String appName, String space) { return cloudFoundryService.getApplication(appName, space).blockOptional(); } diff --git a/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/CreateInstanceAcceptanceTest.java b/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/CreateInstanceAcceptanceTest.java index 799dcf2..83173bf 100644 --- a/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/CreateInstanceAcceptanceTest.java +++ b/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/CreateInstanceAcceptanceTest.java @@ -19,6 +19,7 @@ package org.springframework.cloud.appbroker.acceptance; import java.util.Optional; import com.jayway.jsonpath.DocumentContext; +import org.cloudfoundry.operations.applications.ApplicationDetail; import org.cloudfoundry.operations.applications.ApplicationSummary; import org.junit.jupiter.api.Test; @@ -63,6 +64,7 @@ class CreateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest { "spring.cloud.appbroker.services[0].apps[0].environment.ENV_VAR_1=value1", "spring.cloud.appbroker.services[0].apps[0].environment.ENV_VAR_2=value2", + "spring.cloud.appbroker.services[0].apps[0].properties.stack=cflinuxfs3", "spring.cloud.appbroker.services[0].apps[0].properties.memory=2G", "spring.cloud.appbroker.services[0].apps[0].properties.count=2", @@ -85,6 +87,19 @@ class CreateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest { assertThat(backingApplication2).hasValueSatisfying(app -> assertThat(app.getRunningInstances()).isEqualTo(1)); + + // and stack is updated when specified + Optional application1Detail = getApplicationDetail(APP_CREATE_1); + assertThat(application1Detail).hasValueSatisfying(app -> { + assertThat(app.getStack()).isEqualTo("cflinuxfs3"); + }); + + // and stack is not updated when not specified + Optional application2Detail = getApplicationDetail(APP_CREATE_1); + assertThat(application2Detail).hasValueSatisfying(app -> { + assertThat(app.getStack()).isEqualTo("cflinuxfs4"); + }); + // and has the environment variables DocumentContext json = getSpringAppJson(APP_CREATE_1); assertEnvironmentVariablesSet(json); diff --git a/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/CloudFoundryAppDeployerAutoConfigurationTest.java b/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/CloudFoundryAppDeployerAutoConfigurationTest.java index c061762..efa59c5 100644 --- a/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/CloudFoundryAppDeployerAutoConfigurationTest.java +++ b/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/CloudFoundryAppDeployerAutoConfigurationTest.java @@ -56,6 +56,7 @@ class CloudFoundryAppDeployerAutoConfigurationTest { "spring.cloud.appbroker.deployer.cloudfoundry.properties.memory=2G", "spring.cloud.appbroker.deployer.cloudfoundry.properties.count=3", "spring.cloud.appbroker.deployer.cloudfoundry.properties.buildpack=example-buildpack", + "spring.cloud.appbroker.deployer.cloudfoundry.properties.stack=customstack", "spring.cloud.appbroker.deployer.cloudfoundry.properties.domain=example.local" ) .run((context) -> { @@ -74,6 +75,7 @@ class CloudFoundryAppDeployerAutoConfigurationTest { assertThat(deploymentProperties.getMemory()).isEqualTo("2G"); assertThat(deploymentProperties.getCount()).isEqualTo(3); assertThat(deploymentProperties.getBuildpack()).isEqualTo("example-buildpack"); + assertThat(deploymentProperties.getStack()).isEqualTo("customstack"); assertThat(deploymentProperties.getDomain()).isEqualTo("example.local"); assertThat(context).hasSingleBean(AppDeployer.class); diff --git a/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployer.java b/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployer.java index df8c676..cfda2dc 100644 --- a/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployer.java +++ b/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployer.java @@ -706,6 +706,7 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware .services(request.getServices()) .instances(instances(deploymentProperties)) .memory(memory(deploymentProperties)) + .stack(stack(deploymentProperties)) .disk(diskQuota(deploymentProperties)) .healthCheckType(healthCheck(deploymentProperties)) .healthCheckHttpEndpoint(healthCheckEndpoint(deploymentProperties)) @@ -1047,6 +1048,11 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware .orElse(this.defaultDeploymentProperties.getBuildpacks()); } + private String stack(Map properties) { + return Optional.ofNullable(properties.get(CloudFoundryDeploymentProperties.STACK_PROPERTY_KEY)) + .orElse(this.defaultDeploymentProperties.getStack()); + } + private String javaOpts(Map properties) { return Optional.ofNullable(properties.get(CloudFoundryDeploymentProperties.JAVA_OPTS_PROPERTY_KEY)) .orElse(this.defaultDeploymentProperties.getJavaOpts()); diff --git a/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryDeploymentProperties.java b/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryDeploymentProperties.java index 3a39d9e..f945678 100644 --- a/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryDeploymentProperties.java +++ b/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryDeploymentProperties.java @@ -90,6 +90,11 @@ public class CloudFoundryDeploymentProperties extends DeploymentProperties { */ protected static final String BUILDPACKS_PROPERTY_KEY = "buildpacks"; + /** + * Key for storing the stack deployment property + */ + protected static final String STACK_PROPERTY_KEY = "stack"; + /** * Key for storing JAVA_OPTS deployment property */ @@ -126,6 +131,11 @@ public class CloudFoundryDeploymentProperties extends DeploymentProperties { */ private String buildpacks = ""; + /** + * The stack to use for deploying the application. + */ + private String stack; + /** * The type of health check to perform on deployed application, if not overridden per-app. Defaults to PORT */ @@ -194,6 +204,14 @@ public class CloudFoundryDeploymentProperties extends DeploymentProperties { this.buildpacks = buildpacks; } + public String getStack() { + return stack; + } + + public void setStack(String stack) { + this.stack = stack; + } + public boolean isEnableRandomAppNamePrefix() { return enableRandomAppNamePrefix; } diff --git a/spring-cloud-app-broker-deployer-cloudfoundry/src/test/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployerTest.java b/spring-cloud-app-broker-deployer-cloudfoundry/src/test/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployerTest.java index 134dd12..3be2203 100644 --- a/spring-cloud-app-broker-deployer-cloudfoundry/src/test/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployerTest.java +++ b/spring-cloud-app-broker-deployer-cloudfoundry/src/test/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployerTest.java @@ -208,6 +208,7 @@ class CloudFoundryAppDeployerTest { .property(CloudFoundryDeploymentProperties.HEALTHCHECK_PROPERTY_KEY, "http") .property(CloudFoundryDeploymentProperties.HEALTHCHECK_HTTP_ENDPOINT_PROPERTY_KEY, "/healthcheck") .property(CloudFoundryDeploymentProperties.BUILDPACKS_PROPERTY_KEY, "buildpack1,buildpack2") + .property(CloudFoundryDeploymentProperties.STACK_PROPERTY_KEY, "customstack") .property(CloudFoundryDeploymentProperties.DOMAINS_PROPERTY, "domain1,domain2") .property(DeploymentProperties.HOST_PROPERTY_KEY, "host") .property(CloudFoundryDeploymentProperties.NO_ROUTE_PROPERTY, "true") @@ -226,6 +227,7 @@ class CloudFoundryAppDeployerTest { .healthCheckType(ApplicationHealthCheck.HTTP) .healthCheckHttpEndpoint("/healthcheck") .buildpacks("buildpack1", "buildpack2") + .stack("customstack") .domains("domain2", "domain1") // domains is a list so order matters .host("host") .noRoute(true) @@ -295,6 +297,7 @@ class CloudFoundryAppDeployerTest { .property(CloudFoundryDeploymentProperties.DOMAINS_PROPERTY, "domain2") .property(DeploymentProperties.HOST_PROPERTY_KEY, "host2") .property(CloudFoundryDeploymentProperties.NO_ROUTE_PROPERTY, "true") + .property(CloudFoundryDeploymentProperties.STACK_PROPERTY_KEY, "customstack") .build(); StepVerifier.create(appDeployer.deploy(request)) @@ -312,6 +315,7 @@ class CloudFoundryAppDeployerTest { .buildpack("buildpack2") .domains("domain2", "domain1") .host("host2") + .stack("customstack") .noRoute(true) .build(); diff --git a/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/fixtures/CloudControllerStubFixture.java b/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/fixtures/CloudControllerStubFixture.java index 3733157..763c340 100644 --- a/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/fixtures/CloudControllerStubFixture.java +++ b/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/fixtures/CloudControllerStubFixture.java @@ -183,6 +183,12 @@ public class CloudControllerStubFixture extends WiremockStubFixture { .withBody(cc("empty-query-results")))); } + public void stubListStacks() { + stubFor(get(urlPathEqualTo("/v2/stacks")) + .willReturn(ok() + .withBody(cc("list-stacks")))); + } + public void stubAppExistsInSpace(final String appName, final String spaceGuid) { stubFor(get(urlPathEqualTo("/v2/apps/" + appGuid(appName))) .withMetadata(optionalStubMapping()) diff --git a/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/get-build-STAGED.json b/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/get-build-STAGED.json index 1cbf96f..5f1c5b7 100644 --- a/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/get-build-STAGED.json +++ b/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/get-build-STAGED.json @@ -15,7 +15,7 @@ "buildpacks": [ "ruby_buildpack" ], - "stack": "cflinuxfs2" + "stack": "cflinuxfs4" } }, "package": { diff --git a/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/get-stack.json b/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/get-stack.json index 27f4d0a..af6283d 100644 --- a/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/get-stack.json +++ b/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/get-stack.json @@ -6,7 +6,7 @@ "updated_at": "2018-03-28T22:15:03Z" }, "entity": { - "name": "cflinuxfs2", + "name": "cflinuxfs4", "description": "Cloud Foundry Linux-based filesystem" } } diff --git a/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/list-stacks.json b/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/list-stacks.json new file mode 100644 index 0000000..1653ab3 --- /dev/null +++ b/spring-cloud-app-broker-integration-tests/src/test/resources/responses/cloudcontroller/list-stacks.json @@ -0,0 +1,20 @@ +{ + "total_results": 1, + "total_pages": 1, + "prev_url": null, + "next_url": null, + "resources": [ + { + "metadata": { + "guid": "@stack-guid", + "url": "/v2/stacks/@stack-guid", + "created_at": "2015-07-27T22:43:05Z", + "updated_at": null + }, + "entity": { + "name": "cflinuxfs4", + "description": "cflinuxfs4" + } + } + ] +}