14
build.gradle
14
build.gradle
@@ -156,6 +156,20 @@ configure(allprojects) {
|
||||
"${result.skippedTestCount} skipped"
|
||||
}
|
||||
}
|
||||
|
||||
// print failed tests after the execution
|
||||
def failedTests = []
|
||||
|
||||
afterTest { test, result ->
|
||||
if (result.resultType == TestResult.ResultType.FAILURE) {
|
||||
failedTests << test
|
||||
}
|
||||
}
|
||||
|
||||
afterSuite {
|
||||
failedTests.each { test -> println "FAILED test: ${test.className} > ${test.name}" }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pmd {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.cloud.appbroker.acceptance;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -117,10 +118,18 @@ class CloudFoundryAcceptanceTest {
|
||||
.blockOptional();
|
||||
}
|
||||
|
||||
Optional<ApplicationSummary> getApplicationSummaryByNameAndSpace(String appName, String space) {
|
||||
return cloudFoundryService.getApplicationSummaryByName(appName, space).blockOptional();
|
||||
}
|
||||
|
||||
ApplicationEnvironments getApplicationEnvironmentByName(String appName) {
|
||||
return cloudFoundryService.getApplicationEnvironmentByAppName(appName).block();
|
||||
}
|
||||
|
||||
List<String> getSpaces() {
|
||||
return cloudFoundryService.getSpaces().block();
|
||||
}
|
||||
|
||||
private Path getSampleBrokerAppPath() {
|
||||
return Paths.get(acceptanceTestProperties.getSampleBrokerAppPath(), "");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2016-2018. the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.cloud.appbroker.acceptance;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.cloudfoundry.operations.applications.ApplicationSummary;
|
||||
import org.cloudfoundry.operations.services.ServiceInstanceSummary;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class CreateInstanceWithTargetAcceptanceTest extends CloudFoundryAcceptanceTest {
|
||||
|
||||
private static final String BROKER_SAMPLE_APP_CREATE_WITH_TARGET = "app-with-target";
|
||||
|
||||
@Test
|
||||
@AppBrokerTestProperties({
|
||||
"spring.cloud.appbroker.services[0].service-name=example",
|
||||
"spring.cloud.appbroker.services[0].plan-name=standard",
|
||||
"spring.cloud.appbroker.services[0].apps[0].name=" + BROKER_SAMPLE_APP_CREATE_WITH_TARGET,
|
||||
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
|
||||
"spring.cloud.appbroker.services[0].apps[0].target.name=SpacePerServiceInstance"
|
||||
})
|
||||
void shouldPushAppWithTargetWhenCreateServiceCalled() {
|
||||
// when a service instance is created
|
||||
createServiceInstance();
|
||||
Optional<ServiceInstanceSummary> serviceInstance = getServiceInstance();
|
||||
assertThat(serviceInstance).isNotEmpty();
|
||||
|
||||
// then a backing application is deployed in a space named as the service instance id
|
||||
String serviceInstanceId = serviceInstance.orElseThrow(RuntimeException::new).getId();
|
||||
String spaceName = serviceInstanceId;
|
||||
Optional<ApplicationSummary> backingApplication =
|
||||
getApplicationSummaryByNameAndSpace(BROKER_SAMPLE_APP_CREATE_WITH_TARGET, spaceName);
|
||||
assertThat(backingApplication).isNotEmpty();
|
||||
|
||||
// and has its route with the service instance id appended to it
|
||||
ApplicationSummary applicationSummary = backingApplication.orElseThrow(RuntimeException::new);
|
||||
assertThat(applicationSummary.getUrls()).isNotEmpty();
|
||||
assertThat(applicationSummary.getUrls().get(0)).startsWith(BROKER_SAMPLE_APP_CREATE_WITH_TARGET + "-" + spaceName);
|
||||
|
||||
// when the service instance is deleted
|
||||
deleteServiceInstance();
|
||||
|
||||
// then the space is deleted
|
||||
List<String> spaces = getSpaces();
|
||||
assertThat(spaces).doesNotContain(spaceName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
|
||||
import org.cloudfoundry.client.CloudFoundryClient;
|
||||
import org.cloudfoundry.operations.CloudFoundryOperations;
|
||||
import org.cloudfoundry.operations.DefaultCloudFoundryOperations;
|
||||
import org.cloudfoundry.operations.applications.ApplicationDetail;
|
||||
import org.cloudfoundry.operations.applications.ApplicationEnvironments;
|
||||
import org.cloudfoundry.operations.applications.ApplicationManifest;
|
||||
@@ -175,10 +176,10 @@ public class CloudFoundryService {
|
||||
cloudFoundryOperations
|
||||
.services()
|
||||
.updateInstance(UpdateServiceInstanceRequest
|
||||
.builder()
|
||||
.serviceInstanceName(serviceInstanceName)
|
||||
.parameters(parameters)
|
||||
.build()));
|
||||
.builder()
|
||||
.serviceInstanceName(serviceInstanceName)
|
||||
.parameters(parameters)
|
||||
.build()));
|
||||
}
|
||||
|
||||
public Mono<ServiceInstanceSummary> getServiceInstance(String serviceInstanceName) {
|
||||
@@ -191,6 +192,23 @@ public class CloudFoundryService {
|
||||
cloudFoundryOperations.applications().list().collectList());
|
||||
}
|
||||
|
||||
public Mono<List<String>> getSpaces() {
|
||||
return this.cloudFoundryOperations.spaces().list().map(SpaceSummary::getName).collectList();
|
||||
}
|
||||
|
||||
public Mono<ApplicationSummary> getApplicationSummaryByName(String appName, String space) {
|
||||
final String defaultOrg = cloudFoundryProperties.getDefaultOrg();
|
||||
return loggingFlux(DefaultCloudFoundryOperations.builder()
|
||||
.cloudFoundryClient(cloudFoundryClient)
|
||||
.organization(defaultOrg)
|
||||
.space(space)
|
||||
.build()
|
||||
.applications()
|
||||
.list()
|
||||
.filter(applicationSummary -> applicationSummary.getName().equals(appName))
|
||||
).next();
|
||||
}
|
||||
|
||||
public Mono<ApplicationEnvironments> getApplicationEnvironmentByAppName(String appName) {
|
||||
return loggingMono(
|
||||
cloudFoundryOperations
|
||||
@@ -303,4 +321,11 @@ public class CloudFoundryService {
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Flux<T> loggingFlux(Flux<T> publisher) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
return publisher.log();
|
||||
} else {
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.appbroker.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -25,28 +27,29 @@ import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.deployer.DeployerClient;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialGenerator;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderFactory;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.SimpleCredentialGenerator;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.SpringSecurityBasicAuthCredentialProviderFactory;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.EnvironmentMappingParametersTransformerFactory;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformerFactory;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.PropertyMappingParametersTransformerFactory;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.SpacePerServiceInstance;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetFactory;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetService;
|
||||
import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.appbroker.service.DeleteServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.appbroker.service.UpdateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.appbroker.service.WorkflowServiceInstanceService;
|
||||
import org.springframework.cloud.appbroker.state.InMemoryServiceInstanceStateRepository;
|
||||
import org.springframework.cloud.appbroker.state.ServiceInstanceStateRepository;
|
||||
import org.springframework.cloud.appbroker.workflow.instance.AppDeploymentCreateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.appbroker.workflow.instance.AppDeploymentDeleteServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.appbroker.service.DeleteServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.appbroker.workflow.instance.AppDeploymentUpdateServiceInstanceWorkflow;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@AutoConfigureAfter(AppDeployerAutoConfiguration.class)
|
||||
@ConditionalOnBean(AppDeployer.class)
|
||||
@@ -100,35 +103,45 @@ public class AppBrokerAutoConfiguration {
|
||||
public SpringSecurityBasicAuthCredentialProviderFactory springSecurityBasicAuthCredentialProvider(CredentialGenerator credentialGenerator) {
|
||||
return new SpringSecurityBasicAuthCredentialProviderFactory(credentialGenerator);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public CredentialProviderService credentialProviderService(List<CredentialProviderFactory<?>> providers) {
|
||||
return new CredentialProviderService(providers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpacePerServiceInstance targetFactory() {
|
||||
return new SpacePerServiceInstance();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TargetService targetService(List<TargetFactory<?>> targets) {
|
||||
return new TargetService(targets);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CreateServiceInstanceWorkflow appDeploymentCreateServiceInstanceWorkflow(BrokeredServices brokeredServices,
|
||||
BackingAppDeploymentService backingAppDeploymentService,
|
||||
ParametersTransformationService parametersTransformationService,
|
||||
CredentialProviderService credentialProviderService) {
|
||||
return new AppDeploymentCreateServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService,
|
||||
parametersTransformationService, credentialProviderService);
|
||||
CredentialProviderService credentialProviderService,
|
||||
TargetService targetService) {
|
||||
return new AppDeploymentCreateServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, parametersTransformationService, credentialProviderService, targetService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DeleteServiceInstanceWorkflow appDeploymentDeleteServiceInstanceWorkflow(BrokeredServices brokeredServices,
|
||||
BackingAppDeploymentService backingAppDeploymentService,
|
||||
CredentialProviderService credentialProviderService) {
|
||||
return new AppDeploymentDeleteServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService,
|
||||
credentialProviderService);
|
||||
CredentialProviderService credentialProviderService,
|
||||
TargetService targetService) {
|
||||
return new AppDeploymentDeleteServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, credentialProviderService, targetService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UpdateServiceInstanceWorkflow appDeploymentUpdateServiceInstanceWorkflow(BrokeredServices brokeredServices,
|
||||
BackingAppDeploymentService backingAppDeploymentService,
|
||||
ParametersTransformationService parametersTransformationService) {
|
||||
return new AppDeploymentUpdateServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService,
|
||||
parametersTransformationService);
|
||||
public UpdateServiceInstanceWorkflow updateServiceInstanceWorkflow(BrokeredServices brokeredServices,
|
||||
BackingAppDeploymentService backingAppDeploymentService,
|
||||
ParametersTransformationService parametersTransformationService,
|
||||
TargetService targetService) {
|
||||
return new AppDeploymentUpdateServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, parametersTransformationService, targetService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -34,9 +34,12 @@ public class AppDeployerAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnBean(CloudFoundryOperations.class)
|
||||
public AppDeployer cloudFoundryAppDeployer(CloudFoundryOperations cloudFoundryOperations,
|
||||
CloudFoundryProperties cloudFoundryProperties,
|
||||
ResourceLoader resourceLoader) {
|
||||
CloudFoundryDeploymentProperties cloudFoundryDeploymentProperties = new CloudFoundryDeploymentProperties();
|
||||
return new CloudFoundryAppDeployer(cloudFoundryDeploymentProperties,
|
||||
cloudFoundryOperations, resourceLoader);
|
||||
|
||||
cloudFoundryDeploymentProperties.setDefaultOrg(cloudFoundryProperties.getDefaultOrg());
|
||||
cloudFoundryDeploymentProperties.setUsername(cloudFoundryProperties.getUsername());
|
||||
return new CloudFoundryAppDeployer(cloudFoundryDeploymentProperties, cloudFoundryOperations, resourceLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.cloud.appbroker.deployer.BackingApplications;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.deployer.DeployerClient;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetService;
|
||||
import org.springframework.cloud.appbroker.service.WorkflowServiceInstanceService;
|
||||
import org.springframework.cloud.appbroker.workflow.instance.AppDeploymentCreateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService;
|
||||
@@ -95,6 +96,7 @@ class AppBrokerAutoConfigurationTest {
|
||||
assertThat(context).hasSingleBean(BackingAppDeploymentService.class);
|
||||
assertThat(context).hasSingleBean(ParametersTransformationService.class);
|
||||
assertThat(context).hasSingleBean(CredentialProviderService.class);
|
||||
assertThat(context).hasSingleBean(TargetService.class);
|
||||
assertThat(context).hasSingleBean(WorkflowServiceInstanceService.class);
|
||||
assertThat(context).hasSingleBean(AppDeploymentCreateServiceInstanceWorkflow.class);
|
||||
assertThat(context).hasSingleBean(AppDeploymentDeleteServiceInstanceWorkflow.class);
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.Objects;
|
||||
public class BackingApplication {
|
||||
|
||||
private static final String VALUE_HIDDEN = "<value hidden>";
|
||||
|
||||
|
||||
private String name;
|
||||
private String path;
|
||||
private Map<String, String> properties;
|
||||
@@ -34,6 +34,7 @@ public class BackingApplication {
|
||||
private List<String> services;
|
||||
private List<ParametersTransformerSpec> parametersTransformers;
|
||||
private List<CredentialProviderSpec> credentialProviders;
|
||||
private TargetSpec target;
|
||||
|
||||
public BackingApplication(BackingApplication backingApplicationToCopy) {
|
||||
this.name = backingApplicationToCopy.name;
|
||||
@@ -53,15 +54,19 @@ public class BackingApplication {
|
||||
this.credentialProviders = backingApplicationToCopy.credentialProviders == null
|
||||
? new ArrayList<>()
|
||||
: new ArrayList<>(backingApplicationToCopy.credentialProviders);
|
||||
this.target = backingApplicationToCopy.target;
|
||||
}
|
||||
|
||||
private BackingApplication() {
|
||||
}
|
||||
|
||||
BackingApplication(String name, String path, Map<String, String> properties,
|
||||
Map<String, String> environment, List<String> services,
|
||||
private BackingApplication(String name, String path,
|
||||
Map<String, String> properties,
|
||||
Map<String, String> environment,
|
||||
List<String> services,
|
||||
List<ParametersTransformerSpec> parametersTransformers,
|
||||
List<CredentialProviderSpec> credentialProviders) {
|
||||
List<CredentialProviderSpec> credentialProviders,
|
||||
TargetSpec target) {
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.properties = properties;
|
||||
@@ -69,6 +74,7 @@ public class BackingApplication {
|
||||
this.services = services;
|
||||
this.parametersTransformers = parametersTransformers;
|
||||
this.credentialProviders = credentialProviders;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -135,6 +141,14 @@ public class BackingApplication {
|
||||
this.credentialProviders = credentialProviders;
|
||||
}
|
||||
|
||||
public TargetSpec getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(TargetSpec target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public static BackingApplicationBuilder builder() {
|
||||
return new BackingApplicationBuilder();
|
||||
}
|
||||
@@ -154,13 +168,14 @@ public class BackingApplication {
|
||||
Objects.equals(environment, that.environment) &&
|
||||
Objects.equals(services, that.services) &&
|
||||
Objects.equals(parametersTransformers, that.parametersTransformers) &&
|
||||
Objects.equals(credentialProviders, that.credentialProviders);
|
||||
Objects.equals(credentialProviders, that.credentialProviders) &&
|
||||
Objects.equals(target, that.target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Objects.hash(name, path, properties, environment, services,
|
||||
parametersTransformers, credentialProviders);
|
||||
parametersTransformers, credentialProviders, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -173,6 +188,7 @@ public class BackingApplication {
|
||||
", services=" + services +
|
||||
", parametersTransformers=" + parametersTransformers +
|
||||
", credentialProviders=" + credentialProviders +
|
||||
", target=" + target +
|
||||
'}';
|
||||
}
|
||||
|
||||
@@ -196,6 +212,7 @@ public class BackingApplication {
|
||||
private final List<String> services = new ArrayList<>();
|
||||
private final List<ParametersTransformerSpec> parameterTransformers = new ArrayList<>();
|
||||
private final List<CredentialProviderSpec> credentialProviders = new ArrayList<>();
|
||||
private TargetSpec target;
|
||||
|
||||
BackingApplicationBuilder() {
|
||||
}
|
||||
@@ -245,9 +262,14 @@ public class BackingApplication {
|
||||
return this;
|
||||
}
|
||||
|
||||
public BackingApplicationBuilder target(TargetSpec targetSpec) {
|
||||
this.target = targetSpec;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BackingApplication build() {
|
||||
return new BackingApplication(name, path, properties, environment, services,
|
||||
parameterTransformers, credentialProviders);
|
||||
parameterTransformers, credentialProviders, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public class DeployerClient {
|
||||
|
||||
Mono<String> undeploy(BackingApplication backingApplication) {
|
||||
return appDeployer.undeploy(UndeployApplicationRequest.builder()
|
||||
.properties(backingApplication.getProperties())
|
||||
.name(backingApplication.getName())
|
||||
.build())
|
||||
.map(UndeployApplicationResponse::getName);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2016-2018. the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.cloud.appbroker.deployer;
|
||||
|
||||
public class TargetSpec {
|
||||
|
||||
private String name;
|
||||
|
||||
private TargetSpec() {
|
||||
}
|
||||
|
||||
private TargetSpec(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public static TargetSpecBuilder builder() {
|
||||
return new TargetSpecBuilder();
|
||||
}
|
||||
|
||||
public static class TargetSpecBuilder {
|
||||
|
||||
private String name;
|
||||
|
||||
private TargetSpecBuilder() {
|
||||
}
|
||||
|
||||
public TargetSpecBuilder name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TargetSpec build() {
|
||||
return new TargetSpec(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,7 @@ public class ExtensionLocator<T> {
|
||||
private final Map<String, ExtensionFactory<T, ?>> factoriesByName = new HashMap<>();
|
||||
|
||||
public ExtensionLocator(List<? extends ExtensionFactory<T, ?>> factories) {
|
||||
factories.forEach(parametersTransformer ->
|
||||
this.factoriesByName.put(parametersTransformer.getName(), parametersTransformer));
|
||||
factories.forEach(extension -> this.factoriesByName.put(extension.getName(), extension));
|
||||
}
|
||||
|
||||
public T getByName(String name, Map<String, Object> args) {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2016-2018. the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.cloud.appbroker.extensions.targets;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingApplication;
|
||||
import org.springframework.cloud.appbroker.deployer.DeploymentProperties;
|
||||
|
||||
public class SpacePerServiceInstance extends TargetFactory<SpacePerServiceInstance.Config> {
|
||||
|
||||
public SpacePerServiceInstance() {
|
||||
super(Config.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target create(Config config) {
|
||||
return this::apply;
|
||||
}
|
||||
|
||||
private Mono<BackingApplication> apply(BackingApplication backingApplication, String serviceInstanceId) {
|
||||
backingApplication.getProperties().put(DeploymentProperties.HOST_KEY, backingApplication.getName() + "-" + serviceInstanceId);
|
||||
backingApplication.getProperties().put(DeploymentProperties.TARGET_KEY, serviceInstanceId);
|
||||
|
||||
return Mono.just(backingApplication);
|
||||
}
|
||||
|
||||
static class Config {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2016-2018. the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.cloud.appbroker.extensions.targets;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingApplication;
|
||||
|
||||
public interface Target {
|
||||
|
||||
Mono<BackingApplication> apply(BackingApplication backingApplication, String serviceInstanceId);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2016-2018. the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.cloud.appbroker.extensions.targets;
|
||||
|
||||
import org.springframework.cloud.appbroker.extensions.AbstractExtensionFactory;
|
||||
|
||||
public abstract class TargetFactory<C> extends AbstractExtensionFactory<Target, C> {
|
||||
|
||||
TargetFactory() {
|
||||
super();
|
||||
}
|
||||
|
||||
TargetFactory(Class<C> configClass) {
|
||||
super(configClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Target create(C config);
|
||||
|
||||
public String getName() {
|
||||
return getShortName(TargetFactory.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2016-2018. the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.cloud.appbroker.extensions.targets;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingApplication;
|
||||
import org.springframework.cloud.appbroker.deployer.TargetSpec;
|
||||
import org.springframework.cloud.appbroker.extensions.ExtensionLocator;
|
||||
|
||||
public class TargetService {
|
||||
|
||||
private final ExtensionLocator<Target> locator;
|
||||
|
||||
public TargetService(List<TargetFactory<?>> factories) {
|
||||
locator = new ExtensionLocator<>(factories);
|
||||
}
|
||||
|
||||
public Mono<List<BackingApplication>> add(List<BackingApplication> backingApplications,
|
||||
String serviceInstanceId) {
|
||||
|
||||
return Flux.fromIterable(backingApplications)
|
||||
.flatMap(backingApplication -> {
|
||||
TargetSpec targetSpec = backingApplication.getTarget();
|
||||
if (targetSpec != null) {
|
||||
Target target = locator.getByName(targetSpec.getName(), Collections.emptyMap());
|
||||
return target.apply(backingApplication, serviceInstanceId);
|
||||
}
|
||||
return Mono.just(backingApplication);
|
||||
|
||||
})
|
||||
.collectList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,43 +16,49 @@
|
||||
|
||||
package org.springframework.cloud.appbroker.workflow.instance;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService;
|
||||
import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse.CreateServiceInstanceResponseBuilder;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import reactor.core.publisher.Flux;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.Logger;
|
||||
import reactor.util.Loggers;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetService;
|
||||
import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
|
||||
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse.CreateServiceInstanceResponseBuilder;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
@Order(0)
|
||||
public class AppDeploymentCreateServiceInstanceWorkflow
|
||||
extends AppDeploymentInstanceWorkflow
|
||||
implements CreateServiceInstanceWorkflow {
|
||||
|
||||
private final Logger log = Loggers.getLogger(AppDeploymentCreateServiceInstanceWorkflow.class);
|
||||
|
||||
private final BackingAppDeploymentService deploymentService;
|
||||
private final ParametersTransformationService parametersTransformationService;
|
||||
private final CredentialProviderService credentialProviderService;
|
||||
private final TargetService targetService;
|
||||
|
||||
public AppDeploymentCreateServiceInstanceWorkflow(BrokeredServices brokeredServices,
|
||||
BackingAppDeploymentService deploymentService,
|
||||
ParametersTransformationService parametersTransformationService,
|
||||
CredentialProviderService credentialProviderService) {
|
||||
CredentialProviderService credentialProviderService,
|
||||
TargetService targetService) {
|
||||
super(brokeredServices);
|
||||
this.deploymentService = deploymentService;
|
||||
this.parametersTransformationService = parametersTransformationService;
|
||||
this.credentialProviderService = credentialProviderService;
|
||||
this.targetService = targetService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Void> create(CreateServiceInstanceRequest request) {
|
||||
return getBackingApplicationsForService(request.getServiceDefinition(), request.getPlanId())
|
||||
.flatMap(backingApps -> targetService.add(backingApps, request.getServiceInstanceId()))
|
||||
.flatMap(backingApps ->
|
||||
parametersTransformationService.transformParameters(backingApps, request.getParameters()))
|
||||
.flatMap(backingApplications ->
|
||||
|
||||
@@ -16,34 +16,39 @@
|
||||
|
||||
package org.springframework.cloud.appbroker.workflow.instance;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.Logger;
|
||||
import reactor.util.Loggers;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetService;
|
||||
import org.springframework.cloud.appbroker.service.DeleteServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
|
||||
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse.DeleteServiceInstanceResponseBuilder;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.Logger;
|
||||
import reactor.util.Loggers;
|
||||
|
||||
@Order(0)
|
||||
public class AppDeploymentDeleteServiceInstanceWorkflow
|
||||
extends AppDeploymentInstanceWorkflow
|
||||
implements DeleteServiceInstanceWorkflow {
|
||||
|
||||
private final Logger log = Loggers.getLogger(AppDeploymentDeleteServiceInstanceWorkflow.class);
|
||||
|
||||
private final BackingAppDeploymentService deploymentService;
|
||||
private final CredentialProviderService credentialProviderService;
|
||||
private final TargetService targetService;
|
||||
|
||||
public AppDeploymentDeleteServiceInstanceWorkflow(BrokeredServices brokeredServices,
|
||||
BackingAppDeploymentService deploymentService,
|
||||
CredentialProviderService credentialProviderService) {
|
||||
CredentialProviderService credentialProviderService,
|
||||
TargetService targetService) {
|
||||
super(brokeredServices);
|
||||
this.deploymentService = deploymentService;
|
||||
this.credentialProviderService = credentialProviderService;
|
||||
this.targetService = targetService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,6 +56,7 @@ public class AppDeploymentDeleteServiceInstanceWorkflow
|
||||
return getBackingApplicationsForService(request.getServiceDefinition(), request.getPlanId())
|
||||
.flatMap(backingApplications ->
|
||||
credentialProviderService.deleteCredentials(backingApplications, request.getServiceInstanceId()))
|
||||
.flatMap(backingApps -> targetService.add(backingApps, request.getServiceInstanceId()))
|
||||
.flatMapMany(deploymentService::undeploy)
|
||||
.doOnRequest(l -> log.info("Undeploying applications {}", brokeredServices))
|
||||
.doOnEach(s -> log.info("Finished undeploying {}", s))
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.appbroker.workflow.instance;
|
||||
|
||||
import org.springframework.cloud.appbroker.service.UpdateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse.UpdateServiceInstanceResponseBuilder;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.Logger;
|
||||
@@ -27,27 +24,36 @@ import reactor.util.Loggers;
|
||||
import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetService;
|
||||
import org.springframework.cloud.appbroker.service.UpdateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
|
||||
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse.UpdateServiceInstanceResponseBuilder;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
@Order(0)
|
||||
public class AppDeploymentUpdateServiceInstanceWorkflow
|
||||
extends AppDeploymentInstanceWorkflow
|
||||
implements UpdateServiceInstanceWorkflow {
|
||||
|
||||
private final Logger log = Loggers.getLogger(AppDeploymentUpdateServiceInstanceWorkflow.class);
|
||||
|
||||
private final BackingAppDeploymentService deploymentService;
|
||||
private final ParametersTransformationService parametersTransformationService;
|
||||
private final TargetService targetService;
|
||||
|
||||
public AppDeploymentUpdateServiceInstanceWorkflow(BrokeredServices brokeredServices,
|
||||
BackingAppDeploymentService deploymentService,
|
||||
ParametersTransformationService parametersTransformationService) {
|
||||
ParametersTransformationService parametersTransformationService,
|
||||
TargetService targetService) {
|
||||
super(brokeredServices);
|
||||
this.deploymentService = deploymentService;
|
||||
this.parametersTransformationService = parametersTransformationService;
|
||||
this.targetService = targetService;
|
||||
}
|
||||
|
||||
public Flux<Void> update(UpdateServiceInstanceRequest request) {
|
||||
return getBackingApplicationsForService(request.getServiceDefinition(), request.getPlanId())
|
||||
.flatMap(backingApps -> targetService.add(backingApps, request.getServiceInstanceId()))
|
||||
.flatMap(backingApps ->
|
||||
parametersTransformationService.transformParameters(backingApps, request.getParameters()))
|
||||
.flatMapMany(deploymentService::deploy)
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2016-2018. the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.cloud.appbroker.extensions.targets;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingApplication;
|
||||
import org.springframework.cloud.appbroker.deployer.TargetSpec;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class TargetServiceTest {
|
||||
|
||||
private TargetService targetService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
targetService = new TargetService(singletonList(new SpacePerServiceInstance()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddProperties() {
|
||||
// given an app with a target
|
||||
TargetSpec spacePerServiceInstanceFactory = TargetSpec.builder().name("SpacePerServiceInstance").build();
|
||||
BackingApplication backingApplication = BackingApplication.builder().name("app-name").target(spacePerServiceInstanceFactory).build();
|
||||
|
||||
//when add gets called
|
||||
List<BackingApplication> updatedBackingApplications = targetService.add(singletonList(backingApplication), "service-id").block();
|
||||
|
||||
//then a host and space are added
|
||||
BackingApplication updatedBackingApplication = updatedBackingApplications.get(0);
|
||||
assertThat(updatedBackingApplication.getProperties().get("host")).isEqualTo("app-name-service-id");
|
||||
assertThat(updatedBackingApplication.getProperties().get("target")).isEqualTo("service-id");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddPropertiesToAllBackingApps() {
|
||||
// given an app with a target
|
||||
TargetSpec spacePerServiceInstanceFactory = TargetSpec.builder().name("SpacePerServiceInstance").build();
|
||||
BackingApplication backingApplication1 = BackingApplication.builder().name("app-name1").target(spacePerServiceInstanceFactory).build();
|
||||
BackingApplication backingApplication2 = BackingApplication.builder().name("app-name2").target(spacePerServiceInstanceFactory).build();
|
||||
|
||||
//when add gets called
|
||||
List<BackingApplication> updatedBackingApplications = targetService.add(Lists.list(backingApplication1, backingApplication2), "service-id").block();
|
||||
|
||||
//then a host and space are added
|
||||
BackingApplication updatedBackingApplication1 = updatedBackingApplications.get(0);
|
||||
assertThat(updatedBackingApplication1.getProperties().get("host")).isEqualTo("app-name1-service-id");
|
||||
assertThat(updatedBackingApplication1.getProperties().get("target")).isEqualTo("service-id");
|
||||
|
||||
BackingApplication updatedBackingApplication2 = updatedBackingApplications.get(1);
|
||||
assertThat(updatedBackingApplication2.getProperties().get("host")).isEqualTo("app-name2-service-id");
|
||||
assertThat(updatedBackingApplication2.getProperties().get("target")).isEqualTo("service-id");
|
||||
}
|
||||
}
|
||||
@@ -16,33 +16,35 @@
|
||||
|
||||
package org.springframework.cloud.appbroker.workflow.instance;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredService;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService;
|
||||
import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.servicebroker.model.catalog.Plan;
|
||||
import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition;
|
||||
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
|
||||
import org.springframework.cloud.appbroker.deployer.BackingApplication;
|
||||
import org.springframework.cloud.appbroker.deployer.BackingApplications;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredService;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetService;
|
||||
import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.servicebroker.model.catalog.Plan;
|
||||
import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition;
|
||||
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@@ -57,25 +59,33 @@ class AppDeploymentCreateServiceInstanceWorkflowTest {
|
||||
@Mock
|
||||
private CredentialProviderService credentialProviderService;
|
||||
|
||||
@Mock
|
||||
private TargetService targetService;
|
||||
|
||||
private BackingApplications backingApps;
|
||||
|
||||
private CreateServiceInstanceWorkflow createServiceInstanceWorkflow;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
backingApps = BackingApplications.builder()
|
||||
.backingApplication(BackingApplication.builder()
|
||||
backingApps = BackingApplications
|
||||
.builder()
|
||||
.backingApplication(BackingApplication
|
||||
.builder()
|
||||
.name("app1")
|
||||
.path("http://myfiles/app1.jar")
|
||||
.build())
|
||||
.backingApplication(BackingApplication.builder()
|
||||
.backingApplication(BackingApplication
|
||||
.builder()
|
||||
.name("app2")
|
||||
.path("http://myfiles/app2.jar")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
BrokeredServices brokeredServices = BrokeredServices.builder()
|
||||
.service(BrokeredService.builder()
|
||||
BrokeredServices brokeredServices = BrokeredServices
|
||||
.builder()
|
||||
.service(BrokeredService
|
||||
.builder()
|
||||
.serviceName("service1")
|
||||
.planName("plan1")
|
||||
.apps(backingApps)
|
||||
@@ -86,7 +96,8 @@ class AppDeploymentCreateServiceInstanceWorkflowTest {
|
||||
brokeredServices,
|
||||
backingAppDeploymentService,
|
||||
parametersTransformationService,
|
||||
credentialProviderService);
|
||||
credentialProviderService,
|
||||
targetService);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,6 +111,8 @@ class AppDeploymentCreateServiceInstanceWorkflowTest {
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.credentialProviderService.addCredentials(eq(backingApps), eq(request.getServiceInstanceId())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.targetService.add(eq(backingApps), eq(request.getServiceInstanceId())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
|
||||
StepVerifier
|
||||
.create(createServiceInstanceWorkflow.create(request))
|
||||
@@ -107,9 +120,9 @@ class AppDeploymentCreateServiceInstanceWorkflowTest {
|
||||
.expectNext()
|
||||
.verifyComplete();
|
||||
|
||||
verifyNoMoreInteractions(this.backingAppDeploymentService);
|
||||
verifyNoMoreInteractions(this.parametersTransformationService);
|
||||
verifyNoMoreInteractions(this.credentialProviderService);
|
||||
verify(backingAppDeploymentService).deploy(backingApps);
|
||||
|
||||
verifyNoMoreInteractionsWithServices();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -123,6 +136,8 @@ class AppDeploymentCreateServiceInstanceWorkflowTest {
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.credentialProviderService.addCredentials(eq(backingApps), eq(request.getServiceInstanceId())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.targetService.add(eq(backingApps), eq(request.getServiceInstanceId())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
|
||||
StepVerifier
|
||||
.create(createServiceInstanceWorkflow.create(request))
|
||||
@@ -130,9 +145,35 @@ class AppDeploymentCreateServiceInstanceWorkflowTest {
|
||||
.expectNext()
|
||||
.verifyComplete();
|
||||
|
||||
verifyNoMoreInteractions(this.backingAppDeploymentService);
|
||||
verifyNoMoreInteractions(this.parametersTransformationService);
|
||||
verifyNoMoreInteractions(this.credentialProviderService);
|
||||
verify(parametersTransformationService).transformParameters(backingApps, singletonMap("ENV_VAR_1", "value from parameters"));
|
||||
|
||||
verifyNoMoreInteractionsWithServices();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createServiceInstanceWithTargetSucceeds() {
|
||||
CreateServiceInstanceRequest request = buildRequest("service1", "plan1",
|
||||
singletonMap("ENV_VAR_1", "value from parameters"));
|
||||
|
||||
given(this.backingAppDeploymentService.deploy(eq(backingApps)))
|
||||
.willReturn(Flux.just("app1", "app2"));
|
||||
given(this.parametersTransformationService.transformParameters(eq(backingApps), eq(request.getParameters())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.credentialProviderService.addCredentials(eq(backingApps), eq(request.getServiceInstanceId())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.targetService.add(eq(backingApps), eq(request.getServiceInstanceId())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
|
||||
StepVerifier
|
||||
.create(createServiceInstanceWorkflow.create(request))
|
||||
.expectNext()
|
||||
.expectNext()
|
||||
.verifyComplete();
|
||||
|
||||
final String expectedServiceId = "service-instance-id";
|
||||
verify(targetService).add(backingApps, expectedServiceId);
|
||||
|
||||
verifyNoMoreInteractionsWithServices();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -143,9 +184,14 @@ class AppDeploymentCreateServiceInstanceWorkflowTest {
|
||||
.create(createServiceInstanceWorkflow.create(request))
|
||||
.verifyComplete();
|
||||
|
||||
verifyNoMoreInteractionsWithServices();
|
||||
}
|
||||
|
||||
private void verifyNoMoreInteractionsWithServices() {
|
||||
verifyNoMoreInteractions(this.backingAppDeploymentService);
|
||||
verifyNoMoreInteractions(this.parametersTransformationService);
|
||||
verifyNoMoreInteractions(this.credentialProviderService);
|
||||
verifyNoMoreInteractions(this.targetService);
|
||||
}
|
||||
|
||||
private CreateServiceInstanceRequest buildRequest(String serviceName, String planName) {
|
||||
@@ -154,17 +200,19 @@ class AppDeploymentCreateServiceInstanceWorkflowTest {
|
||||
|
||||
private CreateServiceInstanceRequest buildRequest(String serviceName, String planName,
|
||||
Map<String, Object> parameters) {
|
||||
return CreateServiceInstanceRequest.builder()
|
||||
return CreateServiceInstanceRequest
|
||||
.builder()
|
||||
.serviceInstanceId("service-instance-id")
|
||||
.serviceDefinitionId(serviceName + "-id")
|
||||
.planId(planName + "-id")
|
||||
.serviceInstanceId(serviceName + "-" + planName + "-instance-id")
|
||||
.serviceDefinition(ServiceDefinition.builder()
|
||||
.serviceDefinition(ServiceDefinition
|
||||
.builder()
|
||||
.id(serviceName + "-id")
|
||||
.name(serviceName)
|
||||
.plans(Plan.builder()
|
||||
.id(planName + "-id")
|
||||
.name(planName)
|
||||
.build())
|
||||
.id(planName + "-id")
|
||||
.name(planName)
|
||||
.build())
|
||||
.build())
|
||||
.parameters(parameters == null ? new HashMap<>() : parameters)
|
||||
.build();
|
||||
|
||||
@@ -21,19 +21,21 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
|
||||
import org.springframework.cloud.appbroker.deployer.BackingApplication;
|
||||
import org.springframework.cloud.appbroker.deployer.BackingApplications;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredService;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetService;
|
||||
import org.springframework.cloud.appbroker.service.DeleteServiceInstanceWorkflow;
|
||||
import org.springframework.cloud.servicebroker.model.catalog.Plan;
|
||||
import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition;
|
||||
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -45,6 +47,9 @@ class AppDeploymentDeleteServiceInstanceWorkflowTest {
|
||||
@Mock
|
||||
private BackingAppDeploymentService backingAppDeploymentService;
|
||||
|
||||
@Mock
|
||||
private TargetService targetService;
|
||||
|
||||
@Mock
|
||||
private CredentialProviderService credentialProviderService;
|
||||
|
||||
@@ -53,27 +58,33 @@ class AppDeploymentDeleteServiceInstanceWorkflowTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
backingApps = BackingApplications.builder()
|
||||
backingApps = BackingApplications
|
||||
.builder()
|
||||
.backingApplication(BackingApplication.builder()
|
||||
.name("app1")
|
||||
.path("http://myfiles/app1.jar")
|
||||
.build())
|
||||
.name("app1")
|
||||
.path("http://myfiles/app1.jar")
|
||||
.build())
|
||||
.backingApplication(BackingApplication.builder()
|
||||
.name("app2")
|
||||
.path("http://myfiles/app2.jar")
|
||||
.build())
|
||||
.name("app2")
|
||||
.path("http://myfiles/app2.jar")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
BrokeredServices brokeredServices = BrokeredServices.builder()
|
||||
BrokeredServices brokeredServices = BrokeredServices
|
||||
.builder()
|
||||
.service(BrokeredService.builder()
|
||||
.serviceName("service1")
|
||||
.planName("plan1")
|
||||
.apps(backingApps)
|
||||
.build())
|
||||
.serviceName("service1")
|
||||
.planName("plan1")
|
||||
.apps(backingApps)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
deleteServiceInstanceWorkflow = new AppDeploymentDeleteServiceInstanceWorkflow(brokeredServices,
|
||||
backingAppDeploymentService, credentialProviderService);
|
||||
deleteServiceInstanceWorkflow =
|
||||
new AppDeploymentDeleteServiceInstanceWorkflow(
|
||||
brokeredServices,
|
||||
backingAppDeploymentService,
|
||||
credentialProviderService,
|
||||
targetService);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -84,6 +95,8 @@ class AppDeploymentDeleteServiceInstanceWorkflowTest {
|
||||
.willReturn(Flux.just("undeployed1", "undeployed2"));
|
||||
given(this.credentialProviderService.deleteCredentials(eq(backingApps), eq(request.getServiceInstanceId())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.targetService.add(eq(backingApps), eq("service-instance-id")))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
|
||||
StepVerifier
|
||||
.create(deleteServiceInstanceWorkflow.delete(request))
|
||||
@@ -93,6 +106,7 @@ class AppDeploymentDeleteServiceInstanceWorkflowTest {
|
||||
|
||||
verifyNoMoreInteractions(this.backingAppDeploymentService);
|
||||
verifyNoMoreInteractions(this.credentialProviderService);
|
||||
verifyNoMoreInteractions(this.targetService);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,21 +117,23 @@ class AppDeploymentDeleteServiceInstanceWorkflowTest {
|
||||
|
||||
verifyNoMoreInteractions(this.backingAppDeploymentService);
|
||||
verifyNoMoreInteractions(this.credentialProviderService);
|
||||
verifyNoMoreInteractions(this.targetService);
|
||||
}
|
||||
|
||||
private DeleteServiceInstanceRequest buildRequest(String serviceName, String planName) {
|
||||
return DeleteServiceInstanceRequest.builder()
|
||||
return DeleteServiceInstanceRequest
|
||||
.builder()
|
||||
.serviceDefinitionId(serviceName + "-id")
|
||||
.serviceInstanceId("service-instance-id")
|
||||
.planId(planName + "-id")
|
||||
.serviceInstanceId(serviceName + "-" + planName + "-instance-id")
|
||||
.serviceDefinition(ServiceDefinition.builder()
|
||||
.id(serviceName + "-id")
|
||||
.name(serviceName)
|
||||
.plans(Plan.builder()
|
||||
.id(planName + "-id")
|
||||
.name(planName)
|
||||
.build())
|
||||
.build())
|
||||
.id(serviceName + "-id")
|
||||
.name(serviceName)
|
||||
.plans(Plan.builder()
|
||||
.id(planName + "-id")
|
||||
.name(planName)
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import org.springframework.cloud.appbroker.deployer.BackingApplications;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredService;
|
||||
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
|
||||
import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService;
|
||||
import org.springframework.cloud.appbroker.extensions.targets.TargetService;
|
||||
import org.springframework.cloud.servicebroker.model.catalog.Plan;
|
||||
import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition;
|
||||
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
|
||||
@@ -52,34 +53,40 @@ class AppDeploymentUpdateServiceInstanceWorkflowTest {
|
||||
@Mock
|
||||
private ParametersTransformationService parametersTransformationService;
|
||||
|
||||
@Mock
|
||||
private TargetService targetService;
|
||||
|
||||
private BackingApplications backingApps;
|
||||
private AppDeploymentUpdateServiceInstanceWorkflow updateServiceInstanceWorkflow;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
backingApps = BackingApplications.builder()
|
||||
backingApps = BackingApplications
|
||||
.builder()
|
||||
.backingApplication(BackingApplication.builder()
|
||||
.name("app1")
|
||||
.path("http://myfiles/app1.jar")
|
||||
.build())
|
||||
.name("app1")
|
||||
.path("http://myfiles/app1.jar")
|
||||
.build())
|
||||
.backingApplication(BackingApplication.builder()
|
||||
.name("app2")
|
||||
.path("http://myfiles/app2.jar")
|
||||
.build())
|
||||
.name("app2")
|
||||
.path("http://myfiles/app2.jar")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
BrokeredServices brokeredServices = BrokeredServices.builder()
|
||||
BrokeredServices brokeredServices = BrokeredServices
|
||||
.builder()
|
||||
.service(BrokeredService.builder()
|
||||
.serviceName("service1")
|
||||
.planName("plan1")
|
||||
.apps(backingApps)
|
||||
.build())
|
||||
.serviceName("service1")
|
||||
.planName("plan1")
|
||||
.apps(backingApps)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
updateServiceInstanceWorkflow = new AppDeploymentUpdateServiceInstanceWorkflow(brokeredServices,
|
||||
backingAppDeploymentService,
|
||||
parametersTransformationService
|
||||
);
|
||||
parametersTransformationService,
|
||||
targetService)
|
||||
;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -89,6 +96,8 @@ class AppDeploymentUpdateServiceInstanceWorkflowTest {
|
||||
|
||||
given(this.backingAppDeploymentService.deploy(eq(backingApps)))
|
||||
.willReturn(Flux.just("app1", "app2"));
|
||||
given(this.targetService.add(eq(backingApps), eq("service-instance-id")))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.parametersTransformationService.transformParameters(eq(backingApps), eq(request.getParameters())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
|
||||
@@ -100,6 +109,7 @@ class AppDeploymentUpdateServiceInstanceWorkflowTest {
|
||||
|
||||
verifyNoMoreInteractions(this.backingAppDeploymentService);
|
||||
verifyNoMoreInteractions(this.parametersTransformationService);
|
||||
verifyNoMoreInteractions(this.targetService);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -111,6 +121,8 @@ class AppDeploymentUpdateServiceInstanceWorkflowTest {
|
||||
.willReturn(Flux.just("app1", "app2"));
|
||||
given(this.parametersTransformationService.transformParameters(eq(backingApps), eq(request.getParameters())))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
given(this.targetService.add(eq(backingApps), eq("service-instance-id")))
|
||||
.willReturn(Mono.just(backingApps));
|
||||
|
||||
StepVerifier
|
||||
.create(updateServiceInstanceWorkflow.update(request))
|
||||
@@ -120,6 +132,7 @@ class AppDeploymentUpdateServiceInstanceWorkflowTest {
|
||||
|
||||
verifyNoMoreInteractions(this.backingAppDeploymentService);
|
||||
verifyNoMoreInteractions(this.parametersTransformationService);
|
||||
verifyNoMoreInteractions(this.targetService);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -130,6 +143,7 @@ class AppDeploymentUpdateServiceInstanceWorkflowTest {
|
||||
|
||||
verifyNoMoreInteractions(this.backingAppDeploymentService);
|
||||
verifyNoMoreInteractions(this.parametersTransformationService);
|
||||
verifyNoMoreInteractions(this.targetService);
|
||||
}
|
||||
|
||||
private UpdateServiceInstanceRequest buildRequest(String serviceName, String planName) {
|
||||
@@ -138,18 +152,19 @@ class AppDeploymentUpdateServiceInstanceWorkflowTest {
|
||||
|
||||
private UpdateServiceInstanceRequest buildRequest(String serviceName, String planName,
|
||||
Map<String, Object> parameters) {
|
||||
return UpdateServiceInstanceRequest.builder()
|
||||
return UpdateServiceInstanceRequest
|
||||
.builder()
|
||||
.serviceInstanceId("service-instance-id")
|
||||
.serviceDefinitionId(serviceName + "-id")
|
||||
.planId(planName + "-id")
|
||||
.serviceInstanceId(serviceName + "-" + planName + "-instance-id")
|
||||
.serviceDefinition(ServiceDefinition.builder()
|
||||
.id(serviceName + "-id")
|
||||
.name(serviceName)
|
||||
.plans(Plan.builder()
|
||||
.id(planName + "-id")
|
||||
.name(planName)
|
||||
.build())
|
||||
.build())
|
||||
.id(serviceName + "-id")
|
||||
.name(serviceName)
|
||||
.plans(Plan.builder()
|
||||
.id(planName + "-id")
|
||||
.name(planName)
|
||||
.build())
|
||||
.build())
|
||||
.parameters(parameters == null ? new HashMap<>() : parameters)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -34,30 +34,37 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.cloudfoundry.AbstractCloudFoundryException;
|
||||
import org.cloudfoundry.UnknownCloudFoundryException;
|
||||
import org.cloudfoundry.operations.CloudFoundryOperations;
|
||||
import org.cloudfoundry.operations.applications.ApplicationDetail;
|
||||
import org.cloudfoundry.operations.DefaultCloudFoundryOperations;
|
||||
import org.cloudfoundry.operations.applications.ApplicationHealthCheck;
|
||||
import org.cloudfoundry.operations.applications.ApplicationManifest;
|
||||
import org.cloudfoundry.operations.applications.DefaultApplications;
|
||||
import org.cloudfoundry.operations.applications.DeleteApplicationRequest;
|
||||
import org.cloudfoundry.operations.applications.Docker;
|
||||
import org.cloudfoundry.operations.applications.GetApplicationRequest;
|
||||
import org.cloudfoundry.operations.applications.PushApplicationManifestRequest;
|
||||
import org.cloudfoundry.operations.applications.Route;
|
||||
import org.cloudfoundry.operations.organizations.OrganizationDetail;
|
||||
import org.cloudfoundry.operations.organizations.OrganizationInfoRequest;
|
||||
import org.cloudfoundry.operations.spaces.CreateSpaceRequest;
|
||||
import org.cloudfoundry.operations.spaces.DefaultSpaces;
|
||||
import org.cloudfoundry.operations.spaces.DeleteSpaceRequest;
|
||||
import org.cloudfoundry.operations.spaces.GetSpaceRequest;
|
||||
import org.cloudfoundry.operations.spaces.SpaceDetail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.appbroker.deployer.DeploymentProperties;
|
||||
import org.springframework.cloud.appbroker.deployer.util.ByteSizeUtils;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import reactor.core.Exceptions;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.appbroker.deployer.AppDeployer;
|
||||
import org.springframework.cloud.appbroker.deployer.DeployApplicationRequest;
|
||||
import org.springframework.cloud.appbroker.deployer.DeployApplicationResponse;
|
||||
import org.springframework.cloud.appbroker.deployer.DeploymentProperties;
|
||||
import org.springframework.cloud.appbroker.deployer.UndeployApplicationRequest;
|
||||
import org.springframework.cloud.appbroker.deployer.UndeployApplicationResponse;
|
||||
import org.springframework.cloud.appbroker.deployer.util.ByteSizeUtils;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@SuppressWarnings("PMD.GodClass")
|
||||
@@ -118,15 +125,22 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
|
||||
|
||||
logger.debug("Pushing manifest" + manifest.toString());
|
||||
|
||||
return requestPushApplication(
|
||||
PushApplicationManifestRequest.builder()
|
||||
.manifest(manifest)
|
||||
.stagingTimeout(this.defaultDeploymentProperties.getStagingTimeout())
|
||||
.startupTimeout(this.defaultDeploymentProperties.getStartupTimeout())
|
||||
.build())
|
||||
.doOnSuccess(v -> logger.info("Done uploading bits for {}", request.getName()))
|
||||
.doOnError(e -> logger.error(String.format("Error creating app %s. Exception Message %s",
|
||||
request.getName(), e.getMessage())));
|
||||
PushApplicationManifestRequest applicationManifestRequest =
|
||||
PushApplicationManifestRequest.builder()
|
||||
.manifest(manifest)
|
||||
.stagingTimeout(this.defaultDeploymentProperties.getStagingTimeout())
|
||||
.startupTimeout(this.defaultDeploymentProperties.getStartupTimeout())
|
||||
.build();
|
||||
|
||||
Mono<Void> requestPushApplication = requestPushApplication(applicationManifestRequest);
|
||||
if (deploymentProperties.containsKey(DeploymentProperties.TARGET_KEY)) {
|
||||
String space = deploymentProperties.get(DeploymentProperties.TARGET_KEY);
|
||||
requestPushApplication = requestPushApplicationInSpace(applicationManifestRequest, space);
|
||||
}
|
||||
|
||||
return requestPushApplication
|
||||
.doOnSuccess(v -> logger.info("Done uploading bits for {}", request.getName()))
|
||||
.doOnError(e -> logger.error(String.format("Error creating app %s. Exception Message %s", request.getName(), e.getMessage())));
|
||||
}
|
||||
|
||||
private ApplicationManifest buildAppManifest(DeployApplicationRequest request,
|
||||
@@ -173,28 +187,49 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
|
||||
.pushManifest(request);
|
||||
}
|
||||
|
||||
private Mono<Void> requestPushApplicationInSpace(PushApplicationManifestRequest request, String space) {
|
||||
return createSpaceOperations()
|
||||
.create(CreateSpaceRequest.builder().name(space).build())
|
||||
.then(createCloudFoundryOperationsForSpace(space).applications().pushManifest(request));
|
||||
}
|
||||
|
||||
private DefaultCloudFoundryOperations createCloudFoundryOperationsForSpace(String space) {
|
||||
return DefaultCloudFoundryOperations
|
||||
.builder()
|
||||
.from((DefaultCloudFoundryOperations) this.operations)
|
||||
.space(space).build();
|
||||
}
|
||||
|
||||
private Mono<String> getOrganizationIdPublisher() {
|
||||
OrganizationInfoRequest organizationInfoRequest =
|
||||
OrganizationInfoRequest.builder().name(this.defaultDeploymentProperties.getDefaultOrg()).build();
|
||||
return this.operations.organizations().get(organizationInfoRequest).map(OrganizationDetail::getId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UndeployApplicationResponse> undeploy(UndeployApplicationRequest request) {
|
||||
String appName = request.getName();
|
||||
|
||||
logger.trace("Undeploying application: request={}", request);
|
||||
|
||||
return requestGetApplication(appName)
|
||||
.timeout(Duration.ofSeconds(this.defaultDeploymentProperties.getApiTimeout()))
|
||||
.then(requestDeleteApplication(appName)
|
||||
Map<String, String> deploymentProperties = request.getProperties();
|
||||
Mono<Void> requestDeleteApplication;
|
||||
if (deploymentProperties.containsKey(DeploymentProperties.TARGET_KEY)) {
|
||||
String space = deploymentProperties.get(DeploymentProperties.TARGET_KEY);
|
||||
requestDeleteApplication = requestDeleteApplicationInSpace(appName, space)
|
||||
.then(createSpaceOperations().delete(DeleteSpaceRequest.builder().name(space).build()));
|
||||
} else {
|
||||
requestDeleteApplication = requestDeleteApplication(appName);
|
||||
}
|
||||
|
||||
return
|
||||
requestDeleteApplication
|
||||
.timeout(Duration.ofSeconds(this.defaultDeploymentProperties.getApiTimeout()))
|
||||
.doOnSuccess(v -> logger.info("Successfully undeployed app {}", appName))
|
||||
.doOnError(logError(String.format("Failed to undeploy app %s", appName)))
|
||||
.then(Mono.just(UndeployApplicationResponse.builder()
|
||||
.name(appName)
|
||||
.build())));
|
||||
}
|
||||
|
||||
private Mono<ApplicationDetail> requestGetApplication(String name) {
|
||||
return this.operations.applications()
|
||||
.get(GetApplicationRequest.builder()
|
||||
.name(name)
|
||||
.build());
|
||||
.build()));
|
||||
}
|
||||
|
||||
private Mono<Void> requestDeleteApplication(String name) {
|
||||
@@ -205,6 +240,28 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
|
||||
.build());
|
||||
}
|
||||
|
||||
private Mono<Void> requestDeleteApplicationInSpace(String name, String space) {
|
||||
return createSpaceApplications(space)
|
||||
.delete(DeleteApplicationRequest.builder()
|
||||
.deleteRoutes(defaultDeploymentProperties.isDeleteRoutes())
|
||||
.name(name)
|
||||
.build());
|
||||
}
|
||||
|
||||
private DefaultApplications createSpaceApplications(String space) {
|
||||
return new DefaultApplications(
|
||||
((DefaultCloudFoundryOperations) this.operations).getCloudFoundryClientPublisher(),
|
||||
((DefaultCloudFoundryOperations) this.operations).getDopplerClientPublisher(),
|
||||
(this.operations).spaces().get(GetSpaceRequest.builder().name(space).build()).map(SpaceDetail::getId));
|
||||
}
|
||||
|
||||
private DefaultSpaces createSpaceOperations() {
|
||||
return new DefaultSpaces(
|
||||
((DefaultCloudFoundryOperations) this.operations).getCloudFoundryClientPublisher() ,
|
||||
getOrganizationIdPublisher(),
|
||||
Mono.just(this.defaultDeploymentProperties.getUsername()));
|
||||
}
|
||||
|
||||
private Map<String, String> getEnvironmentVariables(Map<String, String> environment) {
|
||||
Map<String, String> envVariables = new HashMap<>(getApplicationEnvironment(environment));
|
||||
|
||||
|
||||
@@ -151,6 +151,10 @@ public class CloudFoundryDeploymentProperties {
|
||||
|
||||
private String javaOpts;
|
||||
|
||||
private String defaultOrg;
|
||||
|
||||
private String username;
|
||||
|
||||
public String getBuildpack() {
|
||||
return buildpack;
|
||||
}
|
||||
@@ -302,4 +306,20 @@ public class CloudFoundryDeploymentProperties {
|
||||
public void setJavaOpts(String javaOpts) {
|
||||
this.javaOpts = javaOpts;
|
||||
}
|
||||
|
||||
public String getDefaultOrg() {
|
||||
return defaultOrg;
|
||||
}
|
||||
|
||||
public void setDefaultOrg(String defaultOrg) {
|
||||
this.defaultOrg = defaultOrg;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,4 +83,15 @@ public class DeploymentProperties {
|
||||
* round up. Exactly how this property affects the deployments will vary between implementations.
|
||||
*/
|
||||
public static final String CPU_PROPERTY_KEY = "cpu";
|
||||
|
||||
/**
|
||||
* The deployment property for the host that will be used in the app.
|
||||
*/
|
||||
public static final String HOST_KEY = "host";
|
||||
|
||||
/**
|
||||
* The deployment property for the location where the app will be deployed.
|
||||
* The location will vary between implementations.
|
||||
*/
|
||||
public static final String TARGET_KEY = "target";
|
||||
}
|
||||
|
||||
@@ -16,12 +16,16 @@
|
||||
|
||||
package org.springframework.cloud.appbroker.deployer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class UndeployApplicationRequest {
|
||||
|
||||
private final String name;
|
||||
private final Map<String, String> properties;
|
||||
|
||||
UndeployApplicationRequest(String name) {
|
||||
private UndeployApplicationRequest(String name, Map<String, String> properties) {
|
||||
this.name = name;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public static UndeployApplicationRequestBuilder builder() {
|
||||
@@ -32,9 +36,14 @@ public class UndeployApplicationRequest {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static class UndeployApplicationRequestBuilder {
|
||||
|
||||
private String name;
|
||||
private Map<String, String> properties;
|
||||
|
||||
UndeployApplicationRequestBuilder() {
|
||||
}
|
||||
@@ -44,8 +53,13 @@ public class UndeployApplicationRequest {
|
||||
return this;
|
||||
}
|
||||
|
||||
public UndeployApplicationRequestBuilder properties(Map<String, String> properties) {
|
||||
this.properties = properties;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UndeployApplicationRequest build() {
|
||||
return new UndeployApplicationRequest(name);
|
||||
return new UndeployApplicationRequest(name, properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2016-2018. the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.cloud.appbroker.sample;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.appbroker.sample.fixtures.CloudControllerStubFixture;
|
||||
import org.springframework.cloud.appbroker.sample.fixtures.OpenServiceBrokerApiFixture;
|
||||
import org.springframework.cloud.servicebroker.model.instance.OperationState;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.cloud.appbroker.sample.CreateInstanceWithTargetComponentTest.APP_NAME;
|
||||
|
||||
@TestPropertySource(properties = {
|
||||
"spring.cloud.appbroker.services[0].service-name=example",
|
||||
"spring.cloud.appbroker.services[0].plan-name=standard",
|
||||
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
|
||||
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
|
||||
"spring.cloud.appbroker.services[0].apps[0].target.name=SpacePerServiceInstance"
|
||||
})
|
||||
class CreateInstanceWithTargetComponentTest extends WiremockComponentTest {
|
||||
|
||||
static final String APP_NAME = "app-with-target";
|
||||
|
||||
@Autowired
|
||||
private OpenServiceBrokerApiFixture brokerFixture;
|
||||
|
||||
@Autowired
|
||||
private CloudControllerStubFixture cloudControllerFixture;
|
||||
|
||||
@Test
|
||||
void shouldPushAppWithTargetWhenCreateServiceCalled() {
|
||||
String serviceInstanceId = "instance-id";
|
||||
cloudControllerFixture.stubAppDoesNotExistInSpace(APP_NAME, serviceInstanceId);
|
||||
final String host = APP_NAME + "-" + serviceInstanceId;
|
||||
cloudControllerFixture.stubPushAppWithHost(APP_NAME, host);
|
||||
|
||||
// when a service instance is created
|
||||
given(brokerFixture.serviceInstanceRequest())
|
||||
.when()
|
||||
.put(brokerFixture.createServiceInstanceUrl(), "instance-id")
|
||||
.then()
|
||||
.statusCode(HttpStatus.ACCEPTED.value());
|
||||
|
||||
// when the "last_operation" API is polled
|
||||
given(brokerFixture.serviceInstanceRequest())
|
||||
.when()
|
||||
.get(brokerFixture.getLastInstanceOperationUrl(), "instance-id")
|
||||
.then()
|
||||
.statusCode(HttpStatus.OK.value())
|
||||
.body("state", is(equalTo(OperationState.IN_PROGRESS.toString())));
|
||||
|
||||
String state = brokerFixture.waitForAsyncOperationComplete("instance-id");
|
||||
assertThat(state).isEqualTo(OperationState.SUCCEEDED.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.cloud.appbroker.sample.fixtures;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.MappingBuilder;
|
||||
import com.github.tomakehurst.wiremock.matching.ContentPattern;
|
||||
|
||||
import org.springframework.boot.test.context.TestComponent;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.created;
|
||||
@@ -34,8 +35,10 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
|
||||
|
||||
@TestComponent
|
||||
public class CloudControllerStubFixture extends WiremockStubFixture {
|
||||
|
||||
private static final String TEST_SPACE_GUID = "TEST-SPACE-GUID";
|
||||
private static final String TEST_ORG_GUID = "TEST-ORG-GUID";
|
||||
private static final String TEST_QUOTA_DEFINITION_GUID = "TEST-QUOTA-DEFINITION-GUID";
|
||||
|
||||
public void stubCommonCloudControllerRequests() {
|
||||
stubGetPlatformInfo();
|
||||
@@ -91,9 +94,36 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
|
||||
.withMetadata(optionalStubMapping())
|
||||
.willReturn(ok()
|
||||
.withBody(cc("empty-query-results"))));
|
||||
|
||||
stubFor(get(urlEqualTo("/v2/organizations/" + TEST_ORG_GUID + "/spaces?page=1"))
|
||||
.willReturn(ok()
|
||||
.withBody(cc("list-spaces",
|
||||
replace("@org-guid", TEST_ORG_GUID),
|
||||
replace("@space-guid", TEST_SPACE_GUID)))));
|
||||
|
||||
stubFor(get(urlEqualTo("/v2/organizations/" + TEST_ORG_GUID + "/space_quota_definitions?page=1"))
|
||||
.willReturn(ok()
|
||||
.withBody(cc("list-organizations-quota",
|
||||
replace("@org-guid", TEST_ORG_GUID)))));
|
||||
|
||||
stubFor(get(urlEqualTo("/v2/quota_definitions/" + TEST_QUOTA_DEFINITION_GUID))
|
||||
.willReturn(ok()
|
||||
.withBody(cc("get-organizations-quota",
|
||||
replace("@org-guid", TEST_ORG_GUID)))));
|
||||
}
|
||||
|
||||
public void stubAppDoesNotExist(final String appName) {
|
||||
stubAppDoesNotExistInSpace(appName, TEST_SPACE_GUID);
|
||||
}
|
||||
|
||||
public void stubAppDoesNotExistInSpace(final String appName, final String space) {
|
||||
stubFor(get(urlEqualTo("/v2/spaces/" + space + "/apps?q=name:" + appName + "&page=1"))
|
||||
.willReturn(ok()
|
||||
.withBody(cc("empty-query-results"))));
|
||||
|
||||
stubFor(post(urlPathEqualTo("/v2/spaces"))
|
||||
.willReturn(ok()));
|
||||
|
||||
stubFor(get(urlEqualTo("/v2/spaces/" + TEST_SPACE_GUID + "/apps?q=name:" + appName + "&page=1"))
|
||||
.willReturn(ok()
|
||||
.withBody(cc("empty-query-results"))));
|
||||
@@ -132,7 +162,16 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
|
||||
|
||||
public void stubPushApp(final String appName, ContentPattern<?>... appMetadataPatterns) {
|
||||
stubCreateAppMetadata(appName, appMetadataPatterns);
|
||||
stubMapRouteToApp(appName);
|
||||
stubAppAfterCreation(appName, appName);
|
||||
}
|
||||
|
||||
public void stubPushAppWithHost(final String appName, final String host, ContentPattern<?>... appMetadataPatterns) {
|
||||
stubCreateAppMetadata(appName, appMetadataPatterns);
|
||||
stubAppAfterCreation(appName, host);
|
||||
}
|
||||
|
||||
private void stubAppAfterCreation(String appName, String host) {
|
||||
stubMapRouteToApp(appName, host);
|
||||
stubUploadAppBits(appName);
|
||||
stubInitializeAppState(appName);
|
||||
stubCheckAppState(appName);
|
||||
@@ -140,10 +179,7 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
|
||||
|
||||
public void stubUpdateApp(final String appName, ContentPattern<?>... appMetadataPatterns) {
|
||||
stubUpdateAppMetadata(appName, appMetadataPatterns);
|
||||
stubMapRouteToApp(appName);
|
||||
stubUploadAppBits(appName);
|
||||
stubInitializeAppState(appName);
|
||||
stubCheckAppState(appName);
|
||||
stubAppAfterCreation(appName, appName);
|
||||
}
|
||||
|
||||
private void stubCreateAppMetadata(String appName, ContentPattern<?>... appMetadataPatterns) {
|
||||
@@ -172,17 +208,17 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
|
||||
replace("@guid", appGuid(appName))))));
|
||||
}
|
||||
|
||||
private void stubMapRouteToApp(String appName) {
|
||||
private void stubMapRouteToApp(String appName, String host) {
|
||||
stubFor(get(urlPathEqualTo("/v2/apps/" + appGuid(appName) + "/routes"))
|
||||
.willReturn(ok()
|
||||
.withBody(cc("empty-query-results"))));
|
||||
|
||||
stubFor(get(urlEqualTo("/v2/routes?q=domain_guid:" + TEST_ORG_GUID + "&q=host:" + appName + "&page=1"))
|
||||
stubFor(get(urlEqualTo("/v2/routes?q=domain_guid:" + TEST_ORG_GUID + "&q=host:" + host + "&page=1"))
|
||||
.willReturn(ok()
|
||||
.withBody(cc("empty-query-results"))));
|
||||
|
||||
stubFor(post(urlEqualTo("/v2/routes"))
|
||||
.withRequestBody(matchingJsonPath("$.[?(@.host == '" + appName + "')]"))
|
||||
.withRequestBody(matchingJsonPath("$.[?(@.host == '" + host + "')]"))
|
||||
.willReturn(created()
|
||||
.withBody(cc("list-routes",
|
||||
replace("@name", appName),
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"metadata": {
|
||||
"guid": "@org-guid",
|
||||
"url": "/v2/organizations/@org-guid",
|
||||
"created_at": "2018-07-19T20:33:45Z",
|
||||
"updated_at": "2018-07-19T20:33:45Z"
|
||||
},
|
||||
"entity": {
|
||||
"name": "default",
|
||||
"non_basic_services_allowed": true,
|
||||
"total_services": 100,
|
||||
"total_routes": 1000,
|
||||
"total_private_domains": -1,
|
||||
"memory_limit": 10240,
|
||||
"trial_db_allowed": false,
|
||||
"instance_memory_limit": -1,
|
||||
"app_instance_limit": -1,
|
||||
"app_task_limit": -1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"total_results": 1,
|
||||
"total_pages": 1,
|
||||
"prev_url": null,
|
||||
"next_url": null,
|
||||
"resources": [
|
||||
{
|
||||
"metadata": {
|
||||
"guid": "@org-guid",
|
||||
"url": "/v2/organizations/@org-guid",
|
||||
"created_at": "2018-07-19T20:33:45Z",
|
||||
"updated_at": "2018-07-19T20:33:45Z"
|
||||
},
|
||||
"entity": {
|
||||
"organization_guid": "@org-guid",
|
||||
"name": "default",
|
||||
"non_basic_services_allowed": true,
|
||||
"total_services": 100,
|
||||
"total_routes": 1000,
|
||||
"total_private_domains": -1,
|
||||
"memory_limit": 10240,
|
||||
"trial_db_allowed": false,
|
||||
"instance_memory_limit": -1,
|
||||
"app_instance_limit": -1,
|
||||
"app_task_limit": -1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -14,10 +14,10 @@
|
||||
"entity": {
|
||||
"name": "test",
|
||||
"billing_enabled": false,
|
||||
"quota_definition_guid": "7885d305-f247-4d9c-b070-9c65536f09f3",
|
||||
"quota_definition_guid": "TEST-QUOTA-DEFINITION-GUID",
|
||||
"status": "active",
|
||||
"default_isolation_segment_guid": null,
|
||||
"quota_definition_url": "/v2/quota_definitions/7885d305-f247-4d9c-b070-9c65536f09f3",
|
||||
"quota_definition_url": "/v2/quota_definitions/TEST-QUOTA-DEFINITION-GUID",
|
||||
"spaces_url": "/v2/organizations/@org-guid/spaces",
|
||||
"domains_url": "/v2/organizations/@org-guid/domains",
|
||||
"private_domains_url": "/v2/organizations/@org-guid/private_domains",
|
||||
|
||||
Reference in New Issue
Block a user