Enforce Spring formatting and style rules

- Add PMD checks and resolve failing rules
- Apply Spring Checkstyle rules based on Spring Framework
- Rearrange imports to be more consistent
- Format whitespace
This commit is contained in:
Roy Clarkson
2019-11-07 12:25:25 -05:00
committed by Roy Clarkson
parent cd1e1d628f
commit b0c71e52de
219 changed files with 4921 additions and 2810 deletions

View File

@@ -1,7 +1,7 @@
[*]
charset=utf-8
end_of_line=lf
insert_final_newline=false
insert_final_newline=true
indent_style=tab
indent_size=4

View File

@@ -27,12 +27,38 @@ buildscript {
}
}
ext {
springBootVersion = project.findProperty("springBootVersion") ?: "2.1.10.RELEASE"
springFrameworkVersion = project.findProperty("springFrameworkVersion") ?: "5.1.11.RELEASE"
reactorVersion = project.findProperty("reactorVersion") ?: "Californium-SR13"
openServiceBrokerVersion = "3.0.4.RELEASE"
springCredhubVersion = "2.0.1.RELEASE"
cfJavaClientVersion = "3.16.0.RELEASE"
checkstyleVersion = "8.21"
pmdVersion = "6.19.0"
javadocLinks = [
"https://docs.oracle.com/javase/8/docs/api/",
"https://docs.spring.io/spring/docs/${springFrameworkVersion}/javadoc-api/",
] as String[]
}
//override managed Spring Boot versions
if (project.hasProperty("springFrameworkVersion")) {
ext['spring-framework.version'] = ext.springFrameworkVersion
}
if (project.hasProperty("reactorVersion")) {
ext['reactor-bom.version'] = ext.reactorVersion
}
// NoHttp has to be applied at the root level
// so that it reads all the root files, including the gradle ones.
apply plugin: "io.spring.nohttp"
// nohttp requires a valid checkstyle configuration
checkstyle {
toolVersion = 8.16
configFile = file("${project.rootDir}/src/checkstyle/checkstyle-nohttp.xml")
toolVersion = "${checkstyleVersion}"
}
configure(allprojects) {
@@ -49,22 +75,7 @@ configure(allprojects) {
apply plugin: "propdeps-eclipse"
apply plugin: "io.spring.dependency-management"
ext {
springBootVersion = project.findProperty("springBootVersion") ?: "2.1.10.RELEASE"
springVersion = project.findProperty("springFrameworkVersion") ?: "5.1.11.RELEASE"
reactorVersion = project.findProperty("reactorVersion") ?: "Californium-SR13"
openServiceBrokerVersion = "3.0.4.RELEASE"
springCredhubVersion = "2.0.1.RELEASE"
cfJavaClientVersion = "3.16.0.RELEASE"
}
//override managed Spring Boot versions
if (project.hasProperty("springFrameworkVersion")) {
ext['spring-framework.version'] = ext.springFrameworkVersion
}
if (project.hasProperty("reactorVersion")) {
ext['reactor-bom.version'] = ext.reactorVersion
}
apply from: "${rootProject.projectDir}/publish-maven.gradle"
repositories {
mavenCentral()
@@ -80,51 +91,36 @@ configure(allprojects) {
maven { url "https://repo.spring.io/libs-snapshot" }
}
}
ext.javadocLinks = [
"https://docs.oracle.com/javase/8/docs/api/",
"https://docs.spring.io/spring/docs/${springFrameworkVersion}/javadoc-api/",
] as String[]
}
subprojects {
apply from: "${rootProject.projectDir}/publish-maven.gradle"
}
configure(allprojects - [project(":spring-cloud-app-broker-docs")]) {
apply plugin: "checkstyle"
apply plugin: "pmd"
configure(subprojects - [project(":spring-cloud-starter-app-broker"),
project(":spring-cloud-starter-app-broker-cloudfoundry")]) {
compileJava {
sourceCompatibility=1.8
targetCompatibility=1.8
options.encoding = "UTF-8"
checkstyle {
configFile = file("${project.rootDir}/src/checkstyle/checkstyle.xml")
toolVersion = "${checkstyleVersion}"
}
compileTestJava {
sourceCompatibility=1.8
targetCompatibility=1.8
options.encoding = "UTF-8"
checkstyleMain {
source = "src/main/java"
}
checkstyleTest {
source = "src/test/java"
}
[compileJava, compileTestJava]*.options*.compilerArgs = [
"-Xlint:serial",
"-Xlint:varargs",
"-Xlint:cast",
"-Xlint:classfile",
"-Xlint:dep-ann",
"-Xlint:divzero",
"-Xlint:empty",
"-Xlint:finally",
"-Xlint:overrides",
"-Xlint:path",
"-Xlint:-processing",
"-Xlint:static",
"-Xlint:try",
"-Xlint:fallthrough",
"-Xlint:rawtypes",
"-Xlint:deprecation",
"-Xlint:unchecked",
"-Xlint:-options",
"-Werror"
]
pmd {
toolVersion = "${pmdVersion}"
}
pmdMain {
ruleSets = []
ruleSetFiles = files("${project.rootDir}/src/pmd/pmdRuleSet.xml")
source = "src/main/java"
}
pmdTest {
ruleSets = []
ruleSetFiles = files("${project.rootDir}/src/pmd/pmdTestRuleSet.xml")
source = "src/test/java"
}
test {
// enable JUnit 5
@@ -160,21 +156,41 @@ configure(subprojects - [project(":spring-cloud-starter-app-broker"),
afterSuite {
failedTests.each { test -> println "FAILED test: ${test.className} > ${test.name}" }
}
}
}
pmd {
ruleSetFiles = files("${project.rootDir}/ci/config/pmdRuleSet.xml")
}
subprojects {
task allDependencyInsight(type: DependencyInsightReportTask)
task dependencyReport(type: DependencyReportTask)
}
pmdTest {
ruleSetFiles = files("${project.rootDir}/ci/config/pmdTestRuleSet.xml")
}
configure(subprojects - [project(":spring-cloud-starter-app-broker"),
project(":spring-cloud-starter-app-broker-cloudfoundry")]) {
sourceCompatibility = 1.8
targetCompatibility = 1.8
[compileJava, compileTestJava]*.options*.encoding = "UTF-8"
checkstyle {
configDir = file("${project.rootDir}/ci/config/")
toolVersion = 8.16
}
[compileJava, compileTestJava]*.options*.compilerArgs = [
"-Xlint:serial",
"-Xlint:varargs",
"-Xlint:cast",
"-Xlint:classfile",
"-Xlint:dep-ann",
"-Xlint:divzero",
"-Xlint:empty",
"-Xlint:finally",
"-Xlint:overrides",
"-Xlint:path",
"-Xlint:-processing",
"-Xlint:static",
"-Xlint:try",
"-Xlint:fallthrough",
"-Xlint:rawtypes",
"-Xlint:deprecation",
"-Xlint:unchecked",
"-Xlint:-options",
"-Werror"
]
jar {
manifest.attributes["Created-By"] =
@@ -196,7 +212,7 @@ configure(subprojects - [project(":spring-cloud-starter-app-broker"),
options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
options.author = true
options.header = project.name
options.links(project.ext.javadocLinks)
options.links(javadocLinks)
options.addStringOption('Xdoclint:none', '-quiet')
}
@@ -220,9 +236,6 @@ configure(subprojects - [project(":spring-cloud-starter-app-broker"),
// exclude JUnit 4 globally, in favor of JUnit 5
testImplementation.exclude group: "junit", module: "junit"
}
task allDependencyInsight(type: DependencyInsightReportTask) {}
task allDependencies(type: DependencyReportTask) {}
}
configure(rootProject) {
@@ -242,7 +255,7 @@ configure(rootProject) {
options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
options.author = true
options.header = rootProject.description
options.links(project.ext.javadocLinks)
options.links(javadocLinks)
options.addStringOption('Xdoclint:none', '-quiet')
source subprojects.collect { project ->

View File

@@ -1,49 +0,0 @@
<?xml version="1.0"?>
<ruleset name="Custom ruleset"
xmlns="https://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<rule ref="rulesets/java/basic.xml"/>
<rule ref="rulesets/java/braces.xml"/>
<rule ref="rulesets/java/codesize.xml">
<exclude name="TooManyMethods"/>
</rule>
<rule ref="rulesets/java/design.xml">
<exclude name="UseUtilityClass"/>
<exclude name="AccessorMethodGeneration"/>
<exclude name="UncommentedEmptyConstructor"/>
<exclude name="UncommentedEmptyMethodBody"/>
</rule>
<rule ref="rulesets/java/empty.xml"/>
<rule ref="rulesets/java/finalizers.xml"/>
<rule ref="rulesets/java/naming.xml">
<exclude name="ShortVariable" />
<exclude name="LongVariable" />
<exclude name="ShortMethodName" />
<exclude name="ShortClassName" />
<exclude name="AbstractNaming" />
<exclude name="AvoidFieldNameMatchingMethodName" />
</rule>
<rule ref="rulesets/java/imports.xml"/>
<rule ref="rulesets/java/imports.xml/TooManyStaticImports">
<properties>
<property name="maximumStaticImports" value="0"/>
</properties>
</rule>
<rule ref="rulesets/java/optimizations.xml">
<exclude name="LocalVariableCouldBeFinal"/>
<exclude name="MethodArgumentCouldBeFinal"/>
</rule>
<rule ref="rulesets/java/strictexception.xml"/>
<rule ref="rulesets/java/strings.xml"/>
<rule ref="rulesets/java/typeresolution.xml"/>
<rule ref="rulesets/java/unnecessary.xml"/>
<rule ref="rulesets/java/unusedcode.xml" />
<!--
<rule ref="rulesets/java/comments.xml"/>
<rule ref="rulesets/java/controversial.xml"/>
<rule ref="rulesets/java/junit.xml" />
-->
</ruleset>

View File

@@ -1,76 +0,0 @@
<?xml version="1.0"?>
<!--
~ Copyright 2002-2019 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
~
~ https://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.
-->
<ruleset name="Custom ruleset"
xmlns="https://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<rule ref="rulesets/java/basic.xml"/>
<rule ref="rulesets/java/braces.xml">
<exclude name="IfStmtsMustUseBraces"/>
</rule>
<rule ref="rulesets/java/codesize.xml">
<exclude name="TooManyMethods"/>
</rule>
<rule ref="rulesets/java/design.xml">
<exclude name="UncommentedEmptyMethodBody"/>
<exclude name="AbstractClassWithoutAbstractMethod"/>
<exclude name="NonStaticInitializer"/>
</rule>
<rule ref="rulesets/java/design.xml">
<exclude name="AbstractClassWithoutAbstractMethod"/>
<exclude name="NonStaticInitializer"/>
<exclude name="UncommentedEmptyConstructor"/>
<exclude name="UncommentedEmptyMethodBody"/>
</rule>
<rule ref="rulesets/java/empty.xml" />
<rule ref="rulesets/java/finalizers.xml" />
<rule ref="rulesets/java/imports.xml">
<exclude name="TooManyStaticImports"/>
</rule>
<rule ref="rulesets/java/junit.xml">
<exclude name="JUnitTestContainsTooManyAsserts"/>
</rule>
<rule ref="rulesets/java/naming.xml">
<exclude name="LongVariable" />
<exclude name="ShortVariable" />
<exclude name="ShortMethodName" />
<exclude name="AbstractNaming"/>
</rule>
<rule ref="rulesets/java/optimizations.xml">
<exclude name="LocalVariableCouldBeFinal"/>
<exclude name="MethodArgumentCouldBeFinal"/>
</rule>
<rule ref="rulesets/java/strictexception.xml">
<exclude name="AvoidThrowingRawExceptionTypes"/>
<exclude name="SignatureDeclareThrowsException"/>
</rule>
<rule ref="rulesets/java/strings.xml">
<exclude name="AvoidDuplicateLiterals"/>
</rule>
<rule ref="rulesets/java/typeresolution.xml">
<exclude name="SignatureDeclareThrowsException"/>
</rule>
<rule ref="rulesets/java/unnecessary.xml" />
<rule ref="rulesets/java/unusedcode.xml" />
<!--
<rule ref="rulesets/java/comments.xml"/>
<rule ref="rulesets/java/controversial.xml"/>
-->
</ruleset>

View File

@@ -18,11 +18,69 @@ package org.springframework.cloud.appbroker.acceptance;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.appbroker.acceptance.services.NoOpCreateServiceInstanceWorkflow;
import org.springframework.cloud.appbroker.acceptance.services.NoOpDeleteServiceInstanceWorkflow;
import org.springframework.cloud.appbroker.acceptance.services.NoOpServiceInstanceBindingService;
import org.springframework.cloud.appbroker.acceptance.services.NoOpUpdateServiceInstanceWorkflow;
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.servicebroker.service.ServiceInstanceBindingService;
import org.springframework.context.annotation.Bean;
/**
* A Spring Boot application for running acceptance tests
*/
@SpringBootApplication
public class AppBrokerApplication {
/**
* main application entry point
*
* @param args the args
*/
public static void main(String[] args) {
SpringApplication.run(AppBrokerApplication.class, args);
}
/**
* A no-op CreateServiceInstanceWorkflow bean
*
* @return the bean
*/
@Bean
public CreateServiceInstanceWorkflow createServiceInstanceWorkflow() {
return new NoOpCreateServiceInstanceWorkflow();
}
/**
* A no-op UpdateServiceInstanceWorkflow bean
*
* @return the bean
*/
@Bean
public UpdateServiceInstanceWorkflow updateServiceInstanceWorkflow() {
return new NoOpUpdateServiceInstanceWorkflow();
}
/**
* A no-op DeleteServiceInstanceWorkflow bean
*
* @return the bean
*/
@Bean
public DeleteServiceInstanceWorkflow deleteServiceInstanceWorkflow() {
return new NoOpDeleteServiceInstanceWorkflow();
}
/**
* A no-op ServiceInstanceBindingService bean
*
* @return the bean
*/
@Bean
public ServiceInstanceBindingService serviceInstanceBindingService() {
return new NoOpServiceInstanceBindingService();
}
}

View File

@@ -23,36 +23,69 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* A controller for testing the {@link BackingAppManagementService}
*/
@RestController
public class ManagementController {
private final BackingAppManagementService service;
/**
* Construct a new {@literal ManagementController}
*
* @param service the service to test
*/
public ManagementController(BackingAppManagementService service) {
this.service = service;
}
/**
* Tests service start
*
* @param serviceInstanceId the id of the service to test
* @return a response
*/
@GetMapping("/start/{serviceInstanceId}")
public Mono<String> startApplications(@PathVariable String serviceInstanceId) {
return service.start(serviceInstanceId)
.thenReturn("starting " + serviceInstanceId);
}
/**
* Tests service stop
*
* @param serviceInstanceId the id of the service to test
* @return a response
*/
@GetMapping("/stop/{serviceInstanceId}")
public Mono<String> stopApplications(@PathVariable String serviceInstanceId) {
return service.stop(serviceInstanceId)
.thenReturn("stopping " + serviceInstanceId);
}
/**
* Tests service restart
*
* @param serviceInstanceId the id of the service to test
* @return a response
*/
@GetMapping("/restart/{serviceInstanceId}")
public Mono<String> restartApplications(@PathVariable String serviceInstanceId) {
return service.restart(serviceInstanceId)
.thenReturn("restarting " + serviceInstanceId);
}
/**
* Tests service restage
*
* @param serviceInstanceId the id of the service to test
* @return a response
*/
@GetMapping("/restage/{serviceInstanceId}")
public Mono<String> restageApplications(@PathVariable String serviceInstanceId) {
return service.restage(serviceInstanceId)
.thenReturn("restaging " + serviceInstanceId);
}
}

View File

@@ -18,17 +18,20 @@ package org.springframework.cloud.appbroker.acceptance.services;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse.CreateServiceInstanceResponseBuilder;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
/**
* A no-op implementation of {@link CreateServiceInstanceWorkflow}
*/
public class NoOpCreateServiceInstanceWorkflow implements CreateServiceInstanceWorkflow {
private static final Logger LOGGER = LoggerFactory.getLogger(NoOpCreateServiceInstanceWorkflow.class);
private static final Logger LOG = LoggerFactory.getLogger(NoOpCreateServiceInstanceWorkflow.class);
@Value("${spring.cloud.openservicebroker.catalog.services[1].id}")
private String backingServiceId;
@@ -40,14 +43,19 @@ public class NoOpCreateServiceInstanceWorkflow implements CreateServiceInstanceW
@Override
public Mono<Boolean> accept(CreateServiceInstanceRequest request) {
LOGGER.info("Got request to create service instance: " + request);
if (LOG.isInfoEnabled()) {
LOG.info("Got request to create service instance: " + request);
}
return Mono.just(request.getServiceDefinitionId().equals(backingServiceId));
}
@Override
public Mono<CreateServiceInstanceResponseBuilder> buildResponse(CreateServiceInstanceRequest request,
CreateServiceInstanceResponseBuilder responseBuilder) {
LOGGER.info("Got request to create service instance: " + request);
CreateServiceInstanceResponseBuilder responseBuilder) {
if (LOG.isInfoEnabled()) {
LOG.info("Got request to create service instance: " + request);
}
return Mono.just(responseBuilder);
}
}

View File

@@ -16,16 +16,19 @@
package org.springframework.cloud.appbroker.acceptance.services;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.appbroker.service.DeleteServiceInstanceWorkflow;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse.DeleteServiceInstanceResponseBuilder;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
/**
* A no-op implementation of {@link DeleteServiceInstanceWorkflow}
*/
public class NoOpDeleteServiceInstanceWorkflow implements DeleteServiceInstanceWorkflow {
@Value("${spring.cloud.openservicebroker.catalog.services[1].id}")
private String backingServiceId;
@@ -41,7 +44,8 @@ public class NoOpDeleteServiceInstanceWorkflow implements DeleteServiceInstanceW
@Override
public Mono<DeleteServiceInstanceResponseBuilder> buildResponse(DeleteServiceInstanceRequest request,
DeleteServiceInstanceResponseBuilder responseBuilder) {
DeleteServiceInstanceResponseBuilder responseBuilder) {
return Mono.just(responseBuilder);
}
}

View File

@@ -16,24 +16,30 @@
package org.springframework.cloud.appbroker.acceptance.services;
import reactor.core.publisher.Mono;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.service.ServiceInstanceBindingService;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
/**
* A no-op implementation of {@link ServiceInstanceBindingService}
*/
public class NoOpServiceInstanceBindingService implements ServiceInstanceBindingService {
@Override
public Mono<CreateServiceInstanceBindingResponse> createServiceInstanceBinding(CreateServiceInstanceBindingRequest request) {
public Mono<CreateServiceInstanceBindingResponse> createServiceInstanceBinding(
CreateServiceInstanceBindingRequest request) {
return Mono.just(CreateServiceInstanceAppBindingResponse.builder().build());
}
@Override
public Mono<DeleteServiceInstanceBindingResponse> deleteServiceInstanceBinding(DeleteServiceInstanceBindingRequest request) {
public Mono<DeleteServiceInstanceBindingResponse> deleteServiceInstanceBinding(
DeleteServiceInstanceBindingRequest request) {
return Mono.just(DeleteServiceInstanceBindingResponse.builder().build());
}
}

View File

@@ -16,16 +16,19 @@
package org.springframework.cloud.appbroker.acceptance.services;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.appbroker.service.UpdateServiceInstanceWorkflow;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse.UpdateServiceInstanceResponseBuilder;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
/**
* A no-op implementation of {@link UpdateServiceInstanceWorkflow}
*/
public class NoOpUpdateServiceInstanceWorkflow implements UpdateServiceInstanceWorkflow {
@Value("${spring.cloud.openservicebroker.catalog.services[1].id}")
private String backingServiceId;
@@ -41,7 +44,8 @@ public class NoOpUpdateServiceInstanceWorkflow implements UpdateServiceInstanceW
@Override
public Mono<UpdateServiceInstanceResponseBuilder> buildResponse(UpdateServiceInstanceRequest request,
UpdateServiceInstanceResponseBuilder responseBuilder) {
UpdateServiceInstanceResponseBuilder responseBuilder) {
return Mono.just(responseBuilder);
}
}

View File

@@ -18,7 +18,7 @@ package org.springframework.cloud.appbroker.acceptance;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(value = "tests")
@ConfigurationProperties("tests")
public class AcceptanceTestProperties {
private String brokerAppPath;

View File

@@ -32,11 +32,14 @@ class AppManagementRestageAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String SUFFIX = "app-management-restage";
private static final String APP_1 = "app-1-" + SUFFIX;
private static final String APP_2 = "app-2" + SUFFIX;
private static final String SI_NAME = "si-managed" + SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -56,23 +59,23 @@ class AppManagementRestageAcceptanceTest extends CloudFoundryAcceptanceTest {
@BeforeEach
void setUp() {
StepVerifier.create(cloudFoundryService.deleteServiceInstance(SI_NAME))
.verifyComplete();
.verifyComplete();
StepVerifier.create(cloudFoundryService.createServiceInstance(PLAN_NAME, APP_SERVICE_NAME, SI_NAME, null))
.verifyComplete();
.verifyComplete();
StepVerifier.create(cloudFoundryService.getServiceInstance(SI_NAME))
.assertNext(serviceInstance -> assertThat(serviceInstance.getStatus()).isEqualTo("succeeded"))
.verifyComplete();
.assertNext(serviceInstance -> assertThat(serviceInstance.getStatus()).isEqualTo("succeeded"))
.verifyComplete();
}
@AfterEach
void cleanUp() {
StepVerifier.create(cloudFoundryService.deleteServiceInstance(SI_NAME))
.verifyComplete();
.verifyComplete();
StepVerifier.create(getApplications(APP_1, APP_2))
.verifyError();
.verifyError();
}
@Test
@@ -91,8 +94,8 @@ class AppManagementRestageAcceptanceTest extends CloudFoundryAcceptanceTest {
assertThat(apps).extracting("runningInstances").containsOnly(1);
StepVerifier.create(manageApps(SI_NAME, "restage"))
.assertNext(result -> assertThat(result).contains("restaging"))
.verifyComplete();
.assertNext(result -> assertThat(result).contains("restaging"))
.verifyComplete();
List<ApplicationDetail> restagedApps = getApplications(APP_1, APP_2).block();
Date since1 = restagedApps.get(0).getInstanceDetails().get(0).getSince();
@@ -102,4 +105,4 @@ class AppManagementRestageAcceptanceTest extends CloudFoundryAcceptanceTest {
assertThat(since2).isAfter(originallySince2);
}
}
}

View File

@@ -32,11 +32,14 @@ class AppManagementRestartAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String SUFFIX = "app-management-restart";
private static final String APP_1 = "app-1-" + SUFFIX;
private static final String APP_2 = "app-2" + SUFFIX;
private static final String SI_NAME = "si-managed" + SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -56,23 +59,23 @@ class AppManagementRestartAcceptanceTest extends CloudFoundryAcceptanceTest {
@BeforeEach
void setUp() {
StepVerifier.create(cloudFoundryService.deleteServiceInstance(SI_NAME))
.verifyComplete();
.verifyComplete();
StepVerifier.create(cloudFoundryService.createServiceInstance(PLAN_NAME, APP_SERVICE_NAME, SI_NAME, null))
.verifyComplete();
.verifyComplete();
StepVerifier.create(cloudFoundryService.getServiceInstance(SI_NAME))
.assertNext(serviceInstance -> assertThat(serviceInstance.getStatus()).isEqualTo("succeeded"))
.verifyComplete();
.assertNext(serviceInstance -> assertThat(serviceInstance.getStatus()).isEqualTo("succeeded"))
.verifyComplete();
}
@AfterEach
void cleanUp() {
StepVerifier.create(cloudFoundryService.deleteServiceInstance(SI_NAME))
.verifyComplete();
.verifyComplete();
StepVerifier.create(getApplications(APP_1, APP_2))
.verifyError();
.verifyError();
}
@Test
@@ -90,8 +93,8 @@ class AppManagementRestartAcceptanceTest extends CloudFoundryAcceptanceTest {
Date originallySince2 = apps.get(1).getInstanceDetails().get(0).getSince();
StepVerifier.create(manageApps(SI_NAME, "restart"))
.assertNext(result -> assertThat(result).contains("restarting"))
.verifyComplete();
.assertNext(result -> assertThat(result).contains("restarting"))
.verifyComplete();
List<ApplicationDetail> restagedApps = getApplications(APP_1, APP_2).block();
Date since1 = restagedApps.get(0).getInstanceDetails().get(0).getSince();
@@ -101,4 +104,4 @@ class AppManagementRestartAcceptanceTest extends CloudFoundryAcceptanceTest {
assertThat(since2).isAfter(originallySince2);
}
}
}

View File

@@ -28,11 +28,14 @@ class AppManagementStartAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String SUFFIX = "app-management-start";
private static final String APP_1 = "app-1-" + SUFFIX;
private static final String APP_2 = "app-2" + SUFFIX;
private static final String SI_NAME = "si-managed" + SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -52,23 +55,23 @@ class AppManagementStartAcceptanceTest extends CloudFoundryAcceptanceTest {
@BeforeEach
void setUp() {
StepVerifier.create(cloudFoundryService.deleteServiceInstance(SI_NAME))
.verifyComplete();
.verifyComplete();
StepVerifier.create(cloudFoundryService.createServiceInstance(PLAN_NAME, APP_SERVICE_NAME, SI_NAME, null))
.verifyComplete();
.verifyComplete();
StepVerifier.create(cloudFoundryService.getServiceInstance(SI_NAME))
.assertNext(serviceInstance -> assertThat(serviceInstance.getStatus()).isEqualTo("succeeded"))
.verifyComplete();
.assertNext(serviceInstance -> assertThat(serviceInstance.getStatus()).isEqualTo("succeeded"))
.verifyComplete();
}
@AfterEach
void cleanUp() {
StepVerifier.create(cloudFoundryService.deleteServiceInstance(SI_NAME))
.verifyComplete();
.verifyComplete();
StepVerifier.create(getApplications(APP_1, APP_2))
.verifyError();
.verifyError();
}
@Test
@@ -82,19 +85,20 @@ class AppManagementStartAcceptanceTest extends CloudFoundryAcceptanceTest {
})
void startApps() {
StepVerifier.create(cloudFoundryService.stopApplication(APP_1)
.then(cloudFoundryService.stopApplication(APP_2)))
.verifyComplete();
.then(cloudFoundryService.stopApplication(APP_2)))
.verifyComplete();
StepVerifier.create(getApplications(APP_1, APP_2))
.assertNext(apps -> assertThat(apps).extracting("runningInstances").containsOnly(0))
.verifyComplete();
.assertNext(apps -> assertThat(apps).extracting("runningInstances").containsOnly(0))
.verifyComplete();
StepVerifier.create(manageApps(SI_NAME, "start"))
.assertNext(result -> assertThat(result).contains("starting"))
.verifyComplete();
.assertNext(result -> assertThat(result).contains("starting"))
.verifyComplete();
StepVerifier.create(getApplications(APP_1, APP_2))
.assertNext(apps -> assertThat(apps).extracting("runningInstances").containsOnly(1))
.verifyComplete();
.assertNext(apps -> assertThat(apps).extracting("runningInstances").containsOnly(1))
.verifyComplete();
}
}
}

View File

@@ -28,11 +28,14 @@ class AppManagementStopAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String SUFFIX = "app-management-stop";
private static final String APP_1 = "app-1-" + SUFFIX;
private static final String APP_2 = "app-2" + SUFFIX;
private static final String SI_NAME = "si-managed" + SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -52,23 +55,23 @@ class AppManagementStopAcceptanceTest extends CloudFoundryAcceptanceTest {
@BeforeEach
void setUp() {
StepVerifier.create(cloudFoundryService.deleteServiceInstance(SI_NAME))
.verifyComplete();
.verifyComplete();
StepVerifier.create(cloudFoundryService.createServiceInstance(PLAN_NAME, APP_SERVICE_NAME, SI_NAME, null))
.verifyComplete();
.verifyComplete();
StepVerifier.create(cloudFoundryService.getServiceInstance(SI_NAME))
.assertNext(serviceInstance -> assertThat(serviceInstance.getStatus()).isEqualTo("succeeded"))
.verifyComplete();
.assertNext(serviceInstance -> assertThat(serviceInstance.getStatus()).isEqualTo("succeeded"))
.verifyComplete();
}
@AfterEach
void cleanUp() {
StepVerifier.create(cloudFoundryService.deleteServiceInstance(SI_NAME))
.verifyComplete();
.verifyComplete();
StepVerifier.create(getApplications(APP_1, APP_2))
.verifyError();
.verifyError();
}
@Test
@@ -82,11 +85,12 @@ class AppManagementStopAcceptanceTest extends CloudFoundryAcceptanceTest {
})
void stopApps() {
StepVerifier.create(manageApps(SI_NAME, "stop"))
.assertNext(result -> assertThat(result).contains("stopping"))
.verifyComplete();
.assertNext(result -> assertThat(result).contains("stopping"))
.verifyComplete();
StepVerifier.create(getApplications(APP_1, APP_2))
.assertNext(apps -> assertThat(apps).extracting("runningInstances").containsOnly(0))
.verifyComplete();
.assertNext(apps -> assertThat(apps).extracting("runningInstances").containsOnly(0))
.verifyComplete();
}
}
}

View File

@@ -16,15 +16,27 @@
package org.springframework.cloud.appbroker.acceptance;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.util.CollectionUtils;
class BrokerProperties {
private final String[] properties;
private final List<String> properties = new ArrayList<>();
BrokerProperties(String... properties) {
this.properties = properties;
public BrokerProperties(List<String> properties) {
if (!CollectionUtils.isEmpty(properties)) {
this.properties.addAll(properties);
}
}
String[] getProperties() {
public BrokerProperties(String... properties) {
this(Arrays.asList(properties));
}
public List<String> getProperties() {
return properties;
}

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.appbroker.acceptance;
import java.lang.reflect.Method;
import java.util.Optional;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
@@ -25,13 +26,17 @@ import org.junit.jupiter.api.extension.ParameterResolver;
class BrokerPropertiesParameterResolver implements ParameterResolver {
@SuppressWarnings("PMD.AvoidUncheckedExceptionsInSignatures")
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return parameterContext.getParameter().getType() == BrokerProperties.class;
}
@SuppressWarnings("PMD.AvoidUncheckedExceptionsInSignatures")
@Override
public BrokerProperties resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
public BrokerProperties resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
String[] properties = getValueHolderProperties(extensionContext);
return new BrokerProperties(properties);
}
@@ -40,7 +45,7 @@ class BrokerPropertiesParameterResolver implements ParameterResolver {
Optional<Method> testInstance = extensionContext.getTestMethod();
return testInstance
.map(method -> method.getAnnotation(AppBrokerTestProperties.class).value())
.orElseGet(() -> new String[]{});
.orElseGet(() -> new String[] {});
}
}
}

View File

@@ -16,10 +16,11 @@
package org.springframework.cloud.appbroker.acceptance;
import javax.net.ssl.SSLException;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
@@ -29,6 +30,8 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import javax.net.ssl.SSLException;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
@@ -39,7 +42,6 @@ import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.mapper.MappingProvider;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import org.apache.commons.lang3.ArrayUtils;
import org.cloudfoundry.operations.applications.ApplicationDetail;
import org.cloudfoundry.operations.applications.ApplicationEnvironments;
import org.cloudfoundry.operations.applications.ApplicationSummary;
@@ -50,6 +52,8 @@ import org.cloudfoundry.uaa.clients.GetClientResponse;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
@@ -83,8 +87,11 @@ import static org.springframework.cloud.appbroker.acceptance.fixtures.cf.CloudFo
@EnableConfigurationProperties(AcceptanceTestProperties.class)
abstract class CloudFoundryAcceptanceTest {
static final String PLAN_NAME = "standard";
static final String BACKING_APP_PATH = "classpath:backing-app.jar";
private static final Logger LOG = LoggerFactory.getLogger(CloudFoundryAcceptanceTest.class);
protected static final String PLAN_NAME = "standard";
protected static final String BACKING_APP_PATH = "classpath:backing-app.jar";
@Autowired
protected CloudFoundryService cloudFoundryService;
@@ -98,12 +105,15 @@ abstract class CloudFoundryAcceptanceTest {
private final WebClient webClient = getSslIgnoringWebClient();
protected abstract String testSuffix();
protected abstract String appServiceName();
protected abstract String backingServiceName();
private String testBrokerAppName() {
return "test-broker-app-" + testSuffix();
}
private String serviceBrokerName() {
return "test-broker-" + testSuffix();
}
@@ -119,12 +129,11 @@ abstract class CloudFoundryAcceptanceTest {
"spring.cloud.openservicebroker.catalog.services[0].name=" + appServiceName(),
"spring.cloud.openservicebroker.catalog.services[0].description=A service that deploys a backing app",
"spring.cloud.openservicebroker.catalog.services[0].bindable=true",
"spring.cloud.openservicebroker.catalog.services[0].plans[0].id=" + UUID.randomUUID().toString() ,
"spring.cloud.openservicebroker.catalog.services[0].plans[0].id=" + UUID.randomUUID().toString(),
"spring.cloud.openservicebroker.catalog.services[0].plans[0].name=standard",
"spring.cloud.openservicebroker.catalog.services[0].plans[0].bindable=true",
"spring.cloud.openservicebroker.catalog.services[0].plans[0].description=A simple plan",
"spring.cloud.openservicebroker.catalog.services[0].plans[0].free=true",
"spring.cloud.openservicebroker.catalog.services[1].id=" + UUID.randomUUID().toString(),
"spring.cloud.openservicebroker.catalog.services[1].name=" + backingServiceName(),
"spring.cloud.openservicebroker.catalog.services[1].description=A backing service that can be bound to backing apps",
@@ -136,9 +145,9 @@ abstract class CloudFoundryAcceptanceTest {
"spring.cloud.openservicebroker.catalog.services[1].plans[0].free=true"
};
String[] appBrokerProperties = ArrayUtils.addAll(
openServiceBrokerProperties,
brokerProperties.getProperties());
List<String> appBrokerProperties = new ArrayList<>();
appBrokerProperties.addAll(Arrays.asList(openServiceBrokerProperties));
appBrokerProperties.addAll(brokerProperties.getProperties());
blockingSubscribe(initializeBroker(appBrokerProperties));
}
@@ -147,6 +156,7 @@ abstract class CloudFoundryAcceptanceTest {
void configureJsonPath() {
Configuration.setDefaults(new Configuration.Defaults() {
private final JsonProvider jacksonJsonProvider = new JacksonJsonProvider();
private final MappingProvider jacksonMappingProvider = new JacksonMappingProvider();
@Override
@@ -167,7 +177,7 @@ abstract class CloudFoundryAcceptanceTest {
}
@AfterEach
void tearDown() {
public void tearDown() {
blockingSubscribe(cloudFoundryService.getOrCreateDefaultOrganization()
.map(OrganizationSummary::getId)
.flatMap(orgId -> cloudFoundryService.getOrCreateDefaultSpace()
@@ -175,7 +185,7 @@ abstract class CloudFoundryAcceptanceTest {
.flatMap(spaceId -> cleanup(orgId, spaceId))));
}
private Mono<Void> initializeBroker(String... appBrokerProperties) {
private Mono<Void> initializeBroker(List<String> appBrokerProperties) {
return cloudFoundryService
.getOrCreateDefaultOrganization()
.map(OrganizationSummary::getId)
@@ -188,7 +198,9 @@ abstract class CloudFoundryAcceptanceTest {
APP_BROKER_CLIENT_SECRET,
APP_BROKER_CLIENT_AUTHORITIES))
.then(cloudFoundryService.associateAppBrokerClientWithOrgAndSpace(brokerClientId(), orgId, spaceId))
.then(cloudFoundryService.pushBrokerApp(testBrokerAppName(), getTestBrokerAppPath(), brokerClientId(), appBrokerProperties))
.then(cloudFoundryService
.pushBrokerApp(testBrokerAppName(), getTestBrokerAppPath(), brokerClientId(),
appBrokerProperties))
.then(cloudFoundryService.createServiceBroker(serviceBrokerName(), testBrokerAppName()))
.then(cloudFoundryService.enableServiceBrokerAccess(appServiceName()))
.then(cloudFoundryService.enableServiceBrokerAccess(backingServiceName()))));
@@ -201,18 +213,18 @@ abstract class CloudFoundryAcceptanceTest {
.onErrorResume(e -> Mono.empty());
}
void createServiceInstance(String serviceInstanceName) {
protected void createServiceInstance(String serviceInstanceName) {
createServiceInstance(serviceInstanceName, Collections.emptyMap());
}
void createServiceInstance(String serviceInstanceName, Map<String, Object> parameters) {
protected void createServiceInstance(String serviceInstanceName, Map<String, Object> parameters) {
createServiceInstance(appServiceName(), PLAN_NAME, serviceInstanceName, parameters);
}
void createServiceInstance(String serviceName,
String planName,
String serviceInstanceName,
Map<String, Object> parameters) {
protected void createServiceInstance(String serviceName,
String planName,
String serviceInstanceName,
Map<String, Object> parameters) {
cloudFoundryService.createServiceInstance(planName, serviceName, serviceInstanceName, parameters)
.then(getServiceInstanceMono(serviceInstanceName))
.flatMap(serviceInstance -> {
@@ -224,7 +236,7 @@ abstract class CloudFoundryAcceptanceTest {
.block();
}
void updateServiceInstance(String serviceInstanceName, Map<String, Object> parameters) {
protected void updateServiceInstance(String serviceInstanceName, Map<String, Object> parameters) {
cloudFoundryService.updateServiceInstance(serviceInstanceName, parameters)
.then(getServiceInstanceMono(serviceInstanceName))
.flatMap(serviceInstance -> {
@@ -236,19 +248,19 @@ abstract class CloudFoundryAcceptanceTest {
.block();
}
void deleteServiceInstance(String serviceInstanceName) {
protected void deleteServiceInstance(String serviceInstanceName) {
blockingSubscribe(cloudFoundryService.deleteServiceInstance(serviceInstanceName));
}
ServiceInstance getServiceInstance(String serviceInstanceName) {
protected ServiceInstance getServiceInstance(String serviceInstanceName) {
return getServiceInstanceMono(serviceInstanceName).block();
}
ServiceInstance getServiceInstance(String serviceInstanceName, String space) {
protected ServiceInstance getServiceInstance(String serviceInstanceName, String space) {
return cloudFoundryService.getServiceInstance(serviceInstanceName, space).block();
}
String getServiceInstanceGuid(String serviceInstanceName) {
protected String getServiceInstanceGuid(String serviceInstanceName) {
return getServiceInstanceMono(serviceInstanceName)
.map(ServiceInstance::getId)
.block();
@@ -258,7 +270,7 @@ abstract class CloudFoundryAcceptanceTest {
return cloudFoundryService.getServiceInstance(serviceInstanceName);
}
Optional<ApplicationSummary> getApplicationSummary(String appName) {
protected Optional<ApplicationSummary> getApplicationSummary(String appName) {
return cloudFoundryService
.getApplications()
.flatMapMany(Flux::fromIterable)
@@ -267,44 +279,44 @@ abstract class CloudFoundryAcceptanceTest {
.blockOptional();
}
Optional<ApplicationSummary> getApplicationSummary(String appName, String space) {
protected Optional<ApplicationSummary> getApplicationSummary(String appName, String space) {
return cloudFoundryService.getApplication(appName, space).blockOptional();
}
ApplicationEnvironments getApplicationEnvironment(String appName) {
private ApplicationEnvironments getApplicationEnvironment(String appName) {
return cloudFoundryService.getApplicationEnvironment(appName).block();
}
ApplicationEnvironments getApplicationEnvironment(String appName, String space) {
private ApplicationEnvironments getApplicationEnvironment(String appName, String space) {
return cloudFoundryService.getApplicationEnvironment(appName, space).block();
}
DocumentContext getSpringAppJson(String appName) {
protected DocumentContext getSpringAppJson(String appName) {
ApplicationEnvironments env = getApplicationEnvironment(appName);
String saj = (String) env.getUserProvided().get("SPRING_APPLICATION_JSON");
return JsonPath.parse(saj);
}
DocumentContext getSpringAppJson(String appName, String space) {
protected DocumentContext getSpringAppJson(String appName, String space) {
ApplicationEnvironments env = getApplicationEnvironment(appName, space);
String saj = (String) env.getUserProvided().get("SPRING_APPLICATION_JSON");
return JsonPath.parse(saj);
}
List<String> getSpaces() {
protected List<String> getSpaces() {
return cloudFoundryService.getSpaces().block();
}
Optional<GetClientResponse> getUaaClient(String clientId) {
protected Optional<GetClientResponse> getUaaClient(String clientId) {
return uaaService.getUaaClient(clientId)
.blockOptional();
}
void createDomain(String domain) {
protected void createDomain(String domain) {
cloudFoundryService.createDomain(domain).block();
}
void deleteDomain(String domain) {
protected void deleteDomain(String domain) {
cloudFoundryService.deleteDomain(domain).block();
}
@@ -315,7 +327,9 @@ abstract class CloudFoundryAcceptanceTest {
private <T> void blockingSubscribe(Mono<? super T> publisher) {
CountDownLatch latch = new CountDownLatch(1);
publisher.subscribe(System.out::println, t -> {
t.printStackTrace();
if (LOG.isDebugEnabled()) {
LOG.debug("error subscribing to publisher", t);
}
latch.countDown();
}, latch::countDown);
try {
@@ -326,7 +340,7 @@ abstract class CloudFoundryAcceptanceTest {
}
}
Mono<String> manageApps(String serviceInstanceName, String operation) {
protected Mono<String> manageApps(String serviceInstanceName, String operation) {
return cloudFoundryService
.getServiceInstance(serviceInstanceName)
.map(ServiceInstance::getId)
@@ -335,37 +349,39 @@ abstract class CloudFoundryAcceptanceTest {
.getApplicationRoute(testBrokerAppName())
.flatMap(appRoute ->
webClient.get()
.uri(URI.create(appRoute + "/" + operation + "/" + serviceInstanceId))
.exchange()
.flatMap(clientResponse -> clientResponse.toEntity(String.class))
.map(HttpEntity::getBody)));
.uri(URI.create(appRoute + "/" + operation + "/" + serviceInstanceId))
.exchange()
.flatMap(clientResponse -> clientResponse.toEntity(String.class))
.map(HttpEntity::getBody)));
}
private WebClient getSslIgnoringWebClient() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(HttpClient
.create()
.secure(t -> {
try {
t.sslContext(SslContextBuilder
.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build());
}
catch (SSLException e) {
e.printStackTrace();
}
})))
.build();
.clientConnector(new ReactorClientHttpConnector(HttpClient
.create()
.secure(t -> {
try {
t.sslContext(SslContextBuilder
.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build());
}
catch (SSLException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("problem ignoring SSL in WebClient", e);
}
}
})))
.build();
}
protected Mono<List<ApplicationDetail>> getApplications(String app1, String app2) {
return Flux.merge(cloudFoundryService.getApplication(app1),
cloudFoundryService.getApplication(app2))
.parallel()
.runOn(Schedulers.parallel())
.sequential()
.collectList();
.parallel()
.runOn(Schedulers.parallel())
.sequential()
.collectList();
}
}

View File

@@ -27,12 +27,16 @@ import static org.assertj.core.api.Assertions.assertThat;
class CreateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_CREATE_1 = "app-create-1";
private static final String APP_CREATE_2 = "app-create-2";
private static final String SI_NAME = "si-create";
private static final String SUFFIX = "create-instance";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -115,4 +119,5 @@ class CreateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest {
assertThat(json.read("$.['spring.security.user.password']").toString())
.matches("[a-zA-Z]{14}");
}
}
}

View File

@@ -29,11 +29,14 @@ import static org.assertj.core.api.Assertions.assertThat;
class CreateInstanceWithOAuth2CredentialsAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_NAME = "app-create-oauth2";
private static final String SI_NAME = "si-create-oauth2";
private static final String SUFFIX = "create-instance-oauth2";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -57,7 +60,7 @@ class CreateInstanceWithOAuth2CredentialsAcceptanceTest extends CloudFoundryAcce
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].path=" + BACKING_APP_PATH,
"spring.cloud.appbroker.services[0].apps[0].credential-providers[0].name=SpringSecurityOAuth2",
"spring.cloud.appbroker.services[0].apps[0].credential-providers[0].args.registration=sample-app-client",
"spring.cloud.appbroker.services[0].apps[0].credential-providers[0].args.grant-types=[\"client_credentials\"]",
@@ -83,7 +86,8 @@ class CreateInstanceWithOAuth2CredentialsAcceptanceTest extends CloudFoundryAcce
DocumentContext json = getSpringAppJson(APP_NAME);
assertThat(json.read("$.['spring.security.oauth2.client.registration.sample-app-client.client-id']").toString())
.isEqualTo(uaaClientId(serviceInstanceGuid));
assertThat(json.read("$.['spring.security.oauth2.client.registration.sample-app-client.client-secret']").toString())
assertThat(
json.read("$.['spring.security.oauth2.client.registration.sample-app-client.client-secret']").toString())
.matches("[a-zA-Z]{12}");
// and a UAA client is created
@@ -108,4 +112,5 @@ class CreateInstanceWithOAuth2CredentialsAcceptanceTest extends CloudFoundryAcce
private String uaaClientId(String serviceInstanceGuid) {
return APP_NAME + "-" + serviceInstanceGuid;
}
}
}

View File

@@ -29,11 +29,14 @@ import static org.assertj.core.api.Assertions.assertThat;
class CreateInstanceWithParametersAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_NAME = "app-create-params";
private static final String SI_NAME = "si-create-params";
private static final String SUFFIX = "create-instance-with-params";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -54,18 +57,15 @@ class CreateInstanceWithParametersAcceptanceTest extends CloudFoundryAcceptanceT
@AppBrokerTestProperties({
"spring.cloud.appbroker.services[0].service-name=" + APP_SERVICE_NAME,
"spring.cloud.appbroker.services[0].plan-name=" + PLAN_NAME,
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].path=" + BACKING_APP_PATH,
"spring.cloud.appbroker.services[0].apps[0].environment.parameter1=config1",
"spring.cloud.appbroker.services[0].apps[0].environment.parameter2=config2",
"spring.cloud.appbroker.services[0].apps[0].environment.parameter3=config3",
"spring.cloud.appbroker.services[0].apps[0].parameters-transformers[0].name=EnvironmentMapping",
"spring.cloud.appbroker.services[0].apps[0].parameters-transformers[0].args.include=parameter1,parameter3",
"spring.cloud.appbroker.services[0].apps[0].parameters-transformers[1].name=PropertyMapping",
"spring.cloud.appbroker.services[0].apps[0].parameters-transformers[1].args.include=memory",
"spring.cloud.appbroker.services[0].apps[0].parameters-transformers[1].args.include=memory"
})
void deployAppsWithParametersOnCreateService() {
// when a service instance is created
@@ -96,4 +96,4 @@ class CreateInstanceWithParametersAcceptanceTest extends CloudFoundryAcceptanceT
deleteServiceInstance(SI_NAME);
}
}
}

View File

@@ -27,13 +27,16 @@ import static org.assertj.core.api.Assertions.assertThat;
class CreateInstanceWithServiceInstanceGuidSuffixTargetAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String SUFFIX = "create-si-guid";
private static final String APP_NAME_1 = "app-create-" + SUFFIX;
private static final String SI_NAME = "si-create-" + SUFFIX;
private static final String BACKING_SI_NAME = "backing-si";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -54,15 +57,12 @@ class CreateInstanceWithServiceInstanceGuidSuffixTargetAcceptanceTest extends Cl
@AppBrokerTestProperties({
"spring.cloud.appbroker.services[0].service-name=" + APP_SERVICE_NAME,
"spring.cloud.appbroker.services[0].plan-name=" + PLAN_NAME,
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME_1,
"spring.cloud.appbroker.services[0].apps[0].path=" + BACKING_APP_PATH,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=" + PLAN_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].target.name=ServiceInstanceGuidSuffix"
})
void deployAppsWithServiceInstanceGuidSuffixOnCreateService() {
@@ -88,4 +88,5 @@ class CreateInstanceWithServiceInstanceGuidSuffixTargetAcceptanceTest extends Cl
// when the service instance is deleted
deleteServiceInstance(SI_NAME);
}
}
}

View File

@@ -28,14 +28,18 @@ import static org.assertj.core.api.Assertions.assertThat;
class CreateInstanceWithServicesAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_NAME = "app-create-services";
private static final String SI_NAME = "si-create-services";
private static final String BACKING_SI_1_NAME = "backing-service-instance-created";
private static final String BACKING_SI_2_NAME = "backing-service-instance-existing";
private static final String SUFFIX = "create-instance-with-services";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -56,15 +60,13 @@ class CreateInstanceWithServicesAcceptanceTest extends CloudFoundryAcceptanceTes
@AppBrokerTestProperties({
"spring.cloud.appbroker.services[0].service-name=" + APP_SERVICE_NAME,
"spring.cloud.appbroker.services[0].plan-name=" + PLAN_NAME,
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].path=" + BACKING_APP_PATH,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_1_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[1].service-instance-name=" + BACKING_SI_2_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=" + PLAN_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_1_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_1_NAME
})
void deployAppsAndCreateServicesOnCreateService() {
// given that a service is available in the marketplace
@@ -94,4 +96,5 @@ class CreateInstanceWithServicesAcceptanceTest extends CloudFoundryAcceptanceTes
deleteServiceInstance(BACKING_SI_2_NAME);
}
}

View File

@@ -28,14 +28,18 @@ import static org.assertj.core.api.Assertions.assertThat;
class CreateInstanceWithSpacePerServiceInstanceTargetAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_NAME_1 = "app-create-space-per1";
private static final String APP_NAME_2 = "app-create-space-per2";
private static final String SI_NAME = "si-create-space-per";
private static final String BACKING_SI_NAME = "backing-service-space-per-target";
private static final String SUFFIX = "create-instance-space-per-si";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Override
protected String testSuffix() {
@@ -101,4 +105,5 @@ class CreateInstanceWithSpacePerServiceInstanceTargetAcceptanceTest extends Clou
List<String> spaces = getSpaces();
assertThat(spaces).doesNotContain(spaceName);
}
}
}

View File

@@ -20,25 +20,36 @@ import java.net.URI;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
@SuppressWarnings("PMD.DoNotUseThreads")
@Service
public class HealthListener {
class HealthListener {
private static final Logger LOG = LoggerFactory.getLogger(HealthListener.class);
private final AtomicInteger requests = new AtomicInteger();
private final AtomicInteger errors = new AtomicInteger();
private final AtomicBoolean running = new AtomicBoolean(false);
private Thread runner;
private final RestTemplate restTemplate;
public HealthListener(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
void start(String path) {
public void start(String path) {
if (running.get()) {
throw new IllegalStateException("cannot start when test is already running");
}
@@ -50,8 +61,9 @@ public class HealthListener {
while (running.get()) {
try {
requests.incrementAndGet();
ResponseEntity<String> response = restTemplate.getForEntity(URI.create("http://" + path + "/actuator/health"), String.class);
if (response.getStatusCodeValue() != 200) {
ResponseEntity<String> response = restTemplate
.getForEntity(URI.create("http://" + path + "/actuator/health"), String.class);
if (response.getStatusCode() != HttpStatus.OK) {
errors.incrementAndGet();
}
Thread.sleep(1000);
@@ -64,21 +76,23 @@ public class HealthListener {
runner.start();
}
void stop() {
public void stop() {
running.set(false);
try {
runner.join();
}
catch (InterruptedException e) {
e.printStackTrace();
if (LOG.isDebugEnabled()) {
LOG.debug("thread was interrupted while waiting to die", e);
}
}
}
int getSuccesses() {
public int getSuccesses() {
return requests.get();
}
int getFailures() {
public int getFailures() {
return errors.get();
}

View File

@@ -31,11 +31,14 @@ import static org.assertj.core.api.Assertions.assertThat;
class UpdateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_NAME = "app-update";
private static final String SI_NAME = "si-update";
private static final String SUFFIX = "update-instance";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Autowired
private HealthListener healthListener;
@@ -59,7 +62,6 @@ class UpdateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest {
@AppBrokerTestProperties({
"spring.cloud.appbroker.services[0].service-name=" + APP_SERVICE_NAME,
"spring.cloud.appbroker.services[0].plan-name=" + PLAN_NAME,
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].path=" + BACKING_APP_PATH,
"spring.cloud.appbroker.services[0].apps[0].environment.parameter1=config1",
@@ -71,7 +73,7 @@ class UpdateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest {
"spring.cloud.appbroker.services[0].apps[0].parameters-transformers[1].name=PropertyMapping",
"spring.cloud.appbroker.services[0].apps[0].parameters-transformers[1].args.include=count"
})
void deployAppsOnUpdateService() {
public void deployAppsOnUpdateService() {
// given a service instance is created
createServiceInstance(SI_NAME);
@@ -119,4 +121,5 @@ class UpdateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest {
Optional<ApplicationSummary> backingApplicationAfterDeletion = getApplicationSummary(APP_NAME);
assertThat(backingApplicationAfterDeletion).isEmpty();
}
}
}

View File

@@ -30,11 +30,14 @@ import static org.assertj.core.api.Assertions.assertThat;
class UpdateInstanceWithHostAndDomainAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_NAME = "app-update-domain";
private static final String SI_NAME = "si-update-domain";
private static final String SUFFIX = "update-instance-domain";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Autowired
private HealthListener healthListener;
@@ -103,4 +106,5 @@ class UpdateInstanceWithHostAndDomainAcceptanceTest extends CloudFoundryAcceptan
deleteDomain("mydomain.com");
}
}

View File

@@ -16,14 +16,14 @@
package org.springframework.cloud.appbroker.acceptance;
import org.cloudfoundry.operations.applications.ApplicationSummary;
import org.cloudfoundry.operations.services.ServiceInstance;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.cloudfoundry.operations.applications.ApplicationSummary;
import org.cloudfoundry.operations.services.ServiceInstance;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.assertj.core.api.Assertions.assertThat;
@@ -31,13 +31,16 @@ import static org.assertj.core.api.Assertions.assertThat;
class UpdateInstanceWithServicesAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_NAME = "app-update-services";
private static final String SI_NAME = "si-update-services";
private static final String BACKING_SI_NAME = "backing-service-instance-update";
private static final String SUFFIX = "update-instance-with-services";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Autowired
private HealthListener healthListener;
@@ -111,4 +114,5 @@ class UpdateInstanceWithServicesAcceptanceTest extends CloudFoundryAcceptanceTes
// then the service instance is deleted
deleteServiceInstance(SI_NAME);
}
}

View File

@@ -31,11 +31,14 @@ import static org.assertj.core.api.Assertions.assertThat;
class UpdateInstanceWithTargetAcceptanceTest extends CloudFoundryAcceptanceTest {
private static final String APP_NAME = "app-update-target";
private static final String SI_NAME = "si-update-target";
private static final String SUFFIX = "update-instance-with-target";
private static final String APP_SERVICE_NAME = "app-service-"+ SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-"+ SUFFIX;
private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX;
private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX;
@Autowired
private HealthListener healthListener;
@@ -105,4 +108,4 @@ class UpdateInstanceWithTargetAcceptanceTest extends CloudFoundryAcceptanceTest
assertThat(spaces).doesNotContain(spaceName);
}
}
}

View File

@@ -42,16 +42,23 @@ import org.springframework.context.annotation.Configuration;
@EnableConfigurationProperties(CloudFoundryProperties.class)
public class CloudFoundryClientConfiguration {
/**
* The client secret
*/
public static final String APP_BROKER_CLIENT_SECRET = "app-broker-client-secret";
/**
* The client authorities
*/
public static final String[] APP_BROKER_CLIENT_AUTHORITIES = {
"cloud_controller.read", "cloud_controller.write", "clients.write"
};
@Bean
CloudFoundryOperations cloudFoundryOperations(CloudFoundryProperties properties,
CloudFoundryClient client,
DopplerClient dopplerClient,
UaaClient uaaClient) {
protected CloudFoundryOperations cloudFoundryOperations(CloudFoundryProperties properties,
CloudFoundryClient client,
DopplerClient dopplerClient,
UaaClient uaaClient) {
return DefaultCloudFoundryOperations.builder()
.cloudFoundryClient(client)
.dopplerClient(dopplerClient)
@@ -62,8 +69,8 @@ public class CloudFoundryClientConfiguration {
}
@Bean
CloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext,
@Qualifier("userCredentials") TokenProvider tokenProvider) {
protected CloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext,
@Qualifier("userCredentials") TokenProvider tokenProvider) {
return ReactorCloudFoundryClient.builder()
.connectionContext(connectionContext)
.tokenProvider(tokenProvider)
@@ -71,7 +78,7 @@ public class CloudFoundryClientConfiguration {
}
@Bean
ConnectionContext connectionContext(CloudFoundryProperties properties) {
protected ConnectionContext connectionContext(CloudFoundryProperties properties) {
return DefaultConnectionContext.builder()
.apiHost(properties.getApiHost())
.port(Optional.ofNullable(properties.getApiPort()))
@@ -81,8 +88,8 @@ public class CloudFoundryClientConfiguration {
}
@Bean
DopplerClient dopplerClient(ConnectionContext connectionContext,
@Qualifier("userCredentials") TokenProvider tokenProvider) {
protected DopplerClient dopplerClient(ConnectionContext connectionContext,
@Qualifier("userCredentials") TokenProvider tokenProvider) {
return ReactorDopplerClient.builder()
.connectionContext(connectionContext)
.tokenProvider(tokenProvider)
@@ -90,8 +97,8 @@ public class CloudFoundryClientConfiguration {
}
@Bean
UaaClient uaaClient(ConnectionContext connectionContext,
@Qualifier("clientCredentials") TokenProvider tokenProvider) {
protected UaaClient uaaClient(ConnectionContext connectionContext,
@Qualifier("clientCredentials") TokenProvider tokenProvider) {
return ReactorUaaClient.builder()
.connectionContext(connectionContext)
.tokenProvider(tokenProvider)
@@ -104,7 +111,7 @@ public class CloudFoundryClientConfiguration {
CloudFoundryProperties.PROPERTY_PREFIX + ".username",
CloudFoundryProperties.PROPERTY_PREFIX + ".password"
})
PasswordGrantTokenProvider passwordTokenProvider(CloudFoundryProperties properties) {
protected PasswordGrantTokenProvider passwordTokenProvider(CloudFoundryProperties properties) {
return PasswordGrantTokenProvider.builder()
.password(properties.getPassword())
.username(properties.getUsername())
@@ -117,7 +124,7 @@ public class CloudFoundryClientConfiguration {
CloudFoundryProperties.PROPERTY_PREFIX + ".client-id",
CloudFoundryProperties.PROPERTY_PREFIX + ".client-secret"
})
ClientCredentialsGrantTokenProvider clientTokenProvider(CloudFoundryProperties properties) {
protected ClientCredentialsGrantTokenProvider clientTokenProvider(CloudFoundryProperties properties) {
return ClientCredentialsGrantTokenProvider.builder()
.clientId(properties.getClientId())
.clientSecret(properties.getClientSecret())

View File

@@ -27,18 +27,28 @@ import static org.springframework.cloud.appbroker.acceptance.fixtures.cf.CloudFo
@ConfigurationProperties(PROPERTY_PREFIX)
public class CloudFoundryProperties {
static final String PROPERTY_PREFIX = "spring.cloud.appbroker.acceptancetest.cloudfoundry";
protected static final String PROPERTY_PREFIX = "spring.cloud.appbroker.acceptancetest.cloudfoundry";
private String apiHost;
private Integer apiPort;
private String defaultOrg;
private String defaultSpace;
private String username;
private String password;
private String clientId;
private String clientSecret;
private String identityZoneSubdomain;
private boolean secure = true;
private boolean skipSslValidation;
public String getApiHost() {

View File

@@ -73,9 +73,11 @@ import static java.lang.String.format;
public class CloudFoundryService {
private static final Logger LOGGER = LoggerFactory.getLogger(CloudFoundryService.class);
private static final String DEPLOYER_PROPERTY_PREFIX = "spring.cloud.appbroker.deployer.cloudfoundry.";
private static final int EXPECTED_PROPERTY_PARTS = 2;
private final CloudFoundryClient cloudFoundryClient;
private final CloudFoundryOperations cloudFoundryOperations;
@@ -83,8 +85,8 @@ public class CloudFoundryService {
private final CloudFoundryProperties cloudFoundryProperties;
public CloudFoundryService(CloudFoundryClient cloudFoundryClient,
CloudFoundryOperations cloudFoundryOperations,
CloudFoundryProperties cloudFoundryProperties) {
CloudFoundryOperations cloudFoundryOperations,
CloudFoundryProperties cloudFoundryProperties) {
this.cloudFoundryClient = cloudFoundryClient;
this.cloudFoundryOperations = cloudFoundryOperations;
this.cloudFoundryProperties = cloudFoundryProperties;
@@ -125,7 +127,8 @@ public class CloudFoundryService {
.map(url -> "https://" + url);
}
public Mono<Void> pushBrokerApp(String appName, Path appPath, String brokerClientId, String... appBrokerProperties) {
public Mono<Void> pushBrokerApp(String appName, Path appPath, String brokerClientId,
List<String> appBrokerProperties) {
return cloudFoundryOperations.applications()
.pushManifest(PushApplicationManifestRequest.builder()
.manifest(ApplicationManifest.builder()
@@ -168,16 +171,17 @@ public class CloudFoundryService {
.name(si.getName())
.build())
.doOnSuccess(item -> LOGGER.info("Deleted service instance " + serviceInstanceName))
.doOnError(error -> LOGGER.error("Error deleting service instance " + serviceInstanceName + ": " + error))
.doOnError(
error -> LOGGER.error("Error deleting service instance " + serviceInstanceName + ": " + error))
.onErrorResume(e -> Mono.empty()))
.doOnError(error -> LOGGER.warn("Error getting service instance " + serviceInstanceName + ": " + error))
.onErrorResume(e -> Mono.empty());
}
public Mono<Void> createServiceInstance(String planName,
String serviceName,
String serviceInstanceName,
Map<String, Object> parameters) {
String serviceName,
String serviceInstanceName,
Map<String, Object> parameters) {
return cloudFoundryOperations.services()
.createInstance(CreateServiceInstanceRequest.builder()
.planName(planName)
@@ -208,7 +212,7 @@ public class CloudFoundryService {
}
private Mono<ServiceInstance> getServiceInstance(CloudFoundryOperations operations,
String serviceInstanceName) {
String serviceInstanceName) {
return operations.services()
.getInstance(GetServiceInstanceRequest.builder()
.name(serviceInstanceName)
@@ -338,28 +342,28 @@ public class CloudFoundryService {
public Mono<Void> createDomain(String domain) {
return cloudFoundryOperations
.domains()
.create(CreateDomainRequest
.builder()
.domain(domain)
.organization(cloudFoundryProperties.getDefaultOrg())
.build())
.onErrorResume(e -> Mono.empty());
.domains()
.create(CreateDomainRequest
.builder()
.domain(domain)
.organization(cloudFoundryProperties.getDefaultOrg())
.build())
.onErrorResume(e -> Mono.empty());
}
public Mono<Void> deleteDomain(String domain) {
return cloudFoundryOperations
.domains()
.list()
.filter(d -> d.getName().equals(domain))
.map(Domain::getId)
.flatMap(domainId -> cloudFoundryClient
.privateDomains()
.delete(DeletePrivateDomainRequest
.builder()
.privateDomainId(domainId)
.build()))
.then();
.domains()
.list()
.filter(d -> d.getName().equals(domain))
.map(Domain::getId)
.flatMap(domainId -> cloudFoundryClient
.privateDomains()
.delete(DeletePrivateDomainRequest
.builder()
.privateDomainId(domainId)
.build()))
.then();
}
private Mono<AssociateOrganizationUserResponse> associateOrgUser(String orgId, String userId) {
@@ -432,17 +436,19 @@ public class CloudFoundryService {
return deployerVariables;
}
private Map<String, String> propertiesToEnvironment(String... properties) {
private Map<String, String> propertiesToEnvironment(List<String> properties) {
Map<String, String> environment = new HashMap<>();
for (String property : properties) {
final String[] propertyKeyValue = property.split("=");
if (propertyKeyValue.length == 2) {
if (propertyKeyValue.length == EXPECTED_PROPERTY_PARTS) {
environment.put(propertyKeyValue[0], propertyKeyValue[1]);
} else {
}
else {
throw new IllegalArgumentException(format("App Broker property '%s' is incorrectly formatted",
Arrays.toString(propertyKeyValue)));
}
}
return environment;
}
}

View File

@@ -24,12 +24,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.appbroker.deployer.AppDeployer;
import org.springframework.cloud.appbroker.deployer.DefaultBackingAppDeploymentService;
import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService;
import org.springframework.cloud.appbroker.deployer.BackingApplication;
import org.springframework.cloud.appbroker.deployer.BackingService;
import org.springframework.cloud.appbroker.deployer.BackingServicesProvisionService;
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
import org.springframework.cloud.appbroker.deployer.DefaultBackingAppDeploymentService;
import org.springframework.cloud.appbroker.deployer.DefaultBackingServicesProvisionService;
import org.springframework.cloud.appbroker.deployer.DeployerClient;
import org.springframework.cloud.appbroker.extensions.credentials.CredentialGenerator;
@@ -71,6 +71,10 @@ import org.springframework.cloud.servicebroker.service.ServiceInstanceBindingSer
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* App Broker Auto-configuration
*/
@SuppressWarnings("PMD.CouplingBetweenObjects")
@Configuration
@AutoConfigureAfter(CloudFoundryAppDeployerAutoConfiguration.class)
@ConditionalOnBean(AppDeployer.class)
@@ -78,124 +82,251 @@ public class AppBrokerAutoConfiguration {
private static final String PROPERTY_PREFIX = "spring.cloud.appbroker";
/**
* Provide a {@link DeployerClient} bean
*
* @param appDeployer the AppDeployer bean
* @return the bean
*/
@Bean
public DeployerClient deployerClient(AppDeployer appDeployer) {
return new DeployerClient(appDeployer);
}
/**
* Provide a {@link BackingAppDeploymentService} bean
*
* @param deployerClient the DeployerClient bean
* @return the bean
*/
@Bean
@ConditionalOnMissingBean
public BackingAppDeploymentService backingAppDeploymentService(DeployerClient deployerClient) {
return new DefaultBackingAppDeploymentService(deployerClient);
}
/**
* Provide a {@link ManagementClient} bean
*
* @param appManager the AppManager bean
* @return the bean
*/
@Bean
public ManagementClient managementClient(AppManager appManager) {
return new ManagementClient(appManager);
}
/**
* Provide a {@link BackingAppManagementService} bean
*
* @param managementClient the ManagementClient bean
* @param appDeployer the AppDeployer bean
* @param brokeredServices the BrokeredServices bean
* @param targetService the TargetService bean
* @return the bean
*/
@Bean
public BackingAppManagementService backingAppManagementService(ManagementClient managementClient,
AppDeployer appDeployer, BrokeredServices brokeredServices, TargetService targetService) {
return new BackingAppManagementService(managementClient, appDeployer, brokeredServices, targetService);
}
/**
* Provide a {@link BrokeredServices} bean
*
* @return the bean
*/
@Bean
@ConfigurationProperties(PROPERTY_PREFIX + ".services")
public BrokeredServices brokeredServices() {
return BrokeredServices.builder().build();
}
/**
* Provide a {@link ServiceInstanceStateRepository} bean
*
* @return the bean
*/
@Bean
@ConditionalOnMissingBean(ServiceInstanceStateRepository.class)
public ServiceInstanceStateRepository serviceInstanceStateRepository() {
return new InMemoryServiceInstanceStateRepository();
}
/**
* Provide a {@link ServiceInstanceBindingStateRepository} bean
*
* @return the bean
*/
@Bean
@ConditionalOnMissingBean(ServiceInstanceBindingStateRepository.class)
public ServiceInstanceBindingStateRepository serviceInstanceBindingStateRepository() {
return new InMemoryServiceInstanceBindingStateRepository();
}
/**
* Provide an {@link EnvironmentMappingParametersTransformerFactory} bean
*
* @return the bean
*/
@Bean
public EnvironmentMappingParametersTransformerFactory environmentMappingParametersTransformerFactory() {
return new EnvironmentMappingParametersTransformerFactory();
}
/**
* Provide a {@link ParameterMappingParametersTransformerFactory} bean
*
* @return the bean
*/
@Bean
public PropertyMappingParametersTransformerFactory propertyMappingParametersTransformerFactory() {
return new PropertyMappingParametersTransformerFactory();
}
/**
* Provide a {@link ParameterMappingParametersTransformerFactory} bean
*
* @return the bean
*/
@Bean
public ParameterMappingParametersTransformerFactory parameterMappingParametersTransformerFactory() {
return new ParameterMappingParametersTransformerFactory();
}
/**
* Provide a {@link BackingApplicationsParametersTransformationService} bean
*
* @param transformers a collection of parameter transformers
* @return the bean
*/
@Bean
public BackingApplicationsParametersTransformationService backingApplicationsParametersTransformationService(
List<ParametersTransformerFactory<BackingApplication, ?>> transformers) {
return new BackingApplicationsParametersTransformationService(transformers);
}
/**
* Provide a {@link BackingServicesParametersTransformationService} bean
*
* @param transformers a collection of parameter transformers
* @return the bean
*/
@Bean
public BackingServicesParametersTransformationService backingServicesParametersTransformationService(
List<ParametersTransformerFactory<BackingService, ?>> transformers) {
return new BackingServicesParametersTransformationService(transformers);
}
/**
* Provide a {@link SimpleCredentialGenerator} bean
*
* @return the bean
*/
@ConditionalOnMissingBean(CredentialGenerator.class)
@Bean
public SimpleCredentialGenerator simpleCredentialGenerator() {
return new SimpleCredentialGenerator();
}
/**
* Provide a {@link SpringSecurityBasicAuthCredentialProviderFactory} bean
*
* @param credentialGenerator the CredentialGenerator bean
* @return the bean
*/
@Bean
public SpringSecurityBasicAuthCredentialProviderFactory springSecurityBasicAuthCredentialProvider(CredentialGenerator credentialGenerator) {
public SpringSecurityBasicAuthCredentialProviderFactory springSecurityBasicAuthCredentialProvider(
CredentialGenerator credentialGenerator) {
return new SpringSecurityBasicAuthCredentialProviderFactory(credentialGenerator);
}
/**
* Provide a {@link SpringSecurityOAuth2CredentialProviderFactory} bean
*
* @param credentialGenerator the CredentialGenerator bean
* @param oAuth2Client the OAuth2Client bean
* @return the bean
*/
@Bean
public SpringSecurityOAuth2CredentialProviderFactory springSecurityOAuth2CredentialProvider(CredentialGenerator credentialGenerator,
OAuth2Client oAuth2Client) {
public SpringSecurityOAuth2CredentialProviderFactory springSecurityOAuth2CredentialProvider(
CredentialGenerator credentialGenerator,
OAuth2Client oAuth2Client) {
return new SpringSecurityOAuth2CredentialProviderFactory(credentialGenerator, oAuth2Client);
}
/**
* Provide a {@link CredentialProviderService} bean
*
* @param providers a collection of credential providers
* @return the bean
*/
@Bean
public CredentialProviderService credentialProviderService(List<CredentialProviderFactory<?>> providers) {
return new CredentialProviderService(providers);
}
/**
* Provide a {@link SpacePerServiceInstance} bean
*
* @return the bean
*/
@Bean
public SpacePerServiceInstance spacePerServiceInstance() {
return new SpacePerServiceInstance();
}
/**
* Provide a {@link ServiceInstanceGuidSuffix} bean
*
* @return the bean
*/
@Bean
public ServiceInstanceGuidSuffix serviceInstanceGuidSuffix() {
return new ServiceInstanceGuidSuffix();
}
/**
* Provide a {@link TargetService} bean
*
* @param targets a collection of targets
* @return the bean
*/
@Bean
public TargetService targetService(List<TargetFactory<?>> targets) {
return new TargetService(targets);
}
/**
* Provide a {@link BackingServicesProvisionService} bean
*
* @param deployerClient the DeployerClient bean
* @return the bean
*/
@Bean
@ConditionalOnMissingBean
public BackingServicesProvisionService backingServicesProvisionService(DeployerClient deployerClient) {
return new DefaultBackingServicesProvisionService(deployerClient);
}
/**
* Provide a {@link CreateServiceInstanceWorkflow} bean
*
* @param brokeredServices the BrokeredServices bean
* @param backingAppDeploymentService the BackingAppDeploymentService bean
* @param appsParametersTransformationService the BackingApplicationsParametersTransformationService bean
* @param servicesParametersTransformationService the BackingServicesParametersTransformationService bean
* @param credentialProviderService the CredentialProviderService bean
* @param targetService the TargetService bean
* @param backingServicesProvisionService the BackingServicesProvisionService bean
* @return the bean
*/
@Bean
public CreateServiceInstanceWorkflow appDeploymentCreateServiceInstanceWorkflow(
BrokeredServices brokeredServices,
BackingAppDeploymentService backingAppDeploymentService,
BrokeredServices brokeredServices, BackingAppDeploymentService backingAppDeploymentService,
BackingApplicationsParametersTransformationService appsParametersTransformationService,
BackingServicesParametersTransformationService servicesParametersTransformationService,
CredentialProviderService credentialProviderService,
TargetService targetService,
CredentialProviderService credentialProviderService, TargetService targetService,
BackingServicesProvisionService backingServicesProvisionService) {
return new AppDeploymentCreateServiceInstanceWorkflow(
brokeredServices,
@@ -207,10 +338,20 @@ public class AppBrokerAutoConfiguration {
targetService);
}
/**
* Provide a {@link UpdateServiceInstanceWorkflow} bean
*
* @param brokeredServices the BrokeredServices bean
* @param backingAppDeploymentService the BackingAppDeploymentService bean
* @param backingServicesProvisionService the BackingServicesProvisionService bean
* @param appsParametersTransformationService the BackingApplicationsParametersTransformationService bean
* @param servicesParametersTransformationService the BackingServicesParametersTransformationService bean
* @param targetService the TargetService bean
* @return the bean
*/
@Bean
public UpdateServiceInstanceWorkflow appDeploymentUpdateServiceInstanceWorkflow(
BrokeredServices brokeredServices,
BackingAppDeploymentService backingAppDeploymentService,
BrokeredServices brokeredServices, BackingAppDeploymentService backingAppDeploymentService,
BackingServicesProvisionService backingServicesProvisionService,
BackingApplicationsParametersTransformationService appsParametersTransformationService,
BackingServicesParametersTransformationService servicesParametersTransformationService,
@@ -225,13 +366,21 @@ public class AppBrokerAutoConfiguration {
targetService);
}
/**
* Provide a {@link DeleteServiceInstanceWorkflow} bean
*
* @param brokeredServices the BrokeredServices bean
* @param backingAppDeploymentService the BackingAppDeploymentService bean
* @param backingServicesProvisionService the BackingServicesProvisionService bean
* @param credentialProviderService the CredentialProviderService bean
* @param targetService the TargetService bean
* @return the bean
*/
@Bean
public DeleteServiceInstanceWorkflow appDeploymentDeleteServiceInstanceWorkflow(
BrokeredServices brokeredServices,
BackingAppDeploymentService backingAppDeploymentService,
BrokeredServices brokeredServices, BackingAppDeploymentService backingAppDeploymentService,
BackingServicesProvisionService backingServicesProvisionService,
CredentialProviderService credentialProviderService,
TargetService targetService) {
CredentialProviderService credentialProviderService, TargetService targetService) {
return new AppDeploymentDeleteServiceInstanceWorkflow(
brokeredServices,
@@ -241,14 +390,31 @@ public class AppBrokerAutoConfiguration {
);
}
/**
* Provide a {@link WorkflowServiceInstanceService} bean
*
* @param stateRepository the ServiceInstanceStateRepository bean
* @param createWorkflows a collection of create workflows
* @param deleteWorkflows a collection of delete workflows
* @param updateWorkflows a collection of update workflows
* @return the bean
*/
@Bean
public WorkflowServiceInstanceService serviceInstanceService(ServiceInstanceStateRepository stateRepository,
List<CreateServiceInstanceWorkflow> createWorkflows,
List<DeleteServiceInstanceWorkflow> deleteWorkflows,
List<UpdateServiceInstanceWorkflow> updateWorkflows) {
List<CreateServiceInstanceWorkflow> createWorkflows, List<DeleteServiceInstanceWorkflow> deleteWorkflows,
List<UpdateServiceInstanceWorkflow> updateWorkflows) {
return new WorkflowServiceInstanceService(stateRepository, createWorkflows, deleteWorkflows, updateWorkflows);
}
/**
* Provide a {@link WorkflowServiceInstanceBindingService} bean
*
* @param stateRepository the ServiceInstanceBindingStateRepository bean
* @param createServiceInstanceAppBindingWorkflows a collection of create app binding workflows
* @param createServiceInstanceRouteBindingWorkflows a collection of create route binding workflows
* @param deleteServiceInstanceBindingWorkflows a collection of update workflows
* @return the bean
*/
@Bean
@ConditionalOnMissingBean(ServiceInstanceBindingService.class)
public WorkflowServiceInstanceBindingService serviceInstanceBindingService(
@@ -257,8 +423,8 @@ public class AppBrokerAutoConfiguration {
@Autowired(required = false) List<CreateServiceInstanceRouteBindingWorkflow> createServiceInstanceRouteBindingWorkflows,
@Autowired(required = false) List<DeleteServiceInstanceBindingWorkflow> deleteServiceInstanceBindingWorkflows) {
return new WorkflowServiceInstanceBindingService(stateRepository,
createServiceInstanceAppBindingWorkflows,
createServiceInstanceRouteBindingWorkflows,
createServiceInstanceAppBindingWorkflows, createServiceInstanceRouteBindingWorkflows,
deleteServiceInstanceBindingWorkflows);
}
}

View File

@@ -42,11 +42,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.appbroker.deployer.AppDeployer;
import org.springframework.cloud.appbroker.deployer.cloudfoundry.CloudFoundryAppManager;
import org.springframework.cloud.appbroker.deployer.cloudfoundry.CloudFoundryOperationsUtils;
import org.springframework.cloud.appbroker.deployer.cloudfoundry.CloudFoundryAppDeployer;
import org.springframework.cloud.appbroker.deployer.cloudfoundry.CloudFoundryAppManager;
import org.springframework.cloud.appbroker.deployer.cloudfoundry.CloudFoundryDeploymentProperties;
import org.springframework.cloud.appbroker.deployer.cloudfoundry.CloudFoundryOAuth2Client;
import org.springframework.cloud.appbroker.deployer.cloudfoundry.CloudFoundryOperationsUtils;
import org.springframework.cloud.appbroker.deployer.cloudfoundry.CloudFoundryTargetProperties;
import org.springframework.cloud.appbroker.manager.AppManager;
import org.springframework.cloud.appbroker.oauth2.OAuth2Client;
@@ -55,59 +55,108 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
/**
* Auto-configuration support for deploying apps to Cloud Foundry
*/
@Configuration
@ConditionalOnProperty(CloudFoundryAppDeployerAutoConfiguration.PROPERTY_PREFIX + ".api-host")
@EnableConfigurationProperties
public class CloudFoundryAppDeployerAutoConfiguration {
static final String PROPERTY_PREFIX = "spring.cloud.appbroker.deployer.cloudfoundry";
protected static final String PROPERTY_PREFIX = "spring.cloud.appbroker.deployer.cloudfoundry";
/**
* Provide a {@link CloudFoundryDeploymentProperties} bean
*
* @return the bean
*/
@Bean
@ConfigurationProperties(PROPERTY_PREFIX + ".properties")
CloudFoundryDeploymentProperties cloudFoundryDeploymentProperties() {
public CloudFoundryDeploymentProperties cloudFoundryDeploymentProperties() {
return new CloudFoundryDeploymentProperties();
}
/**
* Provide a {@link CloudFoundryTargetProperties} bean
*
* @return the bean
*/
@Bean
@ConfigurationProperties(PROPERTY_PREFIX)
CloudFoundryTargetProperties cloudFoundryTargetProperties() {
public CloudFoundryTargetProperties cloudFoundryTargetProperties() {
return new CloudFoundryTargetProperties();
}
/**
* Provide a {@link AppDeployer} bean
*
* @param deploymentProperties the CloudFoundryDeploymentProperties bean
* @param cloudFoundryOperations the CloudFoundryOperations bean
* @param cloudFoundryClient the CloudFoundryClient bean
* @param operationsUtils the CloudFoundryOperationsUtils bean
* @param targetProperties the CloudFoundryTargetProperties bean
* @param resourceLoader the ResourceLoader bean
* @return the bean
*/
@Bean
AppDeployer cloudFoundryAppDeployer(CloudFoundryDeploymentProperties deploymentProperties,
CloudFoundryOperations cloudFoundryOperations,
CloudFoundryClient cloudFoundryClient,
CloudFoundryOperationsUtils operationsUtils,
CloudFoundryTargetProperties targetProperties,
ResourceLoader resourceLoader) {
public AppDeployer cloudFoundryAppDeployer(CloudFoundryDeploymentProperties deploymentProperties,
CloudFoundryOperations cloudFoundryOperations, CloudFoundryClient cloudFoundryClient,
CloudFoundryOperationsUtils operationsUtils, CloudFoundryTargetProperties targetProperties,
ResourceLoader resourceLoader) {
return new CloudFoundryAppDeployer(deploymentProperties, cloudFoundryOperations, cloudFoundryClient,
operationsUtils, targetProperties, resourceLoader);
}
/**
* Provide an {@link AppManager} bean
*
* @param cloudFoundryOperationsUtils the CloudFoundryOperationsUtils bean
* @return the bean
*/
@Bean
AppManager cloudFoundryAppManager(CloudFoundryOperationsUtils cloudFoundryOperationsUtils) {
public AppManager cloudFoundryAppManager(CloudFoundryOperationsUtils cloudFoundryOperationsUtils) {
return new CloudFoundryAppManager(cloudFoundryOperationsUtils);
}
/**
* Provide an {@link OAuth2Client} bean
*
* @param uaaClient the UaaClient bean
* @return the bean
*/
@Bean
OAuth2Client cloudFoundryOAuth2Client(@UaaClientQualifier UaaClient uaaClient) {
public OAuth2Client cloudFoundryOAuth2Client(@UaaClientQualifier UaaClient uaaClient) {
return new CloudFoundryOAuth2Client(uaaClient);
}
/**
* Provide a {@link ReactorCloudFoundryClient} bean
*
* @param connectionContext the ConnectionContext bean
* @param tokenProvider the TokenProvider bean
* @return the bean
*/
@Bean
ReactorCloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext,
@TokenQualifier TokenProvider tokenProvider) {
public ReactorCloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext,
@TokenQualifier TokenProvider tokenProvider) {
return ReactorCloudFoundryClient.builder()
.connectionContext(connectionContext)
.tokenProvider(tokenProvider)
.build();
}
/**
* Provide a {@link CloudFoundryOperations} bean
*
* @param properties the CloudFoundryTargetProperties bean
* @param client the CloudFoundryClient bean
* @param dopplerClient the DopplerClient bean
* @param uaaClient the UaaClient bean
* @return the bean
*/
@Bean
CloudFoundryOperations cloudFoundryOperations(CloudFoundryTargetProperties properties,
CloudFoundryClient client,
DopplerClient dopplerClient,
@UaaClientQualifier UaaClient uaaClient) {
public CloudFoundryOperations cloudFoundryOperations(CloudFoundryTargetProperties properties,
CloudFoundryClient client, DopplerClient dopplerClient, @UaaClientQualifier UaaClient uaaClient) {
return DefaultCloudFoundryOperations.builder()
.cloudFoundryClient(client)
.dopplerClient(dopplerClient)
@@ -117,13 +166,25 @@ public class CloudFoundryAppDeployerAutoConfiguration {
.build();
}
/**
* Provide a {@link CloudFoundryOperationsUtils} bean
*
* @param operations the CloudFoundryOperations bean
* @return the bean
*/
@Bean
CloudFoundryOperationsUtils cloudFoundryOperationsUtils(CloudFoundryOperations operations) {
public CloudFoundryOperationsUtils cloudFoundryOperationsUtils(CloudFoundryOperations operations) {
return new CloudFoundryOperationsUtils(operations);
}
/**
* Provide a {@link DefaultConnectionContext} bean
*
* @param properties the CloudFoundryTargetProperties bean
* @return the bean
*/
@Bean
DefaultConnectionContext connectionContext(CloudFoundryTargetProperties properties) {
public DefaultConnectionContext connectionContext(CloudFoundryTargetProperties properties) {
return DefaultConnectionContext.builder()
.apiHost(properties.getApiHost())
.port(Optional.ofNullable(properties.getApiPort()))
@@ -132,22 +193,35 @@ public class CloudFoundryAppDeployerAutoConfiguration {
.build();
}
/**
* Provide a {@link ReactorDopplerClient} bean
*
* @param connectionContext the ConnectionContext bean
* @param tokenProvider the TokenProvider bean
* @return the bean
*/
@Bean
ReactorDopplerClient dopplerClient(ConnectionContext connectionContext,
@TokenQualifier TokenProvider tokenProvider) {
public ReactorDopplerClient dopplerClient(ConnectionContext connectionContext,
@TokenQualifier TokenProvider tokenProvider) {
return ReactorDopplerClient.builder()
.connectionContext(connectionContext)
.tokenProvider(tokenProvider)
.build();
}
/**
* Provide a {@link TokenProvider} bean
*
* @param properties the CloudFoundryTargetProperties bean
* @return the bean
*/
@TokenQualifier
@Bean
TokenProvider uaaTokenProvider(CloudFoundryTargetProperties properties) {
public TokenProvider uaaTokenProvider(CloudFoundryTargetProperties properties) {
boolean isClientIdAndSecretSet = Stream.of(properties.getClientId(), properties.getClientSecret())
.allMatch(StringUtils::hasText);
.allMatch(StringUtils::hasText);
boolean isUsernameAndPasswordSet = Stream.of(properties.getUsername(), properties.getPassword())
.allMatch(StringUtils::hasText);
.allMatch(StringUtils::hasText);
if (isClientIdAndSecretSet && isUsernameAndPasswordSet) {
throw new IllegalStateException(
String.format("(%1$s.client_id / %1$s.client_secret) must not be set when\n" +
@@ -155,16 +229,16 @@ public class CloudFoundryAppDeployerAutoConfiguration {
}
else if (isClientIdAndSecretSet) {
return ClientCredentialsGrantTokenProvider.builder()
.clientId(properties.getClientId())
.clientSecret(properties.getClientSecret())
.identityZoneSubdomain(properties.getIdentityZoneSubdomain())
.build();
.clientId(properties.getClientId())
.clientSecret(properties.getClientSecret())
.identityZoneSubdomain(properties.getIdentityZoneSubdomain())
.build();
}
else if (isUsernameAndPasswordSet) {
return PasswordGrantTokenProvider.builder()
.password(properties.getPassword())
.username(properties.getUsername())
.build();
.password(properties.getPassword())
.username(properties.getUsername())
.build();
}
else {
throw new IllegalStateException(
@@ -173,10 +247,17 @@ public class CloudFoundryAppDeployerAutoConfiguration {
}
}
/**
* Provide a {@link ReactorUaaClient} bean
*
* @param connectionContext the ConnectionContext bean
* @param tokenProvider the TokenProvider bean
* @return the bean
*/
@UaaClientQualifier
@Bean
ReactorUaaClient uaaClient(ConnectionContext connectionContext,
@TokenQualifier TokenProvider tokenProvider) {
public ReactorUaaClient uaaClient(ConnectionContext connectionContext,
@TokenQualifier TokenProvider tokenProvider) {
return ReactorUaaClient.builder()
.connectionContext(connectionContext)
.tokenProvider(tokenProvider)
@@ -189,13 +270,16 @@ public class CloudFoundryAppDeployerAutoConfiguration {
public @interface TokenQualifier {
String value() default "appBrokerTokenProvider";
}
@Qualifier
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UaaClientQualifier {
public @interface UaaClientQualifier {
String value() default "appBrokerUaaClientQualifier";
}
}

View File

@@ -31,6 +31,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.credhub.autoconfig.CredHubTemplateAutoConfiguration;
import org.springframework.credhub.core.CredHubOperations;
/**
* CredHub auto-configuration
*/
@Configuration
@AutoConfigureBefore(AppBrokerAutoConfiguration.class)
@AutoConfigureAfter(CredHubTemplateAutoConfiguration.class)
@@ -41,16 +44,36 @@ public class CredHubAutoConfiguration {
@Value("${spring.application.name}")
private String appName;
/**
* Provide a {@link CreateServiceInstanceAppBindingWorkflow} bean
*
* @param credHubOperations the CredHubOperations bean
* @return the bean
*/
@Bean
public CreateServiceInstanceAppBindingWorkflow credhubPersistingCreateServiceInstanceAppBindingWorkflow(CredHubOperations credHubOperations) {
public CreateServiceInstanceAppBindingWorkflow credhubPersistingCreateServiceInstanceAppBindingWorkflow(
CredHubOperations credHubOperations) {
return new CredHubPersistingCreateServiceInstanceAppBindingWorkflow(credHubOperations, appName);
}
/**
* Provide a {@link DeleteServiceInstanceBindingWorkflow} bean
*
* @param credHubOperations the CredHubOperations bean
* @return the bean
*/
@Bean
public DeleteServiceInstanceBindingWorkflow credhubPersistingDeleteServiceInstanceAppBindingWorkflow(CredHubOperations credHubOperations) {
public DeleteServiceInstanceBindingWorkflow credhubPersistingDeleteServiceInstanceAppBindingWorkflow(
CredHubOperations credHubOperations) {
return new CredHubPersistingDeleteServiceInstanceBindingWorkflow(credHubOperations, appName);
}
/**
* Provide a {@link CredHubCredentialsGenerator} bean
*
* @param credHubOperations the CredHubOperations bean
* @return the bean
*/
@Bean
public CredHubCredentialsGenerator credHubCredentialsGenerator(CredHubOperations credHubOperations) {
return new CredHubCredentialsGenerator(credHubOperations);

View File

@@ -266,10 +266,12 @@ class AppBrokerAutoConfigurationTest {
public ServiceInstanceBindingService serviceInstanceBindingService() {
return new TestServiceInstanceBindingService();
}
}
@Configuration
public static class CustomStateRepositoriesConfiguration {
@Bean
public ServiceInstanceStateRepository serviceInstanceStateRepository() {
return new TestServiceInstanceStateRepository();
@@ -279,6 +281,7 @@ class AppBrokerAutoConfigurationTest {
public ServiceInstanceBindingStateRepository serviceInstanceBindingStateRepository() {
return new TestServiceInstanceBindingStateRepository();
}
}
private static class TestServiceInstanceBindingService implements ServiceInstanceBindingService {
@@ -287,4 +290,5 @@ class AppBrokerAutoConfigurationTest {
private static class TestServiceInstanceStateRepository implements ServiceInstanceStateRepository {}
private static class TestServiceInstanceBindingStateRepository implements ServiceInstanceBindingStateRepository {}
}
}

View File

@@ -69,7 +69,8 @@ class CloudFoundryAppDeployerAutoConfigurationTest {
assertThat(targetProperties.getPassword()).isEqualTo("secret");
assertThat(context).hasSingleBean(CloudFoundryDeploymentProperties.class);
CloudFoundryDeploymentProperties deploymentProperties = context.getBean(CloudFoundryDeploymentProperties.class);
CloudFoundryDeploymentProperties deploymentProperties = context
.getBean(CloudFoundryDeploymentProperties.class);
assertThat(deploymentProperties.getMemory()).isEqualTo("2G");
assertThat(deploymentProperties.getCount()).isEqualTo(3);
assertThat(deploymentProperties.getBuildpack()).isEqualTo("example-buildpack");
@@ -139,4 +140,4 @@ class CloudFoundryAppDeployerAutoConfigurationTest {
});
}
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.appbroker.autoconfigure;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.TestConfiguration;
@@ -80,10 +81,12 @@ class CredHubAutoConfigurationTest {
@TestConfiguration
public static class CredHubConfiguration {
@Bean
public CredHubOperations credHubOperations() {
return mock(CredHubOperations.class);
}
}
}
}

View File

@@ -20,11 +20,36 @@ import java.util.List;
import reactor.core.publisher.Flux;
/**
* This interface is implemented by service brokers to process requests to deploy, update, and undeploy backing
* applications associated with a service instance.
*/
public interface BackingAppDeploymentService {
/**
* Deploy the backing applications and associate with the service instance
*
* @param backingApps a collection of backing applications
* @param serviceInstanceId the service instance ID
* @return a set of strings, where each corresponds to an application e.g. the application name
*/
Flux<String> deploy(List<BackingApplication> backingApps, String serviceInstanceId);
/**
* Update the backing applications and associate with the service instance
*
* @param backingApps a collection of backing applications
* @param serviceInstanceId the service instance ID
* @return a set of strings, where each corresponds to an application. e.g. the application name
*/
Flux<String> update(List<BackingApplication> backingApps, String serviceInstanceId);
/**
* Undeploy the backing applications
*
* @param backingApps a collection of backing applications
* @return a set of strings, where each corresponds to an application. e.g. the application name
*/
Flux<String> undeploy(List<BackingApplication> backingApps);
}

View File

@@ -26,28 +26,48 @@ import java.util.stream.Collectors;
import org.springframework.util.CollectionUtils;
/**
* An application deployed as part of the service provisioning process
*/
@SuppressWarnings("PMD.GodClass")
public class BackingApplication {
private static final String VALUE_HIDDEN = "<value hidden>";
private String name;
private String path;
private Map<String, String> properties;
private Map<String, Object> environment;
private List<ServicesSpec> services;
private List<ParametersTransformerSpec> parametersTransformers;
private List<CredentialProviderSpec> credentialProviders;
private BackingApplication() {
}
BackingApplication(String name, String path,
Map<String, String> properties,
Map<String, Object> environment,
List<ServicesSpec> services,
List<ParametersTransformerSpec> parametersTransformers,
List<CredentialProviderSpec> credentialProviders) {
/**
* Construct a new {@link BackingApplication}
*
* @param name the name of the application
* @param path the path to the application
* @param properties the properties
* @param environment the environment variables
* @param services the services required by the application
* @param parametersTransformers the parameter transformers
* @param credentialProviders the credential providers
*/
public BackingApplication(String name, String path,
Map<String, String> properties,
Map<String, Object> environment,
List<ServicesSpec> services,
List<ParametersTransformerSpec> parametersTransformers,
List<CredentialProviderSpec> credentialProviders) {
this.name = name;
this.path = path;
this.properties = properties;
@@ -81,6 +101,12 @@ public class BackingApplication {
this.properties = properties;
}
/**
* Add a single property
*
* @param key the key
* @param value the value
*/
public void addProperty(String key, String value) {
this.properties.put(key, value);
}
@@ -93,6 +119,12 @@ public class BackingApplication {
this.environment = environment;
}
/**
* Add a single environment value
*
* @param key the key
* @param value the value
*/
public void addEnvironment(String key, Object value) {
environment.put(key, value);
}
@@ -121,6 +153,11 @@ public class BackingApplication {
this.credentialProviders = credentialProviders;
}
/**
* Create a builder that provides a fluent API for constructing a {@literal BackingApplication}.
*
* @return the builder
*/
public static BackingApplicationBuilder builder() {
return new BackingApplicationBuilder();
}
@@ -145,8 +182,7 @@ public class BackingApplication {
@Override
public final int hashCode() {
return Objects.hash(name, path, properties, environment, services,
parametersTransformers, credentialProviders);
return Objects.hash(name, path, properties, environment, services, parametersTransformers, credentialProviders);
}
@Override
@@ -173,7 +209,10 @@ public class BackingApplication {
return sanitizedEnvironment;
}
public static class BackingApplicationBuilder {
/**
* Provides a fluent API for constructing a {@literal BackingApplication}.
*/
public static final class BackingApplicationBuilder {
private String name;
@@ -189,48 +228,73 @@ public class BackingApplication {
private final List<CredentialProviderSpec> credentialProviders = new ArrayList<>();
BackingApplicationBuilder() {
private BackingApplicationBuilder() {
}
/**
* Build a backing application based on another application definition
*
* @param backingApplication the backing application from which to copy properties
* @return the builder
*/
public BackingApplicationBuilder backingApplication(BackingApplication backingApplication) {
this.name(backingApplication.getName())
.path(backingApplication.getPath())
.properties(backingApplication.getProperties())
.environment(backingApplication.getEnvironment());
if (!CollectionUtils.isEmpty(backingApplication.getServices())) {
this.services(backingApplication.getServices().stream()
.map(spec -> ServicesSpec.builder()
.spec(spec)
.build())
.collect(Collectors.toList()));
}
if (!CollectionUtils.isEmpty(backingApplication.getParametersTransformers())) {
this.parameterTransformers(backingApplication.getParametersTransformers().stream()
.map(spec -> ParametersTransformerSpec.builder()
.spec(spec)
.build())
.collect(Collectors.toList()));
}
if (!CollectionUtils.isEmpty(backingApplication.getCredentialProviders())) {
this.credentialProviders(backingApplication.getCredentialProviders().stream()
.map(spec -> CredentialProviderSpec.builder()
.spec(spec)
.build())
.collect(Collectors.toList()));
}
return this;
if (!CollectionUtils.isEmpty(backingApplication.getServices())) {
this.services(backingApplication.getServices().stream()
.map(spec -> ServicesSpec.builder()
.spec(spec)
.build())
.collect(Collectors.toList()));
}
if (!CollectionUtils.isEmpty(backingApplication.getParametersTransformers())) {
this.parameterTransformers(backingApplication.getParametersTransformers().stream()
.map(spec -> ParametersTransformerSpec.builder()
.spec(spec)
.build())
.collect(Collectors.toList()));
}
if (!CollectionUtils.isEmpty(backingApplication.getCredentialProviders())) {
this.credentialProviders(backingApplication.getCredentialProviders().stream()
.map(spec -> CredentialProviderSpec.builder()
.spec(spec)
.build())
.collect(Collectors.toList()));
}
return this;
}
/**
* The name of the application
*
* @param name the name
* @return the builder
*/
public BackingApplicationBuilder name(String name) {
this.name = name;
return this;
}
/**
* The path to the application
*
* @param path the path
* @return the builder
*/
public BackingApplicationBuilder path(String path) {
this.path = path;
return this;
}
/**
* Properties that describe the application
*
* @param key the property key
* @param value the property value
* @return the builder
*/
public BackingApplicationBuilder property(String key, String value) {
if (key != null && value != null) {
this.properties.put(key, value);
@@ -238,6 +302,12 @@ public class BackingApplication {
return this;
}
/**
* Properties that describe the application
*
* @param properties the properties
* @return the builder
*/
public BackingApplicationBuilder properties(Map<String, String> properties) {
if (!CollectionUtils.isEmpty(properties)) {
this.properties.putAll(properties);
@@ -245,6 +315,13 @@ public class BackingApplication {
return this;
}
/**
* Environment variables to be set for the application
*
* @param key the env var key
* @param value the env var value
* @return the builder
*/
public BackingApplicationBuilder environment(String key, String value) {
if (key != null && value != null) {
this.environment.put(key, value);
@@ -252,6 +329,12 @@ public class BackingApplication {
return this;
}
/**
* Environment variables to be set for the application
*
* @param environment the env vars
* @return the builder
*/
public BackingApplicationBuilder environment(Map<String, Object> environment) {
if (!CollectionUtils.isEmpty(environment)) {
this.environment.putAll(environment);
@@ -259,6 +342,12 @@ public class BackingApplication {
return this;
}
/**
* Services required by the application
*
* @param services the services
* @return the builder
*/
public BackingApplicationBuilder services(List<ServicesSpec> services) {
if (!CollectionUtils.isEmpty(services)) {
this.services.addAll(services);
@@ -266,6 +355,12 @@ public class BackingApplication {
return this;
}
/**
* Services required by the application
*
* @param services the services
* @return the builder
*/
public BackingApplicationBuilder services(ServicesSpec... services) {
if (services != null) {
this.services(Arrays.asList(services));
@@ -273,6 +368,12 @@ public class BackingApplication {
return this;
}
/**
* Parameter transformers for the application
*
* @param parameterTransformers the parameter transformers
* @return the builder
*/
public BackingApplicationBuilder parameterTransformers(List<ParametersTransformerSpec> parameterTransformers) {
if (!CollectionUtils.isEmpty(parameterTransformers)) {
this.parameterTransformers.addAll(parameterTransformers);
@@ -280,6 +381,12 @@ public class BackingApplication {
return this;
}
/**
* Parameter transformers for the application
*
* @param parameterTransformers the parameter transformers
* @return the builder
*/
public BackingApplicationBuilder parameterTransformers(ParametersTransformerSpec... parameterTransformers) {
if (parameterTransformers != null) {
this.parameterTransformers(Arrays.asList(parameterTransformers));
@@ -287,6 +394,12 @@ public class BackingApplication {
return this;
}
/**
* Credential providers for the application
*
* @param credentialProviders the credential providers
* @return the builder
*/
public BackingApplicationBuilder credentialProviders(List<CredentialProviderSpec> credentialProviders) {
if (!CollectionUtils.isEmpty(credentialProviders)) {
this.credentialProviders.addAll(credentialProviders);
@@ -294,6 +407,12 @@ public class BackingApplication {
return this;
}
/**
* Credential providers for the backing application
*
* @param credentialProviders the credential providers
* @return the builder
*/
public BackingApplicationBuilder credentialProviders(CredentialProviderSpec... credentialProviders) {
if (credentialProviders != null) {
this.credentialProviders(Arrays.asList(credentialProviders));
@@ -301,9 +420,16 @@ public class BackingApplication {
return this;
}
/**
* Construct a {@link BackingApplication} from the provided values.
*
* @return the newly constructed {@literal BackingApplication}
*/
public BackingApplication build() {
return new BackingApplication(name, path, properties, environment, services,
parameterTransformers, credentialProviders);
return new BackingApplication(name, path, properties, environment, services, parameterTransformers,
credentialProviders);
}
}
}

View File

@@ -22,12 +22,15 @@ import java.util.List;
import org.springframework.util.CollectionUtils;
public class BackingApplications extends ArrayList<BackingApplication> {
private static final long serialVersionUID = 159473836238657105L;
private BackingApplications() {
super();
}
BackingApplications(List<BackingApplication> backingApplications) {
public BackingApplications(List<BackingApplication> backingApplications) {
super();
super.addAll(backingApplications);
}
@@ -35,7 +38,8 @@ public class BackingApplications extends ArrayList<BackingApplication> {
return new BackingApplicationsBuilder();
}
public static class BackingApplicationsBuilder {
public static final class BackingApplicationsBuilder {
private final List<BackingApplication> backingApplications = new ArrayList<>();
public BackingApplicationsBuilder backingApplication(BackingApplication backingApplication) {
@@ -57,5 +61,7 @@ public class BackingApplications extends ArrayList<BackingApplication> {
public BackingApplications build() {
return new BackingApplications(backingApplications);
}
}
}

View File

@@ -28,23 +28,29 @@ import org.springframework.util.CollectionUtils;
public class BackingService {
private String serviceInstanceName;
private String name;
private String plan;
private Map<String, Object> parameters;
private Map<String, String> properties;
private List<ParametersTransformerSpec> parametersTransformers;
private boolean rebindOnUpdate;
private BackingService() {
}
BackingService(String serviceInstanceName,
String name,
String plan,
Map<String, Object> parameters,
Map<String, String> properties,
List<ParametersTransformerSpec> parametersTransformers,
boolean rebindOnUpdate) {
public BackingService(String serviceInstanceName,
String name,
String plan,
Map<String, Object> parameters,
Map<String, String> properties,
List<ParametersTransformerSpec> parametersTransformers,
boolean rebindOnUpdate) {
this.serviceInstanceName = serviceInstanceName;
this.name = name;
this.plan = plan;
@@ -134,7 +140,8 @@ public class BackingService {
@Override
public int hashCode() {
return Objects.hash(serviceInstanceName, name, plan, parameters, properties, parametersTransformers, rebindOnUpdate);
return Objects
.hash(serviceInstanceName, name, plan, parameters, properties, parametersTransformers, rebindOnUpdate);
}
@Override
@@ -157,14 +164,20 @@ public class BackingService {
public static final class BackingServiceBuilder {
private String serviceInstanceName;
private String name;
private String plan;
private final Map<String, Object> parameters = new HashMap<>();
private final Map<String, String> properties = new HashMap<>();
private final List<ParametersTransformerSpec> parameterTransformers = new ArrayList<>();
private boolean rebindOnUpdate;
BackingServiceBuilder() {
private BackingServiceBuilder() {
}
public BackingServiceBuilder backingService(BackingService backingService) {
@@ -226,8 +239,10 @@ public class BackingService {
}
public BackingService build() {
return new BackingService(serviceInstanceName, name, plan, parameters, properties, parameterTransformers, rebindOnUpdate);
return new BackingService(serviceInstanceName, name, plan, parameters, properties, parameterTransformers,
rebindOnUpdate);
}
}
}

View File

@@ -26,10 +26,11 @@ public class BackingServices extends ArrayList<BackingService> {
private static final long serialVersionUID = 1L;
private BackingServices() {
super();
}
BackingServices(List<BackingService> backingServices) {
super.addAll(backingServices);
public BackingServices(List<BackingService> backingServices) {
super(backingServices);
}
public static BackingServicesBuilder builder() {
@@ -59,5 +60,7 @@ public class BackingServices extends ArrayList<BackingService> {
public BackingServices build() {
return new BackingServices(backingServices);
}
}
}

View File

@@ -27,4 +27,5 @@ public interface BackingServicesProvisionService {
Flux<String> updateServiceInstance(List<BackingService> backingServices);
Flux<String> deleteServiceInstance(List<BackingService> backingServices);
}

View File

@@ -23,15 +23,22 @@ import org.springframework.util.CollectionUtils;
public class BrokeredService {
private String serviceName;
private String planName;
private BackingApplications apps;
private BackingServices services;
private TargetSpec target;
private BrokeredService() {
super();
}
BrokeredService(String serviceName, String planName, BackingApplications apps, BackingServices services, TargetSpec target) {
public BrokeredService(String serviceName, String planName, BackingApplications apps, BackingServices services,
TargetSpec target) {
super();
this.serviceName = serviceName;
this.planName = planName;
this.apps = apps;
@@ -118,9 +125,13 @@ public class BrokeredService {
public static class BrokeredServiceBuilder {
private String id;
private String planId;
private BackingApplications backingApplications;
private BackingServices backingServices;
private TargetSpec target;
public BrokeredServiceBuilder serviceName(String id) {
@@ -159,5 +170,7 @@ public class BrokeredService {
public BrokeredService build() {
return new BrokeredService(id, planId, backingApplications, backingServices, target);
}
}
}

View File

@@ -22,13 +22,15 @@ import java.util.List;
import org.springframework.util.CollectionUtils;
public class BrokeredServices extends ArrayList<BrokeredService> {
private static final long serialVersionUID = 6303127383252611352L;
private BrokeredServices() {
super();
}
BrokeredServices(List<BrokeredService> brokeredServices) {
super.addAll(brokeredServices);
public BrokeredServices(List<BrokeredService> brokeredServices) {
super(brokeredServices);
}
public static BrokeredServicesBuilder builder() {
@@ -36,6 +38,7 @@ public class BrokeredServices extends ArrayList<BrokeredService> {
}
public static class BrokeredServicesBuilder {
private final List<BrokeredService> brokeredServices = new ArrayList<>();
public BrokeredServicesBuilder service(BrokeredService brokeredService) {
@@ -55,5 +58,7 @@ public class BrokeredServices extends ArrayList<BrokeredService> {
public BrokeredServices build() {
return new BrokeredServices(brokeredServices);
}
}
}

View File

@@ -24,12 +24,13 @@ import org.springframework.util.CollectionUtils;
public class CredentialProviderSpec {
private String name;
private Map<String, Object> args;
private CredentialProviderSpec() {
}
CredentialProviderSpec(String name, Map<String, Object> args) {
public CredentialProviderSpec(String name, Map<String, Object> args) {
this.name = name;
this.args = args;
}
@@ -54,13 +55,13 @@ public class CredentialProviderSpec {
return new CredentialProviderSpecBuilder();
}
public static class CredentialProviderSpecBuilder {
public static final class CredentialProviderSpecBuilder {
private String name;
private final Map<String, Object> args = new LinkedHashMap<>();
CredentialProviderSpecBuilder() {
private CredentialProviderSpecBuilder() {
}
public CredentialProviderSpecBuilder spec(CredentialProviderSpec spec) {
@@ -90,5 +91,7 @@ public class CredentialProviderSpec {
public CredentialProviderSpec build() {
return new CredentialProviderSpec(name, args);
}
}
}

View File

@@ -24,6 +24,7 @@ import reactor.util.Logger;
import reactor.util.Loggers;
public class DefaultBackingAppDeploymentService implements BackingAppDeploymentService {
private final Logger log = Loggers.getLogger(DefaultBackingAppDeploymentService.class);
private final DeployerClient deployerClient;
@@ -56,7 +57,8 @@ public class DefaultBackingAppDeploymentService implements BackingAppDeploymentS
.doOnRequest(l -> log.debug("Updating applications {}", backingApps))
.doOnEach(response -> log.debug("Finished updating application {}", response))
.doOnComplete(() -> log.debug("Finished updating application {}", backingApps))
.doOnError(exception -> log.error(String.format("Error updating applications %s with error '%s'", backingApps, exception)));
.doOnError(exception -> log
.error(String.format("Error updating applications %s with error '%s'", backingApps, exception)));
}
@Override
@@ -72,4 +74,5 @@ public class DefaultBackingAppDeploymentService implements BackingAppDeploymentS
.doOnError(exception -> log.error(String.format("Error undeploying applications %s with error '%s'",
backingApps, exception.getMessage()), exception));
}
}

View File

@@ -74,4 +74,5 @@ public class DefaultBackingServicesProvisionService implements BackingServicesPr
.doOnError(exception -> log.error(String.format("Error deleting backing services %s with error '%s'",
backingServices, exception.getMessage()), exception));
}
}

View File

@@ -32,7 +32,7 @@ public class DeployerClient {
this.appDeployer = appDeployer;
}
Mono<String> deploy(BackingApplication backingApplication, String serviceInstanceId) {
public Mono<String> deploy(BackingApplication backingApplication, String serviceInstanceId) {
return appDeployer
.deploy(DeployApplicationRequest
.builder()
@@ -52,7 +52,7 @@ public class DeployerClient {
.map(DeployApplicationResponse::getName);
}
Mono<String> update(BackingApplication backingApplication, String serviceInstanceId) {
public Mono<String> update(BackingApplication backingApplication, String serviceInstanceId) {
return appDeployer
.update(UpdateApplicationRequest
.builder()
@@ -72,7 +72,7 @@ public class DeployerClient {
.map(UpdateApplicationResponse::getName);
}
Mono<String> undeploy(BackingApplication backingApplication) {
public Mono<String> undeploy(BackingApplication backingApplication) {
return appDeployer
.undeploy(UndeployApplicationRequest
.builder()
@@ -89,7 +89,7 @@ public class DeployerClient {
.map(UndeployApplicationResponse::getName);
}
Mono<String> createServiceInstance(BackingService backingService) {
public Mono<String> createServiceInstance(BackingService backingService) {
return appDeployer
.createServiceInstance(
CreateServiceInstanceRequest
@@ -107,7 +107,7 @@ public class DeployerClient {
.map(CreateServiceInstanceResponse::getName);
}
Mono<String> updateServiceInstance(BackingService backingService) {
public Mono<String> updateServiceInstance(BackingService backingService) {
return appDeployer
.updateServiceInstance(
UpdateServiceInstanceRequest
@@ -124,7 +124,7 @@ public class DeployerClient {
.map(UpdateServiceInstanceResponse::getName);
}
Mono<String> deleteServiceInstance(BackingService backingService) {
public Mono<String> deleteServiceInstance(BackingService backingService) {
return appDeployer
.deleteServiceInstance(
DeleteServiceInstanceRequest
@@ -141,4 +141,5 @@ public class DeployerClient {
.build())
.map(DeleteServiceInstanceResponse::getName);
}
}

View File

@@ -30,7 +30,7 @@ public class ParametersTransformerSpec {
private ParametersTransformerSpec() {
}
ParametersTransformerSpec(String name, Map<String, Object> args) {
public ParametersTransformerSpec(String name, Map<String, Object> args) {
this.name = name;
this.args = args;
}
@@ -55,13 +55,13 @@ public class ParametersTransformerSpec {
return new ParametersTransformerSpecBuilder();
}
public static class ParametersTransformerSpecBuilder {
public static final class ParametersTransformerSpecBuilder {
private String name;
private final Map<String, Object> args = new LinkedHashMap<>();
ParametersTransformerSpecBuilder() {
private ParametersTransformerSpecBuilder() {
}
public ParametersTransformerSpecBuilder spec(ParametersTransformerSpec spec) {
@@ -91,5 +91,7 @@ public class ParametersTransformerSpec {
public ParametersTransformerSpec build() {
return new ParametersTransformerSpec(name, args);
}
}
}

View File

@@ -23,7 +23,7 @@ public class ServicesSpec {
private ServicesSpec() {
}
ServicesSpec(String serviceInstanceName) {
public ServicesSpec(String serviceInstanceName) {
this.serviceInstanceName = serviceInstanceName;
}
@@ -39,11 +39,11 @@ public class ServicesSpec {
return new ServicesSpecBuilder();
}
public static class ServicesSpecBuilder {
public static final class ServicesSpecBuilder {
private String serviceInstanceName;
ServicesSpecBuilder() {
private ServicesSpecBuilder() {
}
public ServicesSpecBuilder spec(ServicesSpec spec) {
@@ -58,5 +58,7 @@ public class ServicesSpec {
public ServicesSpec build() {
return new ServicesSpec(serviceInstanceName);
}
}
}

View File

@@ -23,7 +23,7 @@ public class TargetSpec {
private TargetSpec() {
}
TargetSpec(String name) {
public TargetSpec(String name) {
this.name = name;
}
@@ -40,11 +40,11 @@ public class TargetSpec {
return new TargetSpecBuilder();
}
public static class TargetSpecBuilder {
public static final class TargetSpecBuilder {
private String name;
TargetSpecBuilder() {
private TargetSpecBuilder() {
}
public TargetSpecBuilder name(String name) {
@@ -55,5 +55,7 @@ public class TargetSpec {
public TargetSpec build() {
return new TargetSpec(name);
}
}
}

View File

@@ -16,12 +16,13 @@
package org.springframework.cloud.appbroker.extensions;
import org.springframework.cloud.appbroker.extensions.support.ConfigurationBeanUtils;
import java.util.Map;
import java.util.function.Consumer;
import org.springframework.cloud.appbroker.extensions.support.ConfigurationBeanUtils;
public abstract class AbstractExtensionFactory<T, C> implements ExtensionFactory<T, C> {
private Class<C> configClass;
@SuppressWarnings("unchecked")
@@ -42,6 +43,7 @@ public abstract class AbstractExtensionFactory<T, C> implements ExtensionFactory
return create(config);
}
@Override
public T createWithConfig(Map<String, Object> args) {
C config = ConfigurationBeanUtils.instantiate(this.configClass);
ConfigurationBeanUtils.populate(config, args);
@@ -51,4 +53,5 @@ public abstract class AbstractExtensionFactory<T, C> implements ExtensionFactory
protected String getShortName(Class<?> cls) {
return getClass().getSimpleName().replace(cls.getSimpleName(), "");
}
}

View File

@@ -30,4 +30,5 @@ public interface ExtensionFactory<T, C> {
default String getName() {
throw new UnsupportedOperationException("getName() not implemented");
}
}
}

View File

@@ -16,14 +16,15 @@
package org.springframework.cloud.appbroker.extensions;
import org.springframework.cloud.servicebroker.exception.ServiceBrokerException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.cloud.servicebroker.exception.ServiceBrokerException;
public class ExtensionLocator<T> {
private final Map<String, ExtensionFactory<T, ?>> factoriesByName = new HashMap<>();
public ExtensionLocator(List<? extends ExtensionFactory<T, ?>> factories) {
@@ -42,14 +43,16 @@ public class ExtensionLocator<T> {
private ExtensionFactory<T, ?> getFactoryByName(String name) {
if (factoriesByName.containsKey(name)) {
return factoriesByName.get(name);
} else {
}
else {
throw new ServiceBrokerException("Unknown extension " + name + ". " +
"Registered extensions are " + factoriesByName.keySet());
}
}
private T getExtensionFromFactory(ExtensionFactory<T, ?> factory,
Map<String, Object> args) {
Map<String, Object> args) {
return factory.createWithConfig(args);
}
}

View File

@@ -18,10 +18,15 @@ package org.springframework.cloud.appbroker.extensions.credentials;
@SuppressWarnings("WeakerAccess")
public class CredentialGenerationConfig {
private int length;
private boolean includeUppercaseAlpha = true;
private boolean includeLowercaseAlpha = true;
private boolean includeNumeric = true;
private boolean includeSpecial = true;
public int getLength() {
@@ -63,4 +68,5 @@ public class CredentialGenerationConfig {
public void setIncludeSpecial(boolean includeSpecial) {
this.includeSpecial = includeSpecial;
}
}

View File

@@ -22,14 +22,14 @@ import reactor.util.function.Tuple2;
public interface CredentialGenerator {
Mono<Tuple2<String, String>> generateUser(String applicationId, String serviceInstanceId, String descriptor,
int length, boolean includeUppercaseAlpha,
boolean includeLowercaseAlpha, boolean includeNumeric,
boolean includeSpecial);
int length, boolean includeUppercaseAlpha,
boolean includeLowercaseAlpha, boolean includeNumeric,
boolean includeSpecial);
Mono<String> generateString(String applicationId, String serviceInstanceId, String descriptor,
int length, boolean includeUppercaseAlpha,
boolean includeLowercaseAlpha, boolean includeNumeric,
boolean includeSpecial);
int length, boolean includeUppercaseAlpha,
boolean includeLowercaseAlpha, boolean includeNumeric,
boolean includeSpecial);
default Mono<Void> deleteUser(String applicationId, String serviceInstanceId, String descriptor) {
return Mono.empty();
@@ -38,4 +38,5 @@ public interface CredentialGenerator {
default Mono<Void> deleteString(String applicationId, String serviceInstanceId, String descriptor) {
return Mono.empty();
}
}

View File

@@ -16,14 +16,17 @@
package org.springframework.cloud.appbroker.extensions.credentials;
import org.springframework.cloud.appbroker.deployer.BackingApplication;
import reactor.core.publisher.Mono;
import org.springframework.cloud.appbroker.deployer.BackingApplication;
public interface CredentialProvider {
Mono<BackingApplication> addCredentials(BackingApplication backingApplication, String serviceInstanceGuid);
default Mono<BackingApplication> deleteCredentials(BackingApplication backingApplication, String serviceInstanceGuid) {
default Mono<BackingApplication> deleteCredentials(BackingApplication backingApplication,
String serviceInstanceGuid) {
return Mono.just(backingApplication);
}
}

View File

@@ -31,7 +31,9 @@ public abstract class CredentialProviderFactory<C> extends AbstractExtensionFact
@Override
public abstract CredentialProvider create(C config);
@Override
public String getName() {
return getShortName(CredentialProviderFactory.class);
}
}

View File

@@ -16,14 +16,15 @@
package org.springframework.cloud.appbroker.extensions.credentials;
import org.springframework.cloud.appbroker.deployer.BackingApplication;
import org.springframework.cloud.appbroker.deployer.CredentialProviderSpec;
import org.springframework.cloud.appbroker.extensions.ExtensionLocator;
import java.util.Collections;
import java.util.List;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Collections;
import java.util.List;
import org.springframework.cloud.appbroker.deployer.BackingApplication;
import org.springframework.cloud.appbroker.deployer.CredentialProviderSpec;
import org.springframework.cloud.appbroker.extensions.ExtensionLocator;
public class CredentialProviderService {
@@ -34,7 +35,7 @@ public class CredentialProviderService {
}
public Mono<List<BackingApplication>> addCredentials(List<BackingApplication> backingApplications,
String serviceInstanceGuid) {
String serviceInstanceGuid) {
return Flux.fromIterable(backingApplications)
.flatMap(backingApplication -> {
List<CredentialProviderSpec> specs = getSpecsForApplication(backingApplication);
@@ -50,7 +51,7 @@ public class CredentialProviderService {
}
public Mono<List<BackingApplication>> deleteCredentials(List<BackingApplication> backingApplications,
String serviceInstanceGuid) {
String serviceInstanceGuid) {
return Flux.fromIterable(backingApplications)
.flatMap(backingApplication -> {
List<CredentialProviderSpec> specs = getSpecsForApplication(backingApplication);
@@ -70,4 +71,5 @@ public class CredentialProviderService {
? Collections.emptyList()
: backingApplication.getCredentialProviders();
}
}

View File

@@ -26,16 +26,20 @@ import reactor.util.function.Tuples;
public class SimpleCredentialGenerator implements CredentialGenerator {
private static final String UPPERCASE_ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String LOWERCASE_ALPHA = "abcdefghijklmnopqrstuvwxyz";
private static final String DIGITS = "0123456789";
private static final String SPECIAL_CHARACTERS = "~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?";
private final SecureRandom secureRandom = new SecureRandom();
@Override
public Mono<Tuple2<String, String>> generateUser(String applicationId, String serviceInstanceId, String descriptor, int length,
boolean includeUppercaseAlpha, boolean includeLowercaseAlpha,
boolean includeNumeric, boolean includeSpecial) {
public Mono<Tuple2<String, String>> generateUser(String applicationId, String serviceInstanceId, String descriptor,
int length,
boolean includeUppercaseAlpha, boolean includeLowercaseAlpha,
boolean includeNumeric, boolean includeSpecial) {
return generateString(applicationId, serviceInstanceId, descriptor, length,
includeUppercaseAlpha, includeLowercaseAlpha, includeNumeric, includeSpecial)
.flatMap(username -> generateString(applicationId, serviceInstanceId, descriptor, length,
@@ -45,8 +49,8 @@ public class SimpleCredentialGenerator implements CredentialGenerator {
@Override
public Mono<String> generateString(String applicationId, String serviceInstanceId, String descriptor, int length,
boolean includeUppercaseAlpha, boolean includeLowercaseAlpha,
boolean includeNumeric, boolean includeSpecial) {
boolean includeUppercaseAlpha, boolean includeLowercaseAlpha,
boolean includeNumeric, boolean includeSpecial) {
StringBuilder builder = new StringBuilder();
if (includeUppercaseAlpha) {
@@ -67,13 +71,14 @@ public class SimpleCredentialGenerator implements CredentialGenerator {
if (builder.length() == 0) {
builder.append(UPPERCASE_ALPHA)
.append(LOWERCASE_ALPHA)
.append(DIGITS)
.append(SPECIAL_CHARACTERS);
.append(LOWERCASE_ALPHA)
.append(DIGITS)
.append(SPECIAL_CHARACTERS);
}
char[] chars = builder.toString().toCharArray();
return Mono.just(RandomStringUtils.random(length, 0, chars.length - 1, false, false, chars, secureRandom));
}
}

View File

@@ -21,13 +21,20 @@ import reactor.util.function.Tuple2;
import org.springframework.cloud.appbroker.deployer.BackingApplication;
public class SpringSecurityBasicAuthCredentialProviderFactory extends
CredentialProviderFactory<CredentialGenerationConfig> {
public class SpringSecurityBasicAuthCredentialProviderFactory
extends CredentialProviderFactory<CredentialGenerationConfig> {
private static final String CREDENTIAL_DESCRIPTOR = "basic";
static final String SPRING_SECURITY_USER_NAME_KEY = "spring.security.user.name";
static final String SPRING_SECURITY_USER_PASSWORD_KEY = "spring.security.user.password";
/**
* Key for storing the Spring Security Username in the environment
*/
public static final String SPRING_SECURITY_USER_NAME_KEY = "spring.security.user.name";
/**
* Key for storing the Spring Security Password in the environment
*/
public static final String SPRING_SECURITY_USER_PASSWORD_KEY = "spring.security.user.password";
private final CredentialGenerator credentialGenerator;
@@ -41,7 +48,7 @@ public class SpringSecurityBasicAuthCredentialProviderFactory extends
return new CredentialProvider() {
@Override
public Mono<BackingApplication> addCredentials(BackingApplication backingApplication,
String serviceInstanceGuid) {
String serviceInstanceGuid) {
return generateCredentials(config, backingApplication, serviceInstanceGuid)
.flatMap(user -> addUserToEnvironment(backingApplication, user))
.thenReturn(backingApplication);
@@ -49,19 +56,21 @@ public class SpringSecurityBasicAuthCredentialProviderFactory extends
@Override
public Mono<BackingApplication> deleteCredentials(BackingApplication backingApplication,
String serviceInstanceGuid) {
return credentialGenerator.deleteUser(backingApplication.getName(), serviceInstanceGuid, CREDENTIAL_DESCRIPTOR)
.thenReturn(backingApplication);
String serviceInstanceGuid) {
return credentialGenerator
.deleteUser(backingApplication.getName(), serviceInstanceGuid, CREDENTIAL_DESCRIPTOR)
.thenReturn(backingApplication);
}
};
}
private Mono<Tuple2<String, String>> generateCredentials(CredentialGenerationConfig config,
BackingApplication backingApplication,
String serviceInstanceGuid) {
return credentialGenerator.generateUser(backingApplication.getName(), serviceInstanceGuid, CREDENTIAL_DESCRIPTOR,
config.getLength(), config.isIncludeUppercaseAlpha(), config.isIncludeLowercaseAlpha(),
config.isIncludeNumeric(), config.isIncludeSpecial());
BackingApplication backingApplication,
String serviceInstanceGuid) {
return credentialGenerator
.generateUser(backingApplication.getName(), serviceInstanceGuid, CREDENTIAL_DESCRIPTOR,
config.getLength(), config.isIncludeUppercaseAlpha(), config.isIncludeLowercaseAlpha(),
config.isIncludeNumeric(), config.isIncludeSpecial());
}
private Mono<Void> addUserToEnvironment(BackingApplication backingApplication, Tuple2<String, String> user) {
@@ -69,4 +78,5 @@ public class SpringSecurityBasicAuthCredentialProviderFactory extends
backingApplication.addEnvironment(SPRING_SECURITY_USER_PASSWORD_KEY, user.getT2());
return Mono.empty();
}
}

View File

@@ -16,6 +16,10 @@
package org.springframework.cloud.appbroker.extensions.credentials;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
@@ -32,15 +36,27 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
private static final String CREDENTIAL_DESCRIPTOR = "oauth2";
static final String SPRING_SECURITY_OAUTH2_REGISTRATION_KEY = "spring.security.oauth2.client.registration.";
static final String SPRING_SECURITY_OAUTH2_CLIENT_ID_KEY = ".client-id";
static final String SPRING_SECURITY_OAUTH2_CLIENT_SECRET_KEY = ".client-secret";
/**
* Key for storing the Spring Security OAuth2 Registration in the environment
*/
public static final String SPRING_SECURITY_OAUTH2_REGISTRATION_KEY = "spring.security.oauth2.client.registration.";
/**
* Key for storing the Spring Security OAuth2 Client ID in the environment
*/
public static final String SPRING_SECURITY_OAUTH2_CLIENT_ID_KEY = ".client-id";
/**
* Key for storing the Spring Security OAuth2 Client Secret in the environment
*/
public static final String SPRING_SECURITY_OAUTH2_CLIENT_SECRET_KEY = ".client-secret";
private final CredentialGenerator credentialGenerator;
private final OAuth2Client oAuth2Client;
public SpringSecurityOAuth2CredentialProviderFactory(CredentialGenerator credentialGenerator,
OAuth2Client oAuth2Client) {
OAuth2Client oAuth2Client) {
super(Config.class);
this.credentialGenerator = credentialGenerator;
this.oAuth2Client = oAuth2Client;
@@ -51,7 +67,7 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
return new CredentialProvider() {
@Override
public Mono<BackingApplication> addCredentials(BackingApplication backingApplication,
String serviceInstanceGuid) {
String serviceInstanceGuid) {
return generateCredentials(config, backingApplication, serviceInstanceGuid)
.flatMap(client -> addClientToEnvironment(config, backingApplication, client))
.flatMap(client -> createOAuth2Client(config, client))
@@ -60,8 +76,9 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
@Override
public Mono<BackingApplication> deleteCredentials(BackingApplication backingApplication,
String serviceInstanceGuid) {
return credentialGenerator.deleteString(backingApplication.getName(), serviceInstanceGuid, CREDENTIAL_DESCRIPTOR)
String serviceInstanceGuid) {
return credentialGenerator
.deleteString(backingApplication.getName(), serviceInstanceGuid, CREDENTIAL_DESCRIPTOR)
.then(generateClientId(config, backingApplication, serviceInstanceGuid))
.flatMap(clientId -> deleteOAuth2Client(config, clientId)
.flatMap(response -> Mono.just(backingApplication)));
@@ -70,16 +87,16 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
}
private Mono<Tuple2<String, String>> generateCredentials(Config config,
BackingApplication backingApplication,
String serviceInstanceGuid) {
BackingApplication backingApplication,
String serviceInstanceGuid) {
return generateClientId(config, backingApplication, serviceInstanceGuid)
.flatMap(id -> generateClientSecret(config, backingApplication, serviceInstanceGuid)
.map(secret -> Tuples.of(id, secret)));
}
private Mono<Tuple2<String, String>> addClientToEnvironment(Config config,
BackingApplication backingApplication,
Tuple2<String, String> client) {
BackingApplication backingApplication,
Tuple2<String, String> client) {
String registrationKey = SPRING_SECURITY_OAUTH2_REGISTRATION_KEY + config.getRegistration();
backingApplication.addEnvironment(registrationKey + SPRING_SECURITY_OAUTH2_CLIENT_ID_KEY, client.getT1());
@@ -89,7 +106,7 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
}
private Mono<String> generateClientId(Config config, BackingApplication backingApplication,
String serviceInstanceGuid) {
String serviceInstanceGuid) {
return Mono.defer(() -> {
if (config.clientId == null) {
return Mono.just(backingApplication.getName() + "-" + serviceInstanceGuid);
@@ -99,9 +116,10 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
}
private Mono<String> generateClientSecret(Config config, BackingApplication backingApplication,
String serviceInstanceGuid) {
String serviceInstanceGuid) {
return credentialGenerator.generateString(backingApplication.getName(), serviceInstanceGuid,
CREDENTIAL_DESCRIPTOR, config.getLength(), config.isIncludeUppercaseAlpha(), config.isIncludeLowercaseAlpha(),
CREDENTIAL_DESCRIPTOR, config.getLength(), config.isIncludeUppercaseAlpha(),
config.isIncludeLowercaseAlpha(),
config.isIncludeNumeric(), config.isIncludeSpecial());
}
@@ -140,13 +158,21 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
@SuppressWarnings("WeakerAccess")
public static class Config extends CredentialGenerationConfig {
private String registration;
private String clientId;
private String clientName;
private String[] scopes;
private String[] authorities;
private String[] grantTypes;
private final List<String> scopes = new ArrayList<>();
private final List<String> authorities = new ArrayList<>();
private final List<String> grantTypes = new ArrayList<>();
private String identityZoneSubdomain;
private String identityZoneId;
public String getRegistration() {
@@ -173,28 +199,34 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
this.clientName = clientName;
}
public String[] getScopes() {
public List<String> getScopes() {
return scopes;
}
public void setScopes(String... scopes) {
this.scopes = scopes;
if (scopes != null) {
this.scopes.addAll(Arrays.asList(scopes));
}
}
public String[] getAuthorities() {
public List<String> getAuthorities() {
return authorities;
}
public void setAuthorities(String... authorities) {
this.authorities = authorities;
if (authorities != null) {
this.authorities.addAll(Arrays.asList(authorities));
}
}
public String[] getGrantTypes() {
public List<String> getGrantTypes() {
return grantTypes;
}
public void setGrantTypes(String... grantTypes) {
this.grantTypes = grantTypes;
if (grantTypes != null) {
this.grantTypes.addAll(Arrays.asList(grantTypes));
}
}
public String getIdentityZoneSubdomain() {
@@ -212,5 +244,7 @@ public class SpringSecurityOAuth2CredentialProviderFactory extends
public void setIdentityZoneId(String identityZoneId) {
this.identityZoneId = identityZoneId;
}
}
}

View File

@@ -37,24 +37,25 @@ public class BackingApplicationsParametersTransformationService {
}
public Mono<List<BackingApplication>> transformParameters(List<BackingApplication> backingApplications,
Map<String, Object> parameters) {
Map<String, Object> parameters) {
return Flux.fromIterable(backingApplications)
.flatMap(backingApplication -> {
List<ParametersTransformerSpec> specs = getTransformerSpecsForApplication(backingApplication);
.flatMap(backingApplication -> {
List<ParametersTransformerSpec> specs = getTransformerSpecsForApplication(backingApplication);
return Flux.fromIterable(specs)
.flatMap(spec -> {
ParametersTransformer<BackingApplication> transformer = locator.getByName(spec.getName(), spec.getArgs());
return transformer.transform(backingApplication, parameters);
})
.then(Mono.just(backingApplication));
})
.collectList();
return Flux.fromIterable(specs)
.flatMap(spec -> {
ParametersTransformer<BackingApplication> transformer = locator
.getByName(spec.getName(), spec.getArgs());
return transformer.transform(backingApplication, parameters);
})
.then(Mono.just(backingApplication));
})
.collectList();
}
private List<ParametersTransformerSpec> getTransformerSpecsForApplication(BackingApplication backingApplication) {
return backingApplication.getParametersTransformers() == null
? Collections.emptyList()
: backingApplication.getParametersTransformers();
return backingApplication.getParametersTransformers() == null ? Collections.emptyList() :
backingApplication.getParametersTransformers();
}
}

View File

@@ -37,19 +37,20 @@ public class BackingServicesParametersTransformationService {
}
public Mono<List<BackingService>> transformParameters(List<BackingService> backingServices,
Map<String, Object> parameters) {
Map<String, Object> parameters) {
return Flux.fromIterable(backingServices)
.flatMap(backingService -> {
List<ParametersTransformerSpec> specs = getTransformerSpecsForService(backingService);
.flatMap(backingService -> {
List<ParametersTransformerSpec> specs = getTransformerSpecsForService(backingService);
return Flux.fromIterable(specs)
.flatMap(spec -> {
ParametersTransformer<BackingService> transformer = locator.getByName(spec.getName(), spec.getArgs());
return transformer.transform(backingService, parameters);
})
.then(Mono.just(backingService));
})
.collectList();
return Flux.fromIterable(specs)
.flatMap(spec -> {
ParametersTransformer<BackingService> transformer = locator
.getByName(spec.getName(), spec.getArgs());
return transformer.transform(backingService, parameters);
})
.then(Mono.just(backingService));
})
.collectList();
}
private List<ParametersTransformerSpec> getTransformerSpecsForService(BackingService backingService) {
@@ -57,4 +58,5 @@ public class BackingServicesParametersTransformationService {
? Collections.emptyList()
: backingService.getParametersTransformers();
}
}

View File

@@ -32,6 +32,7 @@ public class EnvironmentMappingParametersTransformerFactory extends
ParametersTransformerFactory<BackingApplication, EnvironmentMappingParametersTransformerFactory.Config> {
private final Logger logger = Loggers.getLogger(EnvironmentMappingParametersTransformerFactory.class);
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public EnvironmentMappingParametersTransformerFactory() {
@@ -44,8 +45,8 @@ public class EnvironmentMappingParametersTransformerFactory extends
}
private Mono<BackingApplication> transform(BackingApplication backingApplication,
Map<String, Object> parameters,
List<String> include) {
Map<String, Object> parameters,
List<String> include) {
if (parameters != null) {
parameters
.keySet().stream()
@@ -77,9 +78,6 @@ public class EnvironmentMappingParametersTransformerFactory extends
private String include;
public Config() {
}
public List<String> getIncludes() {
return Arrays.asList(include.split(","));
}
@@ -87,5 +85,7 @@ public class EnvironmentMappingParametersTransformerFactory extends
public void setInclude(String include) {
this.include = include;
}
}
}

View File

@@ -37,12 +37,12 @@ public class ParameterMappingParametersTransformerFactory extends
}
private Mono<BackingService> transform(BackingService backingService,
Map<String, Object> parameters,
List<String> include) {
Map<String, Object> parameters,
List<String> include) {
if (parameters != null) {
parameters.keySet().stream()
.filter(include::contains)
.forEach(key -> backingService.addParameter(key, parameters.get(key)));
.filter(include::contains)
.forEach(key -> backingService.addParameter(key, parameters.get(key)));
}
return Mono.just(backingService);
@@ -53,9 +53,6 @@ public class ParameterMappingParametersTransformerFactory extends
private String include;
public Config() {
}
public List<String> getIncludes() {
return Arrays.asList(include.split(","));
}
@@ -63,5 +60,7 @@ public class ParameterMappingParametersTransformerFactory extends
public void setInclude(String include) {
this.include = include;
}
}
}

View File

@@ -19,6 +19,7 @@ package org.springframework.cloud.appbroker.extensions.parameters;
import org.springframework.cloud.appbroker.extensions.AbstractExtensionFactory;
public abstract class ParametersTransformerFactory<B, C> extends AbstractExtensionFactory<ParametersTransformer<B>, C> {
protected ParametersTransformerFactory() {
super();
}
@@ -30,7 +31,9 @@ public abstract class ParametersTransformerFactory<B, C> extends AbstractExtensi
@Override
public abstract ParametersTransformer<B> create(C config);
@Override
public String getName() {
return getShortName(ParametersTransformerFactory.class);
}
}

View File

@@ -37,12 +37,12 @@ public class PropertyMappingParametersTransformerFactory extends
}
private Mono<BackingApplication> transform(BackingApplication backingApplication,
Map<String, Object> parameters,
List<String> include) {
Map<String, Object> parameters,
List<String> include) {
if (parameters != null) {
parameters.keySet().stream()
.filter(include::contains)
.forEach(key -> backingApplication.addProperty(key, parameters.get(key).toString()));
.filter(include::contains)
.forEach(key -> backingApplication.addProperty(key, parameters.get(key).toString()));
}
return Mono.just(backingApplication);
}
@@ -52,9 +52,6 @@ public class PropertyMappingParametersTransformerFactory extends
private String include;
public Config() {
}
public List<String> getIncludes() {
return Arrays.asList(include.split(","));
}
@@ -62,5 +59,7 @@ public class PropertyMappingParametersTransformerFactory extends
public void setInclude(String include) {
this.include = include;
}
}
}

View File

@@ -16,15 +16,16 @@
package org.springframework.cloud.appbroker.extensions.support;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.DefaultBeanIntrospector;
import org.apache.commons.beanutils.SuppressPropertiesBeanIntrospector;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public final class ConfigurationBeanUtils {
private ConfigurationBeanUtils() {
@@ -38,7 +39,7 @@ public final class ConfigurationBeanUtils {
if (properties == null) {
return;
}
T target = getTargetObject(targetObject);
try {
@@ -47,13 +48,14 @@ public final class ConfigurationBeanUtils {
beanUtils.getPropertyUtils().addBeanIntrospector(new KebabCasePropertyBeanIntrospector());
beanUtils.getPropertyUtils().addBeanIntrospector(SuppressPropertiesBeanIntrospector.SUPPRESS_CLASS);
beanUtils.copyProperties(target, properties);
} catch (IllegalAccessException | InvocationTargetException e) {
}
catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalArgumentException("Failed to populate target of type " + targetObject.getClass()
+ " with properties " + properties, e);
}
}
@SuppressWarnings({"unchecked","PMD.AvoidCatchingGenericException"})
@SuppressWarnings({"unchecked", "PMD.AvoidCatchingGenericException"})
private static <T> T getTargetObject(Object candidate) {
try {
if (AopUtils.isAopProxy(candidate) && candidate instanceof Advised) {
@@ -65,4 +67,5 @@ public final class ConfigurationBeanUtils {
}
return (T) candidate;
}
}
}

View File

@@ -15,49 +15,40 @@
*/
package org.springframework.cloud.appbroker.extensions.support;
import org.apache.commons.beanutils.BeanIntrospector;
import org.apache.commons.beanutils.DefaultBeanIntrospector;
import org.apache.commons.beanutils.IntrospectionContext;
import reactor.util.Logger;
import reactor.util.Loggers;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Locale;
import org.apache.commons.beanutils.BeanIntrospector;
import org.apache.commons.beanutils.DefaultBeanIntrospector;
import org.apache.commons.beanutils.IntrospectionContext;
import reactor.util.Logger;
import reactor.util.Loggers;
/**
* An implementation of the {@link BeanIntrospector} interface that provides property descriptors following the
* kebab-case convention.
* <p>
* An implementation of the {@link BeanIntrospector} interface that provides property descriptors
* following the kebab-case convention.
* </p>
*
* This implementation is intended to collaborate with a {@link DefaultBeanIntrospector} object.
* Best results are achieved by adding this instance as custom {@link BeanIntrospector} after the
* {@link DefaultBeanIntrospector} object.
* This implementation is intended to collaborate with a {@link DefaultBeanIntrospector} object. Best results are
* achieved by adding this instance as custom {@link BeanIntrospector} after the {@link DefaultBeanIntrospector}
* object.
*/
public class KebabCasePropertyBeanIntrospector implements BeanIntrospector {
private static final Logger LOG = Loggers.getLogger(KebabCasePropertyBeanIntrospector.class);
private static final String WRITE_METHOD_PREFIX = "set";
private final Logger log = Loggers.getLogger(getClass());
/**
* Creates a new instance of <code>KebabCaseBeanIntrospector</code> and
* sets the default prefix for write methods.
*/
KebabCasePropertyBeanIntrospector() {
}
/**
* Performs introspection. This method scans the current class's methods for
* property write methods add adds a property descriptor using the kebab-case
* naming convention to match each property descriptor that uses the camel-case
* Java Bean convention.
* Performs introspection. This method scans the current class's methods for property write methods add adds a
* property descriptor using the kebab-case naming convention to match each property descriptor that uses the
* camel-case Java Bean convention.
*
* @param context the introspection context
*/
@Override
public void introspect(final IntrospectionContext context) {
for (final Method m : context.getTargetClass().getMethods()) {
if (m.getName().startsWith(WRITE_METHOD_PREFIX)) {
@@ -67,9 +58,12 @@ public class KebabCasePropertyBeanIntrospector implements BeanIntrospector {
if (pd != null) {
context.addPropertyDescriptor(createPropertyDescriptor(m));
}
} catch (final IntrospectionException e) {
log.error("Error when creating PropertyDescriptor for method '{}'. " +
}
catch (final IntrospectionException e) {
if (LOG.isErrorEnabled()) {
LOG.error("Error when creating PropertyDescriptor for method '{}'. " +
"This property will be ignored. {}", m, e);
}
}
}
}
@@ -96,16 +90,17 @@ public class KebabCasePropertyBeanIntrospector implements BeanIntrospector {
*/
private String kebabCasePropertyName(final Method m) {
final String methodName = camelCasePropertyName(m);
StringBuilder builder = new StringBuilder();
for (char c : methodName.toCharArray()) {
if (Character.isUpperCase(c)) {
builder.append('-').append(Character.toLowerCase(c));
} else {
}
else {
builder.append(c);
}
}
return builder.toString();
}
@@ -120,4 +115,5 @@ public class KebabCasePropertyBeanIntrospector implements BeanIntrospector {
String propertyName = kebabCasePropertyName(m);
return new PropertyDescriptor(propertyName, null, m);
}
}
}

View File

@@ -24,9 +24,10 @@ import org.springframework.util.CollectionUtils;
public class ArtifactDetails {
private final String name;
private final Map<String, String> properties;
ArtifactDetails(String name, Map<String, String> properties) {
public ArtifactDetails(String name, Map<String, String> properties) {
this.name = name;
this.properties = properties;
}
@@ -46,9 +47,10 @@ public class ArtifactDetails {
public static final class ArtifactDetailsBuilder {
private String name;
private final Map<String, String> properties = new HashMap<>();
ArtifactDetailsBuilder() {
private ArtifactDetailsBuilder() {
}
public ArtifactDetailsBuilder name(String name) {

View File

@@ -36,7 +36,7 @@ public class ServiceInstanceGuidSuffix extends TargetFactory<ServiceInstanceGuid
.build();
}
static class Config {
public static class Config {
}
}

View File

@@ -41,7 +41,7 @@ public class SpacePerServiceInstance extends TargetFactory<SpacePerServiceInstan
.build();
}
static class Config {
public static class Config {
}
}

View File

@@ -21,4 +21,5 @@ import java.util.Map;
public interface Target {
ArtifactDetails apply(Map<String, String> properties, String name, String serviceInstanceId);
}

View File

@@ -20,18 +20,20 @@ import org.springframework.cloud.appbroker.extensions.AbstractExtensionFactory;
public abstract class TargetFactory<C> extends AbstractExtensionFactory<Target, C> {
TargetFactory() {
protected TargetFactory() {
super();
}
TargetFactory(Class<C> configClass) {
public TargetFactory(Class<C> configClass) {
super(configClass);
}
@Override
public abstract Target create(C config);
@Override
public String getName() {
return getShortName(TargetFactory.class);
}
}

View File

@@ -37,8 +37,7 @@ public class TargetService {
}
public Mono<List<BackingApplication>> addToBackingApplications(List<BackingApplication> backingApplications,
TargetSpec targetSpec,
String serviceInstanceId) {
TargetSpec targetSpec, String serviceInstanceId) {
return Flux.fromIterable(backingApplications)
.flatMap(backingApplication -> {
if (targetSpec != null) {
@@ -59,8 +58,8 @@ public class TargetService {
}
public Mono<List<BackingService>> addToBackingServices(List<BackingService> backingServices,
TargetSpec targetSpec,
String serviceInstanceId) {
TargetSpec targetSpec,
String serviceInstanceId) {
return Flux.fromIterable(backingServices)
.flatMap(backingService -> {
if (targetSpec != null) {
@@ -75,8 +74,9 @@ public class TargetService {
}
private ArtifactDetails getArtifactDetails(TargetSpec targetSpec, String serviceInstanceId,
String name, Map<String, String> properties) {
String name, Map<String, String> properties) {
Target target = locator.getByName(targetSpec.getName());
return target.apply(properties, name, serviceInstanceId);
}
}

View File

@@ -24,7 +24,7 @@ import org.springframework.cloud.appbroker.deployer.BackingApplication;
public class ManagementClient {
private final Logger log = Loggers.getLogger(ManagementClient.class);
private static final Logger LOG = Loggers.getLogger(ManagementClient.class);
private final AppManager appManager;
@@ -32,51 +32,52 @@ public class ManagementClient {
this.appManager = appManager;
}
Mono<Void> start(BackingApplication backingApplication) {
public Mono<Void> start(BackingApplication backingApplication) {
return Mono.justOrEmpty(backingApplication)
.flatMap(backingApp -> appManager.start(StartApplicationRequest.builder()
.name(backingApp.getName())
.properties(backingApp.getProperties())
.build())
.doOnRequest(l -> log.debug("Starting application {}", backingApp))
.doOnSuccess(response -> log.debug("Finished starting application {}", backingApp))
.doOnError(exception -> log.error(String.format("Error starting application %s with error '%s'",
.doOnRequest(l -> LOG.debug("Starting application {}", backingApp))
.doOnSuccess(response -> LOG.debug("Finished starting application {}", backingApp))
.doOnError(exception -> LOG.error(String.format("Error starting application %s with error '%s'",
backingApp, exception.getMessage()), exception)));
}
Mono<Void> stop(BackingApplication backingApplication) {
public Mono<Void> stop(BackingApplication backingApplication) {
return Mono.justOrEmpty(backingApplication)
.flatMap(backingApp -> appManager.stop(StopApplicationRequest.builder()
.name(backingApp.getName())
.properties(backingApp.getProperties())
.build())
.doOnRequest(l -> log.debug("Stopping application {}", backingApp))
.doOnSuccess(response -> log.debug("Finished stopping application {}", backingApp))
.doOnError(exception -> log.error(String.format("Error stopping application %s with error '%s'",
.doOnRequest(l -> LOG.debug("Stopping application {}", backingApp))
.doOnSuccess(response -> LOG.debug("Finished stopping application {}", backingApp))
.doOnError(exception -> LOG.error(String.format("Error stopping application %s with error '%s'",
backingApp, exception.getMessage()), exception)));
}
Mono<Void> restart(BackingApplication backingApplication) {
public Mono<Void> restart(BackingApplication backingApplication) {
return Mono.justOrEmpty(backingApplication)
.flatMap(backingApp -> appManager.restart(RestartApplicationRequest.builder()
.name(backingApp.getName())
.properties(backingApp.getProperties())
.build())
.doOnRequest(l -> log.debug("Restarting application {}", backingApp))
.doOnSuccess(response -> log.debug("Finished restarting application {}", backingApp))
.doOnError(exception -> log.error(String.format("Error restarting application %s with error '%s'",
.doOnRequest(l -> LOG.debug("Restarting application {}", backingApp))
.doOnSuccess(response -> LOG.debug("Finished restarting application {}", backingApp))
.doOnError(exception -> LOG.error(String.format("Error restarting application %s with error '%s'",
backingApp, exception.getMessage()), exception)));
}
Mono<Void> restage(BackingApplication backingApplication) {
public Mono<Void> restage(BackingApplication backingApplication) {
return Mono.justOrEmpty(backingApplication)
.flatMap(backingApp -> appManager.restage(RestageApplicationRequest.builder()
.name(backingApp.getName())
.properties(backingApp.getProperties())
.build())
.doOnRequest(l -> log.debug("Restaging application {}", backingApp))
.doOnSuccess(response -> log.debug("Finished restaging application {}", backingApp))
.doOnError(exception -> log.error(String.format("Error restaging application %s with error '%s'",
.doOnRequest(l -> LOG.debug("Restaging application {}", backingApp))
.doOnSuccess(response -> LOG.debug("Finished restaging application {}", backingApp))
.doOnError(exception -> LOG.error(String.format("Error restaging application %s with error '%s'",
backingApp, exception.getMessage()), exception)));
}
}

View File

@@ -18,13 +18,14 @@ package org.springframework.cloud.appbroker.service;
import reactor.core.publisher.Mono;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse.CreateServiceInstanceAppBindingResponseBuilder;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse;
public interface CreateServiceInstanceAppBindingWorkflow {
default Mono<Void> create(CreateServiceInstanceBindingRequest request,
CreateServiceInstanceAppBindingResponse response) {
CreateServiceInstanceAppBindingResponse response) {
return Mono.empty();
}
@@ -32,8 +33,10 @@ public interface CreateServiceInstanceAppBindingWorkflow {
return Mono.just(true);
}
default Mono<CreateServiceInstanceAppBindingResponseBuilder> buildResponse(CreateServiceInstanceBindingRequest request,
CreateServiceInstanceAppBindingResponseBuilder responseBuilder) {
default Mono<CreateServiceInstanceAppBindingResponseBuilder> buildResponse(
CreateServiceInstanceBindingRequest request,
CreateServiceInstanceAppBindingResponseBuilder responseBuilder) {
return Mono.just(responseBuilder);
}
}

View File

@@ -19,12 +19,13 @@ package org.springframework.cloud.appbroker.service;
import reactor.core.publisher.Mono;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceRouteBindingResponse.CreateServiceInstanceRouteBindingResponseBuilder;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceRouteBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceRouteBindingResponse.CreateServiceInstanceRouteBindingResponseBuilder;
public interface CreateServiceInstanceRouteBindingWorkflow {
default Mono<Void> create(CreateServiceInstanceBindingRequest request,
CreateServiceInstanceRouteBindingResponse response) {
CreateServiceInstanceRouteBindingResponse response) {
return Mono.empty();
}
@@ -32,8 +33,10 @@ public interface CreateServiceInstanceRouteBindingWorkflow {
return Mono.just(true);
}
default Mono<CreateServiceInstanceRouteBindingResponseBuilder> buildResponse(CreateServiceInstanceBindingRequest request,
CreateServiceInstanceRouteBindingResponseBuilder responseBuilder) {
default Mono<CreateServiceInstanceRouteBindingResponseBuilder> buildResponse(
CreateServiceInstanceBindingRequest request,
CreateServiceInstanceRouteBindingResponseBuilder responseBuilder) {
return Mono.just(responseBuilder);
}
}

View File

@@ -19,12 +19,13 @@ package org.springframework.cloud.appbroker.service;
import reactor.core.publisher.Mono;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse.CreateServiceInstanceResponseBuilder;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse.CreateServiceInstanceResponseBuilder;
public interface CreateServiceInstanceWorkflow {
default Mono<Void> create(CreateServiceInstanceRequest request,
CreateServiceInstanceResponse response) {
CreateServiceInstanceResponse response) {
return Mono.empty();
}
@@ -33,7 +34,8 @@ public interface CreateServiceInstanceWorkflow {
}
default Mono<CreateServiceInstanceResponseBuilder> buildResponse(CreateServiceInstanceRequest request,
CreateServiceInstanceResponseBuilder responseBuilder) {
CreateServiceInstanceResponseBuilder responseBuilder) {
return Mono.just(responseBuilder);
}
}

View File

@@ -19,12 +19,13 @@ package org.springframework.cloud.appbroker.service;
import reactor.core.publisher.Mono;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse.DeleteServiceInstanceBindingResponseBuilder;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse.DeleteServiceInstanceBindingResponseBuilder;
public interface DeleteServiceInstanceBindingWorkflow {
default Mono<Void> delete(DeleteServiceInstanceBindingRequest request,
DeleteServiceInstanceBindingResponse response) {
DeleteServiceInstanceBindingResponse response) {
return Mono.empty();
}
@@ -33,7 +34,8 @@ public interface DeleteServiceInstanceBindingWorkflow {
}
default Mono<DeleteServiceInstanceBindingResponseBuilder> buildResponse(DeleteServiceInstanceBindingRequest request,
DeleteServiceInstanceBindingResponseBuilder responseBuilder) {
DeleteServiceInstanceBindingResponseBuilder responseBuilder) {
return Mono.just(responseBuilder);
}
}

View File

@@ -23,6 +23,7 @@ import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInsta
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse.DeleteServiceInstanceResponseBuilder;
public interface DeleteServiceInstanceWorkflow {
default Mono<Void> delete(DeleteServiceInstanceRequest request, DeleteServiceInstanceResponse response) {
return Mono.empty();
}
@@ -32,7 +33,8 @@ public interface DeleteServiceInstanceWorkflow {
}
default Mono<DeleteServiceInstanceResponseBuilder> buildResponse(DeleteServiceInstanceRequest request,
DeleteServiceInstanceResponseBuilder responseBuilder) {
DeleteServiceInstanceResponseBuilder responseBuilder) {
return Mono.just(responseBuilder);
}
}

View File

@@ -23,6 +23,7 @@ import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInsta
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse.UpdateServiceInstanceResponseBuilder;
public interface UpdateServiceInstanceWorkflow {
default Mono<Void> update(UpdateServiceInstanceRequest request, UpdateServiceInstanceResponse response) {
return Mono.empty();
}
@@ -32,7 +33,8 @@ public interface UpdateServiceInstanceWorkflow {
}
default Mono<UpdateServiceInstanceResponseBuilder> buildResponse(UpdateServiceInstanceRequest request,
UpdateServiceInstanceResponseBuilder responseBuilder) {
UpdateServiceInstanceResponseBuilder responseBuilder) {
return Mono.just(responseBuilder);
}
}

View File

@@ -47,7 +47,7 @@ import org.springframework.util.StringUtils;
public class WorkflowServiceInstanceBindingService implements ServiceInstanceBindingService {
private final Logger log = Loggers.getLogger(WorkflowServiceInstanceBindingService.class);
private static final Logger LOG = Loggers.getLogger(WorkflowServiceInstanceBindingService.class);
private final ServiceInstanceBindingStateRepository stateRepository;
@@ -58,10 +58,10 @@ public class WorkflowServiceInstanceBindingService implements ServiceInstanceBin
private final List<DeleteServiceInstanceBindingWorkflow> deleteServiceInstanceBindingWorkflows = new ArrayList<>();
public WorkflowServiceInstanceBindingService(
ServiceInstanceBindingStateRepository serviceInstanceBindingStateRepository,
List<CreateServiceInstanceAppBindingWorkflow> createServiceInstanceAppBindingWorkflows,
List<CreateServiceInstanceRouteBindingWorkflow> createServiceInstanceRouteBindingWorkflows,
List<DeleteServiceInstanceBindingWorkflow> deleteServiceInstanceBindingWorkflows) {
ServiceInstanceBindingStateRepository serviceInstanceBindingStateRepository,
List<CreateServiceInstanceAppBindingWorkflow> createServiceInstanceAppBindingWorkflows,
List<CreateServiceInstanceRouteBindingWorkflow> createServiceInstanceRouteBindingWorkflows,
List<DeleteServiceInstanceBindingWorkflow> deleteServiceInstanceBindingWorkflows) {
this.stateRepository = serviceInstanceBindingStateRepository;
if (!CollectionUtils.isEmpty(createServiceInstanceAppBindingWorkflows)) {
this.createServiceInstanceAppBindingWorkflows.addAll(createServiceInstanceAppBindingWorkflows);
@@ -78,24 +78,29 @@ public class WorkflowServiceInstanceBindingService implements ServiceInstanceBin
}
@Override
public Mono<CreateServiceInstanceBindingResponse> createServiceInstanceBinding(CreateServiceInstanceBindingRequest request) {
public Mono<CreateServiceInstanceBindingResponse> createServiceInstanceBinding(
CreateServiceInstanceBindingRequest request) {
return invokeCreateResponseBuilders(request)
.publishOn(Schedulers.parallel())
.doOnNext(response -> create(request, response)
.subscribe());
}
private Mono<CreateServiceInstanceBindingResponse> invokeCreateResponseBuilders(CreateServiceInstanceBindingRequest request) {
private Mono<CreateServiceInstanceBindingResponse> invokeCreateResponseBuilders(
CreateServiceInstanceBindingRequest request) {
return Mono.defer(() -> {
if (isAppBindingRequest(request)) {
CreateServiceInstanceAppBindingResponseBuilder builder = CreateServiceInstanceAppBindingResponse.builder();
CreateServiceInstanceAppBindingResponseBuilder builder = CreateServiceInstanceAppBindingResponse
.builder();
return invokeAppBindingBuildResponse(builder, request, this.createServiceInstanceAppBindingWorkflows)
.last(builder)
.map(CreateServiceInstanceAppBindingResponseBuilder::build);
}
else if (isRouteBindingRequest(request)) {
CreateServiceInstanceRouteBindingResponseBuilder builder = CreateServiceInstanceRouteBindingResponse.builder();
return invokeRouteBindingBuildResponse(builder, request, this.createServiceInstanceRouteBindingWorkflows)
CreateServiceInstanceRouteBindingResponseBuilder builder = CreateServiceInstanceRouteBindingResponse
.builder();
return invokeRouteBindingBuildResponse(builder, request,
this.createServiceInstanceRouteBindingWorkflows)
.last(builder)
.map(CreateServiceInstanceRouteBindingResponseBuilder::build);
}
@@ -103,51 +108,58 @@ public class WorkflowServiceInstanceBindingService implements ServiceInstanceBin
});
}
Flux<CreateServiceInstanceAppBindingResponseBuilder> invokeAppBindingBuildResponse(CreateServiceInstanceAppBindingResponseBuilder builder, CreateServiceInstanceBindingRequest request, List<CreateServiceInstanceAppBindingWorkflow> workflows) {
AtomicReference<CreateServiceInstanceAppBindingResponseBuilder> responseBuilder = new AtomicReference<>(builder);
private Flux<CreateServiceInstanceAppBindingResponseBuilder> invokeAppBindingBuildResponse(
CreateServiceInstanceAppBindingResponseBuilder builder, CreateServiceInstanceBindingRequest request,
List<CreateServiceInstanceAppBindingWorkflow> workflows) {
AtomicReference<CreateServiceInstanceAppBindingResponseBuilder> responseBuilder = new AtomicReference<>(
builder);
return Flux.fromIterable(workflows)
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.buildResponse(request, responseBuilder.get())
.doOnNext(responseBuilder::set));
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.buildResponse(request, responseBuilder.get())
.doOnNext(responseBuilder::set));
}
Flux<CreateServiceInstanceRouteBindingResponseBuilder> invokeRouteBindingBuildResponse(CreateServiceInstanceRouteBindingResponseBuilder builder, CreateServiceInstanceBindingRequest request, List<CreateServiceInstanceRouteBindingWorkflow> workflows) {
AtomicReference<CreateServiceInstanceRouteBindingResponseBuilder> responseBuilder = new AtomicReference<>(builder);
private Flux<CreateServiceInstanceRouteBindingResponseBuilder> invokeRouteBindingBuildResponse(
CreateServiceInstanceRouteBindingResponseBuilder builder, CreateServiceInstanceBindingRequest request,
List<CreateServiceInstanceRouteBindingWorkflow> workflows) {
AtomicReference<CreateServiceInstanceRouteBindingResponseBuilder> responseBuilder = new AtomicReference<>(
builder);
return Flux.fromIterable(workflows)
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.buildResponse(request, responseBuilder.get())
.doOnNext(responseBuilder::set));
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.buildResponse(request, responseBuilder.get())
.doOnNext(responseBuilder::set));
}
private boolean isAppBindingRequest(CreateServiceInstanceBindingRequest request) {
return request.getBindResource() != null
&& StringUtils.isEmpty(request.getBindResource().getRoute());
&& StringUtils.isEmpty(request.getBindResource().getRoute());
}
private boolean isRouteBindingRequest(CreateServiceInstanceBindingRequest request) {
return request.getBindResource() != null
&& StringUtils.hasText(request.getBindResource().getRoute());
&& StringUtils.hasText(request.getBindResource().getRoute());
}
private Mono<Void> create(CreateServiceInstanceBindingRequest request,
CreateServiceInstanceBindingResponse response) {
CreateServiceInstanceBindingResponse response) {
return stateRepository.saveState(request.getServiceInstanceId(), request.getBindingId(),
OperationState.IN_PROGRESS, "create service instance binding started")
.thenMany(invokeCreateWorkflows(request, response)
.doOnRequest(l -> log.debug("Creating service instance binding"))
.doOnComplete(() -> log.debug("Finished creating service instance binding"))
.doOnError(exception -> log.error(String.format("Error creating service instance binding with error '%s'",
exception.getMessage()), exception)))
.doOnRequest(l -> LOG.debug("Creating service instance binding"))
.doOnComplete(() -> LOG.debug("Finished creating service instance binding"))
.doOnError(exception -> LOG.error(String.format("Error creating service instance binding with error " +
"'%s'", exception.getMessage()), exception)))
.thenEmpty(stateRepository.saveState(request.getServiceInstanceId(), request.getBindingId(),
OperationState.SUCCEEDED, "create service instance binding completed")
.then())
.onErrorResume(exception -> stateRepository.saveState(request.getServiceInstanceId(), request.getBindingId(),
OperationState.FAILED, exception.getMessage())
.then());
.onErrorResume(
exception -> stateRepository.saveState(request.getServiceInstanceId(), request.getBindingId(),
OperationState.FAILED, exception.getMessage())
.then());
}
private Flux<Void> invokeCreateWorkflows(CreateServiceInstanceBindingRequest request,
CreateServiceInstanceBindingResponse response) {
CreateServiceInstanceBindingResponse response) {
return Flux.defer(() -> {
if (isAppBindingRequest(request)) {
return Flux.fromIterable(createServiceInstanceAppBindingWorkflows)
@@ -159,21 +171,23 @@ public class WorkflowServiceInstanceBindingService implements ServiceInstanceBin
return Flux.fromIterable(createServiceInstanceRouteBindingWorkflows)
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.create(request,
(CreateServiceInstanceRouteBindingResponse)response));
(CreateServiceInstanceRouteBindingResponse) response));
}
return Flux.empty();
});
}
@Override
public Mono<DeleteServiceInstanceBindingResponse> deleteServiceInstanceBinding(DeleteServiceInstanceBindingRequest request) {
public Mono<DeleteServiceInstanceBindingResponse> deleteServiceInstanceBinding(
DeleteServiceInstanceBindingRequest request) {
return invokeDeleteResponseBuilders(request)
.publishOn(Schedulers.parallel())
.doOnNext(response -> delete(request, response)
.subscribe());
}
private Mono<DeleteServiceInstanceBindingResponse> invokeDeleteResponseBuilders(DeleteServiceInstanceBindingRequest request) {
private Mono<DeleteServiceInstanceBindingResponse> invokeDeleteResponseBuilders(
DeleteServiceInstanceBindingRequest request) {
AtomicReference<DeleteServiceInstanceBindingResponseBuilder> responseBuilder =
new AtomicReference<>(DeleteServiceInstanceBindingResponse.builder());
@@ -186,31 +200,33 @@ public class WorkflowServiceInstanceBindingService implements ServiceInstanceBin
}
private Mono<Void> delete(DeleteServiceInstanceBindingRequest request,
DeleteServiceInstanceBindingResponse response) {
DeleteServiceInstanceBindingResponse response) {
return stateRepository.saveState(request.getServiceInstanceId(), request.getBindingId(),
OperationState.IN_PROGRESS, "delete service instance binding started")
.thenMany(invokeDeleteWorkflows(request, response)
.doOnRequest(l -> log.debug("Deleting service instance binding"))
.doOnComplete(() -> log.debug("Finished deleting service instance binding"))
.doOnError(exception -> log.error(String.format("Error deleting service instance binding with error '%s'",
exception.getMessage()), exception)))
.doOnRequest(l -> LOG.debug("Deleting service instance binding"))
.doOnComplete(() -> LOG.debug("Finished deleting service instance binding"))
.doOnError(exception -> LOG.error(String.format("Error deleting service instance binding with error " +
"'%s'", exception.getMessage()), exception)))
.thenEmpty(stateRepository.saveState(request.getServiceInstanceId(), request.getBindingId(),
OperationState.SUCCEEDED, "delete service instance binding completed")
.then())
.onErrorResume(exception -> stateRepository.saveState(request.getServiceInstanceId(), request.getBindingId(),
OperationState.FAILED, exception.getMessage())
.then());
.onErrorResume(
exception -> stateRepository.saveState(request.getServiceInstanceId(), request.getBindingId(),
OperationState.FAILED, exception.getMessage())
.then());
}
private Flux<Void> invokeDeleteWorkflows(DeleteServiceInstanceBindingRequest request,
DeleteServiceInstanceBindingResponse response) {
DeleteServiceInstanceBindingResponse response) {
return Flux.fromIterable(deleteServiceInstanceBindingWorkflows)
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.delete(request, response));
}
@Override
public Mono<GetLastServiceBindingOperationResponse> getLastOperation(GetLastServiceBindingOperationRequest request) {
public Mono<GetLastServiceBindingOperationResponse> getLastOperation(
GetLastServiceBindingOperationRequest request) {
return stateRepository.getState(request.getServiceInstanceId(), request.getBindingId())
.doOnError(exception -> Mono.error(new ServiceInstanceBindingDoesNotExistException(request.getBindingId())))
.map(serviceInstanceState -> GetLastServiceBindingOperationResponse.builder()

View File

@@ -61,9 +61,9 @@ public class WorkflowServiceInstanceService implements ServiceInstanceService {
private final ServiceInstanceStateRepository stateRepository;
public WorkflowServiceInstanceService(ServiceInstanceStateRepository serviceInstanceStateRepository,
List<CreateServiceInstanceWorkflow> createServiceInstanceWorkflows,
List<DeleteServiceInstanceWorkflow> deleteServiceInstanceWorkflows,
List<UpdateServiceInstanceWorkflow> updateServiceInstanceWorkflows) {
List<CreateServiceInstanceWorkflow> createServiceInstanceWorkflows,
List<DeleteServiceInstanceWorkflow> deleteServiceInstanceWorkflows,
List<UpdateServiceInstanceWorkflow> updateServiceInstanceWorkflows) {
this.stateRepository = serviceInstanceStateRepository;
this.createServiceInstanceWorkflows = createServiceInstanceWorkflows;
this.deleteServiceInstanceWorkflows = deleteServiceInstanceWorkflows;
@@ -102,7 +102,7 @@ public class WorkflowServiceInstanceService implements ServiceInstanceService {
.doOnRequest(l -> log.debug("Creating service instance"))
.doOnComplete(() -> log.debug("Finished creating service instance"))
.doOnError(exception -> log.error(String.format("Error creating service instance with error '%s'",
exception.getMessage()), exception)))
exception.getMessage()), exception)))
.thenEmpty(stateRepository.saveState(request.getServiceInstanceId(),
OperationState.SUCCEEDED, "create service instance completed")
.then())
@@ -112,7 +112,7 @@ public class WorkflowServiceInstanceService implements ServiceInstanceService {
}
private Flux<Void> invokeCreateWorkflows(CreateServiceInstanceRequest request,
CreateServiceInstanceResponse response) {
CreateServiceInstanceResponse response) {
return Flux.fromIterable(createServiceInstanceWorkflows)
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.create(request, response));
@@ -155,7 +155,7 @@ public class WorkflowServiceInstanceService implements ServiceInstanceService {
}
private Flux<Void> invokeDeleteWorkflows(DeleteServiceInstanceRequest request,
DeleteServiceInstanceResponse response) {
DeleteServiceInstanceResponse response) {
return Flux.fromIterable(deleteServiceInstanceWorkflows)
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.delete(request, response));
@@ -198,7 +198,7 @@ public class WorkflowServiceInstanceService implements ServiceInstanceService {
}
private Flux<Void> invokeUpdateWorkflows(UpdateServiceInstanceRequest request,
UpdateServiceInstanceResponse response) {
UpdateServiceInstanceResponse response) {
return Flux.fromIterable(updateServiceInstanceWorkflows)
.filterWhen(workflow -> workflow.accept(request))
.concatMap(workflow -> workflow.update(request, response));
@@ -219,4 +219,5 @@ public class WorkflowServiceInstanceService implements ServiceInstanceService {
//TODO add functionality
return Mono.empty();
}
}

View File

@@ -34,11 +34,14 @@ public class InMemoryServiceInstanceBindingStateRepository implements ServiceIns
private final Map<BindingKey, ServiceInstanceState> states = new ConcurrentHashMap<>();
@Override
public Mono<ServiceInstanceState> saveState(String serviceInstanceId, String bindingId, OperationState state, String description) {
public Mono<ServiceInstanceState> saveState(String serviceInstanceId, String bindingId, OperationState state,
String description) {
return Mono.just(new BindingKey(serviceInstanceId, bindingId))
.flatMap(bindingKey -> Mono.just(new ServiceInstanceState(state, description, new Timestamp(Instant.now().toEpochMilli())))
.flatMap(serviceInstanceState -> Mono.fromCallable(() -> this.states.put(bindingKey, serviceInstanceState))
.thenReturn(serviceInstanceState)));
.flatMap(bindingKey -> Mono
.just(new ServiceInstanceState(state, description, new Timestamp(Instant.now().toEpochMilli())))
.flatMap(
serviceInstanceState -> Mono.fromCallable(() -> this.states.put(bindingKey, serviceInstanceState))
.thenReturn(serviceInstanceState)));
}
@Override
@@ -87,7 +90,7 @@ public class InMemoryServiceInstanceBindingStateRepository implements ServiceIns
return this.bindingId;
}
BindingKey(String serviceInstanceId, String bindingId) {
public BindingKey(String serviceInstanceId, String bindingId) {
this.serviceInstanceId = serviceInstanceId;
this.bindingId = bindingId;
}
@@ -100,7 +103,7 @@ public class InMemoryServiceInstanceBindingStateRepository implements ServiceIns
if (!(obj instanceof BindingKey)) {
return false;
}
BindingKey that = (BindingKey)obj;
BindingKey that = (BindingKey) obj;
return Objects.equals(this.bindingId, that.bindingId) &&
Objects.equals(this.serviceInstanceId, that.serviceInstanceId);
}
@@ -117,5 +120,7 @@ public class InMemoryServiceInstanceBindingStateRepository implements ServiceIns
", bindingId='" + bindingId + '\'' +
'}';
}
}
}

View File

@@ -32,7 +32,8 @@ public class InMemoryServiceInstanceStateRepository implements ServiceInstanceSt
@Override
public Mono<ServiceInstanceState> saveState(String serviceInstanceId, OperationState state, String description) {
return Mono.just(new ServiceInstanceState(state, description, new Timestamp(Instant.now().toEpochMilli())))
.flatMap(serviceInstanceState -> Mono.fromCallable(() -> this.states.put(serviceInstanceId, serviceInstanceState))
.flatMap(serviceInstanceState -> Mono
.fromCallable(() -> this.states.put(serviceInstanceId, serviceInstanceState))
.thenReturn(serviceInstanceState));
}
@@ -65,4 +66,5 @@ public class InMemoryServiceInstanceStateRepository implements ServiceInstanceSt
private Mono<Boolean> containsState(String serviceInstanceId) {
return Mono.fromCallable(() -> this.states.containsKey(serviceInstanceId));
}
}

View File

@@ -25,7 +25,8 @@ import org.springframework.cloud.servicebroker.model.instance.OperationState;
*/
public interface ServiceInstanceBindingStateRepository {
default Mono<ServiceInstanceState> saveState(String serviceInstanceId, String bindingId, OperationState state, String description) {
default Mono<ServiceInstanceState> saveState(String serviceInstanceId, String bindingId, OperationState state,
String description) {
return Mono.empty();
}

View File

@@ -21,6 +21,7 @@ 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.BackingServicesProvisionService;
import org.springframework.cloud.appbroker.deployer.BrokeredServices;
import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService;
@@ -29,7 +30,6 @@ import org.springframework.cloud.appbroker.extensions.parameters.BackingServices
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.appbroker.deployer.BackingAppDeploymentService;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse.CreateServiceInstanceResponseBuilder;
import org.springframework.core.annotation.Order;
@@ -42,19 +42,24 @@ public class AppDeploymentCreateServiceInstanceWorkflow
private final Logger log = Loggers.getLogger(AppDeploymentCreateServiceInstanceWorkflow.class);
private final BackingAppDeploymentService deploymentService;
private final BackingServicesProvisionService backingServicesProvisionService;
private final BackingApplicationsParametersTransformationService appsParametersTransformationService;
private final BackingServicesParametersTransformationService servicesParametersTransformationService;
private final CredentialProviderService credentialProviderService;
private final TargetService targetService;
public AppDeploymentCreateServiceInstanceWorkflow(BrokeredServices brokeredServices,
BackingAppDeploymentService deploymentService,
BackingServicesProvisionService backingServicesProvisionService,
BackingApplicationsParametersTransformationService appsParametersTransformationService,
BackingServicesParametersTransformationService servicesParametersTransformationService,
CredentialProviderService credentialProviderService,
TargetService targetService) {
BackingAppDeploymentService deploymentService,
BackingServicesProvisionService backingServicesProvisionService,
BackingApplicationsParametersTransformationService appsParametersTransformationService,
BackingServicesParametersTransformationService servicesParametersTransformationService,
CredentialProviderService credentialProviderService,
TargetService targetService) {
super(brokeredServices);
this.deploymentService = deploymentService;
this.backingServicesProvisionService = backingServicesProvisionService;
@@ -75,7 +80,7 @@ public class AppDeploymentCreateServiceInstanceWorkflow
return getBackingServicesForService(request.getServiceDefinition(), request.getPlan())
.flatMap(backingServices ->
targetService.addToBackingServices(backingServices,
getTargetForService(request.getServiceDefinition(), request.getPlan()) ,
getTargetForService(request.getServiceDefinition(), request.getPlan()),
request.getServiceInstanceId()))
.flatMap(backingServices ->
servicesParametersTransformationService.transformParameters(backingServices,
@@ -86,7 +91,8 @@ public class AppDeploymentCreateServiceInstanceWorkflow
.doOnComplete(() -> log.debug("Finished creating backing services for {}/{}",
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnError(exception -> log.error(String.format("Error creating backing services for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()), exception));
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()),
exception));
}
private Flux<String> deployBackingApplications(CreateServiceInstanceRequest request) {
@@ -94,7 +100,7 @@ public class AppDeploymentCreateServiceInstanceWorkflow
.flatMap(backingApps ->
targetService.addToBackingApplications(backingApps,
getTargetForService(request.getServiceDefinition(),
request.getPlan()) , request.getServiceInstanceId()))
request.getPlan()), request.getServiceInstanceId()))
.flatMap(backingApps ->
appsParametersTransformationService.transformParameters(backingApps,
request.getParameters()))
@@ -106,8 +112,10 @@ public class AppDeploymentCreateServiceInstanceWorkflow
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnComplete(() -> log.debug("Finished deploying backing applications for {}/{}",
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnError(exception -> log.error(String.format("Error deploying backing applications for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()), exception));
.doOnError(
exception -> log.error(String.format("Error deploying backing applications for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()),
exception));
}
@Override
@@ -117,7 +125,8 @@ public class AppDeploymentCreateServiceInstanceWorkflow
@Override
public Mono<CreateServiceInstanceResponseBuilder> buildResponse(CreateServiceInstanceRequest request,
CreateServiceInstanceResponseBuilder responseBuilder) {
CreateServiceInstanceResponseBuilder responseBuilder) {
return Mono.just(responseBuilder.async(true));
}
}

View File

@@ -40,15 +40,18 @@ public class AppDeploymentDeleteServiceInstanceWorkflow
private final Logger log = Loggers.getLogger(AppDeploymentDeleteServiceInstanceWorkflow.class);
private final BackingAppDeploymentService deploymentService;
private final CredentialProviderService credentialProviderService;
private final TargetService targetService;
private final BackingServicesProvisionService backingServicesProvisionService;
public AppDeploymentDeleteServiceInstanceWorkflow(BrokeredServices brokeredServices,
BackingAppDeploymentService deploymentService,
BackingServicesProvisionService backingServicesProvisionService,
CredentialProviderService credentialProviderService,
TargetService targetService) {
BackingAppDeploymentService deploymentService,
BackingServicesProvisionService backingServicesProvisionService,
CredentialProviderService credentialProviderService,
TargetService targetService) {
super(brokeredServices);
this.deploymentService = deploymentService;
this.credentialProviderService = credentialProviderService;
@@ -67,7 +70,7 @@ public class AppDeploymentDeleteServiceInstanceWorkflow
return getBackingServicesForService(request.getServiceDefinition(), request.getPlan())
.flatMapMany(backingServices ->
targetService.addToBackingServices(backingServices,
getTargetForService(request.getServiceDefinition(), request.getPlan()) ,
getTargetForService(request.getServiceDefinition(), request.getPlan()),
request.getServiceInstanceId()))
.flatMap(backingServicesProvisionService::deleteServiceInstance)
.doOnRequest(l -> log.debug("Deleting backing services for{}/{}",
@@ -75,7 +78,8 @@ public class AppDeploymentDeleteServiceInstanceWorkflow
.doOnComplete(() -> log.debug("Finished deleting backing services for {}/{}",
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnError(exception -> log.error(String.format("Error deleting backing services for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()), exception));
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()),
exception));
}
private Flux<String> undeployBackingApplications(DeleteServiceInstanceRequest request) {
@@ -92,8 +96,10 @@ public class AppDeploymentDeleteServiceInstanceWorkflow
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnComplete(() -> log.debug("Finished undeploying backing applications for {}/{}",
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnError(exception -> log.error(String.format("Error undeploying backing applications for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()), exception));
.doOnError(
exception -> log.error(String.format("Error undeploying backing applications for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()),
exception));
}
@Override
@@ -103,7 +109,8 @@ public class AppDeploymentDeleteServiceInstanceWorkflow
@Override
public Mono<DeleteServiceInstanceResponseBuilder> buildResponse(DeleteServiceInstanceRequest request,
DeleteServiceInstanceResponseBuilder responseBuilder) {
DeleteServiceInstanceResponseBuilder responseBuilder) {
return Mono.just(responseBuilder.async(true));
}
}

View File

@@ -31,38 +31,38 @@ import org.springframework.cloud.servicebroker.model.catalog.Plan;
import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition;
import org.springframework.util.CollectionUtils;
class AppDeploymentInstanceWorkflow {
public class AppDeploymentInstanceWorkflow {
final BrokeredServices brokeredServices;
private final BrokeredServices brokeredServices;
AppDeploymentInstanceWorkflow(BrokeredServices brokeredServices) {
protected AppDeploymentInstanceWorkflow(BrokeredServices brokeredServices) {
this.brokeredServices = brokeredServices;
}
Mono<Boolean> accept(ServiceDefinition serviceDefinition, Plan plan) {
protected Mono<Boolean> accept(ServiceDefinition serviceDefinition, Plan plan) {
return getBackingApplicationsForService(serviceDefinition, plan)
.map(backingApplications -> !backingApplications.isEmpty())
.defaultIfEmpty(false);
}
TargetSpec getTargetForService(ServiceDefinition serviceDefinition, Plan plan) {
protected TargetSpec getTargetForService(ServiceDefinition serviceDefinition, Plan plan) {
BrokeredService brokeredService = findBrokeredService(serviceDefinition, plan);
return brokeredService == null ? null : brokeredService.getTarget();
}
Mono<List<BackingApplication>> getBackingApplicationsForService(ServiceDefinition serviceDefinition,
Plan plan) {
protected Mono<List<BackingApplication>> getBackingApplicationsForService(ServiceDefinition serviceDefinition,
Plan plan) {
return Mono.defer(() ->
Mono.justOrEmpty(findBackingApplications(serviceDefinition, plan)));
}
Mono<List<BackingService>> getBackingServicesForService(ServiceDefinition serviceDefinition, Plan plan) {
protected Mono<List<BackingService>> getBackingServicesForService(ServiceDefinition serviceDefinition, Plan plan) {
return Mono.defer(() ->
Mono.justOrEmpty(findBackingServices(serviceDefinition, plan)));
}
private BackingApplications findBackingApplications(ServiceDefinition serviceDefinition,
Plan plan) {
Plan plan) {
BrokeredService brokeredService = findBrokeredService(serviceDefinition, plan);
BackingApplications backingApplications = null;
if (brokeredService != null) {
@@ -74,7 +74,7 @@ class AppDeploymentInstanceWorkflow {
}
private BackingServices findBackingServices(ServiceDefinition serviceDefinition,
Plan plan) {
Plan plan) {
BrokeredService brokeredService = findBrokeredService(serviceDefinition, plan);
BackingServices backingServices = null;
if (brokeredService != null && !CollectionUtils.isEmpty(brokeredService.getServices())) {
@@ -86,15 +86,16 @@ class AppDeploymentInstanceWorkflow {
}
private BrokeredService findBrokeredService(ServiceDefinition serviceDefinition,
Plan plan) {
Plan plan) {
String serviceName = serviceDefinition.getName();
String planName = plan.getName();
return brokeredServices.stream()
.filter(brokeredService ->
brokeredService.getServiceName().equals(serviceName)
&& brokeredService.getPlanName().equals(planName))
.findFirst()
.orElse(null);
.filter(brokeredService ->
brokeredService.getServiceName().equals(serviceName)
&& brokeredService.getPlanName().equals(planName))
.findFirst()
.orElse(null);
}
}

View File

@@ -34,24 +34,27 @@ import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInsta
import org.springframework.core.annotation.Order;
@Order(0)
public class AppDeploymentUpdateServiceInstanceWorkflow
extends AppDeploymentInstanceWorkflow
public class AppDeploymentUpdateServiceInstanceWorkflow extends AppDeploymentInstanceWorkflow
implements UpdateServiceInstanceWorkflow {
private final Logger log = Loggers.getLogger(AppDeploymentUpdateServiceInstanceWorkflow.class);
private final BackingAppDeploymentService deploymentService;
private final BackingServicesProvisionService backingServicesProvisionService;
private final BackingApplicationsParametersTransformationService appsParametersTransformationService;
private final BackingServicesParametersTransformationService servicesParametersTransformationService;
private final TargetService targetService;
public AppDeploymentUpdateServiceInstanceWorkflow(BrokeredServices brokeredServices,
BackingAppDeploymentService deploymentService,
BackingServicesProvisionService backingServicesProvisionService,
BackingApplicationsParametersTransformationService appsParametersTransformationService,
BackingServicesParametersTransformationService servicesParametersTransformationService,
TargetService targetService) {
BackingAppDeploymentService deploymentService,
BackingServicesProvisionService backingServicesProvisionService,
BackingApplicationsParametersTransformationService appsParametersTransformationService,
BackingServicesParametersTransformationService servicesParametersTransformationService,
TargetService targetService) {
super(brokeredServices);
this.deploymentService = deploymentService;
this.backingServicesProvisionService = backingServicesProvisionService;
@@ -60,6 +63,7 @@ public class AppDeploymentUpdateServiceInstanceWorkflow
this.targetService = targetService;
}
@Override
public Mono<Void> update(UpdateServiceInstanceRequest request, UpdateServiceInstanceResponse response) {
return updateBackingServices(request)
.thenMany(updateBackingApplications(request))
@@ -81,7 +85,8 @@ public class AppDeploymentUpdateServiceInstanceWorkflow
.doOnComplete(() -> log.debug("Finished updating backing services for {}/{}",
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnError(exception -> log.error(String.format("Error updating backing services for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()), exception));
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()),
exception));
}
private Flux<String> updateBackingApplications(UpdateServiceInstanceRequest request) {
@@ -97,8 +102,10 @@ public class AppDeploymentUpdateServiceInstanceWorkflow
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnComplete(() -> log.debug("Finished updating backing applications for {}/{}",
request.getServiceDefinition().getName(), request.getPlan().getName()))
.doOnError(exception -> log.error(String.format("Error updating backing applications for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()), exception));
.doOnError(
exception -> log.error(String.format("Error updating backing applications for %s/%s with error '%s'",
request.getServiceDefinition().getName(), request.getPlan().getName(), exception.getMessage()),
exception));
}
@Override
@@ -108,7 +115,8 @@ public class AppDeploymentUpdateServiceInstanceWorkflow
@Override
public Mono<UpdateServiceInstanceResponseBuilder> buildResponse(UpdateServiceInstanceRequest request,
UpdateServiceInstanceResponseBuilder responseBuilder) {
UpdateServiceInstanceResponseBuilder responseBuilder) {
return Mono.just(responseBuilder.async(true));
}
}

View File

@@ -45,4 +45,5 @@ class BackingApplicationTest {
backingApp.setEnvironment(null);
assertThat(backingApp.toString()).isNotEmpty();
}
}
}

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.appbroker.deployer;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -24,9 +27,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.doReturn;
@ExtendWith(MockitoExtension.class)
@@ -36,6 +36,7 @@ class DefaultBackingAppDeploymentServiceTest {
private DeployerClient deployerClient;
private BackingAppDeploymentService backingAppDeploymentService;
private BackingApplications backingApps;
@BeforeEach
@@ -92,4 +93,5 @@ class DefaultBackingAppDeploymentServiceTest {
.expectNextMatches(expectedValues::remove)
.verifyComplete();
}
}
}

View File

@@ -38,24 +38,25 @@ class DefaultBackingServicesProvisionServiceTest {
private DeployerClient deployerClient;
private BackingServicesProvisionService backingServicesProvisionService;
private BackingServices backingServices;
@BeforeEach
void setUp() {
backingServicesProvisionService = new DefaultBackingServicesProvisionService(deployerClient);
backingServices = BackingServices.builder()
.backingService(BackingService.builder()
.serviceInstanceName("si1")
.name("service1")
.plan("standard")
.parameters(Collections.singletonMap("key1", "value1"))
.build())
.backingService(BackingService.builder()
.serviceInstanceName("si2")
.name("service2")
.plan("free")
.build())
.build();
.backingService(BackingService.builder()
.serviceInstanceName("si1")
.name("service1")
.plan("standard")
.parameters(Collections.singletonMap("key1", "value1"))
.build())
.backingService(BackingService.builder()
.serviceInstanceName("si2")
.name("service2")
.plan("free")
.build())
.build();
}
@Test
@@ -118,4 +119,4 @@ class DefaultBackingServicesProvisionServiceTest {
.verifyComplete();
}
}
}

View File

@@ -32,8 +32,8 @@ import reactor.test.StepVerifier;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
@ExtendWith(MockitoExtension.class)
@SuppressWarnings("UnassignedFluxMonoInstance")
@@ -73,14 +73,13 @@ class DeployerClientTest {
.expectNext(APP_NAME)
.verifyComplete();
verify(appDeployer).deploy(argThat(matchesRequest(APP_NAME, APP_PATH, Collections.emptyMap(),
then(appDeployer).should().deploy(argThat(matchesRequest(APP_NAME, APP_PATH, Collections.emptyMap(),
Collections.emptyMap(), Collections.emptyList())));
}
@Test
@SuppressWarnings("serial")
void shouldDeployAppWithProperties() {
// given
setupAppDeployer();
Map<String, String> properties = new HashMap<String, String>() {{
@@ -99,14 +98,13 @@ class DeployerClientTest {
.expectNext(APP_NAME)
.verifyComplete();
verify(appDeployer).deploy(argThat(matchesRequest(APP_NAME, APP_PATH, properties,
then(appDeployer).should().deploy(argThat(matchesRequest(APP_NAME, APP_PATH, properties,
Collections.emptyMap(), Collections.emptyList())));
}
@Test
@SuppressWarnings("serial")
void shouldDeployAppWithService() {
// given
setupAppDeployer();
BackingApplication application =
@@ -115,8 +113,8 @@ class DeployerClientTest {
.name(APP_NAME)
.path(APP_PATH)
.services(ServicesSpec.builder()
.serviceInstanceName("my-db-service")
.build())
.serviceInstanceName("my-db-service")
.build())
.build();
// when
@@ -125,14 +123,13 @@ class DeployerClientTest {
.expectNext(APP_NAME)
.verifyComplete();
verify(appDeployer).deploy(argThat(matchesRequest(APP_NAME, APP_PATH, Collections.emptyMap(),
then(appDeployer).should().deploy(argThat(matchesRequest(APP_NAME, APP_PATH, Collections.emptyMap(),
Collections.emptyMap(), Collections.singletonList("my-db-service"))));
}
@Test
@SuppressWarnings("serial")
void shouldDeployAppWithEnvironmentVariables() {
// given
setupAppDeployer();
Map<String, Object> environment = new HashMap<String, Object>() {{
@@ -151,15 +148,14 @@ class DeployerClientTest {
.expectNext(APP_NAME)
.verifyComplete();
verify(appDeployer).deploy(argThat(matchesRequest(APP_NAME, APP_PATH, Collections.emptyMap(),
then(appDeployer).should().deploy(argThat(matchesRequest(APP_NAME, APP_PATH, Collections.emptyMap(),
environment, Collections.emptyList())));
}
@Test
void shouldUndeployApp() {
// given
when(appDeployer.undeploy(any()))
.thenReturn(Mono.just(UndeployApplicationResponse.builder()
given(appDeployer.undeploy(any()))
.willReturn(Mono.just(UndeployApplicationResponse.builder()
.name(APP_NAME)
.build()));
@@ -174,14 +170,13 @@ class DeployerClientTest {
.expectNext(APP_NAME)
.verifyComplete();
verify(appDeployer).undeploy(argThat(request -> APP_NAME.equals(request.getName())));
then(appDeployer).should().undeploy(argThat(request -> APP_NAME.equals(request.getName())));
}
@Test
void shouldNotReturnErrorWhenUndeployingAppThatDoesNotExist() {
// given
when(appDeployer.undeploy(any()))
.thenReturn(Mono.error(new IllegalStateException("app does not exist")));
given(appDeployer.undeploy(any()))
.willReturn(Mono.error(new IllegalStateException("app does not exist")));
BackingApplication application = BackingApplication.builder()
.name(APP_NAME)
@@ -194,14 +189,13 @@ class DeployerClientTest {
.expectNext(APP_NAME)
.verifyComplete();
verify(appDeployer).undeploy(argThat(request -> APP_NAME.equals(request.getName())));
then(appDeployer).should().undeploy(argThat(request -> APP_NAME.equals(request.getName())));
}
@Test
void shouldCreateServiceInstance() {
// given
when(appDeployer.createServiceInstance(any()))
.thenReturn(Mono.just(CreateServiceInstanceResponse.builder()
given(appDeployer.createServiceInstance(any()))
.willReturn(Mono.just(CreateServiceInstanceResponse.builder()
.name(SERVICE_INSTANCE_NAME)
.build()));
@@ -215,15 +209,14 @@ class DeployerClientTest {
.expectNext(SERVICE_INSTANCE_NAME)
.verifyComplete();
verify(appDeployer).createServiceInstance(argThat(request ->
then(appDeployer).should().createServiceInstance(argThat(request ->
SERVICE_INSTANCE_NAME.equals(request.getServiceInstanceName())));
}
@Test
void shouldUpdateServiceInstance() {
// given
when(appDeployer.updateServiceInstance(any()))
.thenReturn(Mono.just(UpdateServiceInstanceResponse.builder()
given(appDeployer.updateServiceInstance(any()))
.willReturn(Mono.just(UpdateServiceInstanceResponse.builder()
.name(SERVICE_INSTANCE_NAME)
.build()));
@@ -237,15 +230,14 @@ class DeployerClientTest {
.expectNext(SERVICE_INSTANCE_NAME)
.verifyComplete();
verify(appDeployer).updateServiceInstance(argThat(request ->
then(appDeployer).should().updateServiceInstance(argThat(request ->
SERVICE_INSTANCE_NAME.equals(request.getServiceInstanceName())));
}
@Test
void shouldReturnErrorWhenUpdatingServiceInstanceThatDoesNotExist() {
// given
when(appDeployer.updateServiceInstance(any()))
.thenReturn(Mono.error(new IllegalStateException("service instance does not exist")));
given(appDeployer.updateServiceInstance(any()))
.willReturn(Mono.error(new IllegalStateException("service instance does not exist")));
BackingService service = BackingService.builder()
.serviceInstanceName(SERVICE_INSTANCE_NAME)
@@ -257,15 +249,14 @@ class DeployerClientTest {
.expectErrorMessage("service instance does not exist")
.verify();
verify(appDeployer).updateServiceInstance(argThat(request ->
then(appDeployer).should().updateServiceInstance(argThat(request ->
SERVICE_INSTANCE_NAME.equals(request.getServiceInstanceName())));
}
@Test
void shouldDeleteServiceInstance() {
// given
when(appDeployer.deleteServiceInstance(any()))
.thenReturn(Mono.just(DeleteServiceInstanceResponse.builder()
given(appDeployer.deleteServiceInstance(any()))
.willReturn(Mono.just(DeleteServiceInstanceResponse.builder()
.name(SERVICE_INSTANCE_NAME)
.build()));
@@ -279,15 +270,14 @@ class DeployerClientTest {
.expectNext(SERVICE_INSTANCE_NAME)
.verifyComplete();
verify(appDeployer).deleteServiceInstance(argThat(request ->
then(appDeployer).should().deleteServiceInstance(argThat(request ->
SERVICE_INSTANCE_NAME.equals(request.getServiceInstanceName())));
}
@Test
void shouldNotReturnErrorWhenDeletingServiceInstanceThatDoesNotExist() {
// given
when(appDeployer.deleteServiceInstance(any()))
.thenReturn(Mono.error(new IllegalStateException("service instance does not exist")));
given(appDeployer.deleteServiceInstance(any()))
.willReturn(Mono.error(new IllegalStateException("service instance does not exist")));
BackingService service = BackingService.builder()
.serviceInstanceName(SERVICE_INSTANCE_NAME)
@@ -299,14 +289,14 @@ class DeployerClientTest {
.expectNext(SERVICE_INSTANCE_NAME)
.verifyComplete();
verify(appDeployer).deleteServiceInstance(argThat(request ->
then(appDeployer).should().deleteServiceInstance(argThat(request ->
SERVICE_INSTANCE_NAME.equals(request.getServiceInstanceName())));
}
private ArgumentMatcher<DeployApplicationRequest> matchesRequest(String appName, String appArchive,
Map<String, String> properties,
Map<String, Object> environment,
List<String> services) {
Map<String, String> properties,
Map<String, Object> environment,
List<String> services) {
return request ->
request.getName().equals(appName) &&
request.getPath().equals(appArchive) &&
@@ -316,9 +306,10 @@ class DeployerClientTest {
}
private void setupAppDeployer() {
when(appDeployer.deploy(any()))
.thenReturn(Mono.just(DeployApplicationResponse.builder()
given(appDeployer.deploy(any()))
.willReturn(Mono.just(DeployApplicationResponse.builder()
.name(APP_NAME)
.build()));
}
}
}

Some files were not shown because too many files have changed in this diff Show More