4. Service Instances

Service brokers are responsible for provisioning the services advertised in their catalog and managing their lifecycle in the underlying cloud platform. The services created by the broker are referred to as service instances.spring-doc.cn

Service brokers must implement the ServiceInstanceService interface and provide implementations of the required methods of that interface. Each method receives a single Java object parameter that contains all the details of the request from the platform and returns a Java object value that provides the details of the operation to the platform.spring-doc.cn

The service instance create, update, and delete operations can be performed synchronously or asynchronously.spring-doc.cn

  • When a service broker creates, updates, or deletes a service instance synchronously, the appropriate interface method should block and return a response to the platform only when the operation completes successfully or when a failure occurs.spring-doc.cn

  • When performing an operation asynchronously, the service broker can return a response to the platform before the operation is complete and indicate in the response that the operation is in progress. The platform polls the service broker to get the status of the operation when an asynchronous operation is indicated.spring-doc.cn

4.1. Service Instance Creation

The service broker must provide an implementation of the createServiceInstance() method.spring-doc.cn

Service brokers typically provision a resource in the platform or in another system when they create a service instance. Service brokers are responsible for keeping track of any resources associated with a service instance for future retrieval, updating, or deletion.spring-doc.cn

4.1.1. Event Registry

Service instance creation can be further customized by utilizing events. To do so:spring-doc.cn

  1. Autowire the CreateServiceInstanceEventFlowRegistry bean.spring-doc.cn

  2. Use one of the addInitializationFlow(), addCompletionFlow(), or addErrorFlow() methods to register custom reactive flows to run during the various stages of creating a service instance.spring-doc.cn

4.2. Service Instance Updating

If the plan_updateable field is set to true in the services catalog, the service broker must provide an implementation of the updateServiceInstance() method. Otherwise, this method is never called by the platform, and the default implementation in the interface can be used.spring-doc.cn

Services brokers can modify the configuration of an existing resource when updating a service instance or deploying a new resource.spring-doc.cn

4.2.1. Event Registry

Service instance updates can be further customized by utilizing events. To do so:spring-doc.cn

  1. Autowire the UpdateServiceInstanceEventFlowRegistry bean.spring-doc.cn

  2. Use one of the addInitializationFlow(), addCompletionFlow(), or addErrorFlow() methods to register custom reactive flows to run during the various stages of updating a service instance.spring-doc.cn

4.3. Service Instance Deletion

An implementation of the deleteServiceInstance() method must be provided by the service broker.spring-doc.cn

Any resources provisioned in the create operation should be de-provisioned by the delete operation.spring-doc.cn

4.3.1. Event Registry

Service instance deletion can be further customized by utilizing events. To do so:spring-doc.cn

  1. Autowire the DeleteServiceInstanceEventFlowRegistry bean.spring-doc.cn

  2. Use one of the addInitializationFlow(), addCompletionFlow(), or addErrorFlow() methods to register custom reactive flows to run during the various stages of deleting a service instance.spring-doc.cn

4.4. Service Instance Operation Status Retrieval

If any create, update, or delete operation can return an asynchronous “operation in progress” response to the platform, the service broker must provide an implementation of the getLastOperation() method. Otherwise, this method is never called by the platform, and the default implementation in the interface can be used.spring-doc.cn

The platform polls this method of the service broker for a service instance that has an asynchronous operation in progress until the service broker indicates that the operation has completed successfully or a failure has occurred.spring-doc.cn

4.4.1. Event Registry

Service instance last operation requests can be further customized by utilizing events. To do so:spring-doc.cn

  1. Autowire the AsyncOperationServiceInstanceEventFlowRegistry bean.spring-doc.cn

  2. Use one of the addInitializationFlow(), addCompletionFlow(), or addErrorFlow() methods to register custom reactive flows to run during the various stages of last operation retrieval.spring-doc.cn

4.5. Service Instance Retrieval

If the instances_retrievable field is set to true in the services catalog, the service broker must provide an implementation of the getServiceInstance() method. Otherwise, this method is never called by the platform, and the default implementation in the interface can be used.spring-doc.cn

Service brokers are responsible for maintaining any service instance state necessary to support the retrieval operation.spring-doc.cn

4.6. Example Implementation

The following example shows a service instance implementation:spring-doc.cn

package com.example.servicebroker;

import java.util.Map;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationRequest;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationResponse;
import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.OperationState;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.service.ServiceInstanceService;
import org.springframework.stereotype.Service;

@Service
public class ExampleServiceInstanceService implements ServiceInstanceService {

	@Override
	public Mono<CreateServiceInstanceResponse> createServiceInstance(CreateServiceInstanceRequest request) {
		String serviceInstanceId = request.getServiceInstanceId();
		String planId = request.getPlanId();
		Map<String, Object> parameters = request.getParameters();

		//
		// perform the steps necessary to initiate the asynchronous
		// provisioning of all necessary resources
		//

		String dashboardUrl = ""; /* construct a dashboard URL */

		return Mono.just(CreateServiceInstanceResponse.builder()
				.dashboardUrl(dashboardUrl)
				.async(true)
				.build());
	}

	@Override
	public Mono<UpdateServiceInstanceResponse> updateServiceInstance(UpdateServiceInstanceRequest request) {
		String serviceInstanceId = request.getServiceInstanceId();
		String planId = request.getPlanId();
		String previousPlan = request.getPreviousValues().getPlanId();
		Map<String, Object> parameters = request.getParameters();

		//
		// perform the steps necessary to initiate the asynchronous
		// updating of all necessary resources
		//

		return Mono.just(UpdateServiceInstanceResponse.builder()
				.async(true)
				.build());
	}

	@Override
	public Mono<DeleteServiceInstanceResponse> deleteServiceInstance(DeleteServiceInstanceRequest request) {
		String serviceInstanceId = request.getServiceInstanceId();
		String planId = request.getPlanId();

		//
		// perform the steps necessary to initiate the asynchronous
		// deletion of all provisioned resources
		//

		return Mono.just(DeleteServiceInstanceResponse.builder()
				.async(true)
				.build());
	}

	@Override
	public Mono<GetServiceInstanceResponse> getServiceInstance(GetServiceInstanceRequest request) {
		String serviceInstanceId = request.getServiceInstanceId();

		//
		// retrieve the details of the specified service instance
		//

		String dashboardUrl = ""; /* retrieve dashboard URL */

		return Mono.just(GetServiceInstanceResponse.builder()
				.dashboardUrl(dashboardUrl)
				.build());
	}

	@Override
	public Mono<GetLastServiceOperationResponse> getLastOperation(GetLastServiceOperationRequest request) {
		String serviceInstanceId = request.getServiceInstanceId();

		//
		// determine the status of the operation in progress
		//

		return Mono.just(GetLastServiceOperationResponse.builder()
				.operationState(OperationState.SUCCEEDED)
				.build());
	}
}

4.7. Example Event Flow Configuration

There are multiple ways to configure service instance event flows. One option is to autowire one or more registries and interact with the registry directly. Another option is to define beans for specific flows. These beans are automatically identified and added to the appropriate registry. A final option is to declare a new registry bean. However, be aware that defining a new registry bean overrides the provided auto-configuration.spring-doc.cn

4.7.1. Option 1: Autowire Registries

The following example shows a configuration for service instance event flows:spring-doc.cn

package com.example.servicebroker;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationRequest;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationResponse;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.service.events.AsyncOperationServiceInstanceEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.CreateServiceInstanceEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.DeleteServiceInstanceEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.UpdateServiceInstanceEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceInitializationFlow;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleServiceInstanceEventFlowsConfiguration {

	private final CreateServiceInstanceEventFlowRegistry createRegistry;

	private final UpdateServiceInstanceEventFlowRegistry updateRegistry;

	private final DeleteServiceInstanceEventFlowRegistry deleteRegistry;

	private final AsyncOperationServiceInstanceEventFlowRegistry asyncRegistry;

	public ExampleServiceInstanceEventFlowsConfiguration(CreateServiceInstanceEventFlowRegistry createRegistry,
			UpdateServiceInstanceEventFlowRegistry updateRegistry,
			DeleteServiceInstanceEventFlowRegistry deleteRegistry,
			AsyncOperationServiceInstanceEventFlowRegistry asyncRegistry) {
		this.createRegistry = createRegistry;
		this.updateRegistry = updateRegistry;
		this.deleteRegistry = deleteRegistry;
		this.asyncRegistry = asyncRegistry;

		prepareCreateEventFlows()
				.then(prepareUpdateEventFlows())
				.then(prepareDeleteEventFlows())
				.then(prepareLastOperationEventFlows())
				.subscribe();
	}

	private Mono<Void> prepareCreateEventFlows() {
		return Mono.just(createRegistry)
				.map(registry -> registry.addInitializationFlow(new CreateServiceInstanceInitializationFlow() {
					@Override
					public Mono<Void> initialize(CreateServiceInstanceRequest request) {
						//
						// do something before the instance is created
						//
						return Mono.empty();
					}
				})
						.then(registry.addCompletionFlow(new CreateServiceInstanceCompletionFlow() {
							@Override
							public Mono<Void> complete(CreateServiceInstanceRequest request,
									CreateServiceInstanceResponse response) {
								//
								// do something after the instance is created
								//
								return Mono.empty();
							}
						}))
						.then(registry.addErrorFlow(new CreateServiceInstanceErrorFlow() {
							@Override
							public Mono<Void> error(CreateServiceInstanceRequest request, Throwable t) {
								//
								// do something if an error occurs while creating an instance
								//
								return Mono.empty();
							}
						})))
				.then();
	}

	private Mono<Void> prepareUpdateEventFlows() {
		return Mono.just(updateRegistry)
				.map(registry -> registry.addInitializationFlow(new UpdateServiceInstanceInitializationFlow() {
					@Override
					public Mono<Void> initialize(UpdateServiceInstanceRequest request) {
						//
						// do something before the instance is updated
						//
						return Mono.empty();
					}
				})
						.then(registry.addCompletionFlow(new UpdateServiceInstanceCompletionFlow() {
							@Override
							public Mono<Void> complete(UpdateServiceInstanceRequest request,
									UpdateServiceInstanceResponse response) {
								//
								// do something after the instance is updated
								//
								return Mono.empty();
							}
						}))
						.then(registry.addErrorFlow(new UpdateServiceInstanceErrorFlow() {
							@Override
							public Mono<Void> error(UpdateServiceInstanceRequest request, Throwable t) {
								//
								// do something if an error occurs while updating an instance
								//
								return Mono.empty();
							}
						})))
				.then();
	}

	private Mono<Void> prepareDeleteEventFlows() {
		return Mono.just(deleteRegistry)
				.map(registry -> registry.addInitializationFlow(new DeleteServiceInstanceInitializationFlow() {
					@Override
					public Mono<Void> initialize(DeleteServiceInstanceRequest request) {
						//
						// do something before the instance is deleted
						//
						return Mono.empty();
					}
				})
						.then(registry.addCompletionFlow(new DeleteServiceInstanceCompletionFlow() {
							@Override
							public Mono<Void> complete(DeleteServiceInstanceRequest request,
									DeleteServiceInstanceResponse response) {
								//
								// do something after the instance is deleted
								//
								return Mono.empty();
							}
						}))
						.then(registry.addErrorFlow(new DeleteServiceInstanceErrorFlow() {
							@Override
							public Mono<Void> error(DeleteServiceInstanceRequest request, Throwable t) {
								//
								// do something if an error occurs while deleting an instance
								//
								return Mono.empty();
							}
						})))
				.then();
	}

	private Mono<Void> prepareLastOperationEventFlows() {
		return Mono.just(asyncRegistry)
				.map(registry -> registry.addInitializationFlow(new AsyncOperationServiceInstanceInitializationFlow() {
					@Override
					public Mono<Void> initialize(GetLastServiceOperationRequest request) {
						//
						// do something before returning the last operation
						//
						return Mono.empty();
					}
				})
						.then(registry.addCompletionFlow(new AsyncOperationServiceInstanceCompletionFlow() {
							@Override
							public Mono<Void> complete(GetLastServiceOperationRequest request,
									GetLastServiceOperationResponse response) {
								//
								// do something after returning the last operation
								//
								return Mono.empty();
							}
						}))
						.then(registry.addErrorFlow(new AsyncOperationServiceInstanceErrorFlow() {
							@Override
							public Mono<Void> error(GetLastServiceOperationRequest request, Throwable t) {
								//
								// do something if an error occurs while processing the last operation response
								//
								return Mono.empty();
							}
						})))
				.then();
	}

}

4.7.2. Option 2: Event Flow Beans

Optionally, you can configure beans for the individual flows, as follows:spring-doc.cn

package com.example.servicebroker;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationRequest;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationResponse;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceInitializationFlow;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleServiceInstanceEventFlowsConfiguration2 {

	//
	// Create Service Instance flows
	//

	@Bean
	public CreateServiceInstanceInitializationFlow createServiceInstanceInitializationFlow() {
		return new CreateServiceInstanceInitializationFlow() {
			@Override
			public Mono<Void> initialize(CreateServiceInstanceRequest request) {
				//
				// do something before the instance is created
				//
				return Mono.empty();
			}
		};
	}

	@Bean
	public CreateServiceInstanceCompletionFlow createServiceInstanceCompletionFlow() {
		return new CreateServiceInstanceCompletionFlow() {
			@Override
			public Mono<Void> complete(CreateServiceInstanceRequest request,
					CreateServiceInstanceResponse response) {
				//
				// do something after the instance is created
				//
				return Mono.empty();
			}
		};
	}

	@Bean
	public CreateServiceInstanceErrorFlow createServiceInstanceErrorFlow() {
		return new CreateServiceInstanceErrorFlow() {
			@Override
			public Mono<Void> error(CreateServiceInstanceRequest request, Throwable t) {
				//
				// do something if an error occurs while creating an instance
				//
				return Mono.empty();
			}
		};
	}

	//
	// Update Service Instance flows
	//

	@Bean
	public UpdateServiceInstanceInitializationFlow updateServiceInstanceInitializationFlow() {
		return new UpdateServiceInstanceInitializationFlow() {
			@Override
			public Mono<Void> initialize(
					UpdateServiceInstanceRequest request) {
				//
				// do something before the instance is updated
				//
				return Mono.empty();
			}
		};
	}

	@Bean
	public UpdateServiceInstanceCompletionFlow updateServiceInstanceCompletionFlow() {
		return new UpdateServiceInstanceCompletionFlow() {
			@Override
			public Mono<Void> complete(UpdateServiceInstanceRequest request,
					UpdateServiceInstanceResponse response) {
				//
				// do something after the instance is updated
				//
				return Mono.empty();
			}
		};
	}

	@Bean
	public UpdateServiceInstanceErrorFlow updateServiceInstanceErrorFlow() {
		return new UpdateServiceInstanceErrorFlow() {
			@Override
			public Mono<Void> error(UpdateServiceInstanceRequest request, Throwable t) {
				//
				// do something if an error occurs while updating an instance
				//
				return Mono.empty();
			}
		};
	}

	//
	// Delete Service Instance flows
	//

	@Bean
	public DeleteServiceInstanceInitializationFlow deleteServiceInstanceInitializationFlow() {
		return new DeleteServiceInstanceInitializationFlow() {
			@Override
			public Mono<Void> initialize(
					DeleteServiceInstanceRequest request) {
				//
				// do something before the instance is deleted
				//
				return Mono.empty();
			}
		};
	}

	@Bean
	public DeleteServiceInstanceCompletionFlow deleteServiceInstanceCompletionFlow() {
		return new DeleteServiceInstanceCompletionFlow() {
			@Override
			public Mono<Void> complete(DeleteServiceInstanceRequest request,
					DeleteServiceInstanceResponse response) {
				//
				// do something after the instance is deleted
				//
				return Mono.empty();
			}
		};
	}

	@Bean
	public DeleteServiceInstanceErrorFlow deleteServiceInstanceErrorFlow() {
		return new DeleteServiceInstanceErrorFlow() {
			@Override
			public Mono<Void> error(DeleteServiceInstanceRequest request, Throwable t) {
				//
				// do something if an error occurs while deleting the instance
				//
				return Mono.empty();
			}
		};
	}

	//
	// Get Last Operation flows
	//

	@Bean
	public AsyncOperationServiceInstanceInitializationFlow getLastOperationInitializationFlow() {
		return new AsyncOperationServiceInstanceInitializationFlow() {
			@Override
			public Mono<Void> initialize(
					GetLastServiceOperationRequest request) {
				//
				// do something before getting the last operation
				//
				return Mono.empty();
			}
		};
	}

	@Bean
	public AsyncOperationServiceInstanceCompletionFlow getLastOperationCompletionFlow() {
		return new AsyncOperationServiceInstanceCompletionFlow() {
			@Override
			public Mono<Void> complete(GetLastServiceOperationRequest request,
					GetLastServiceOperationResponse response) {
				//
				// do something after getting the last operation
				//
				return Mono.empty();
			}
		};
	}

	@Bean
	public AsyncOperationServiceInstanceErrorFlow getLastOperationErrorFlow() {
		return new AsyncOperationServiceInstanceErrorFlow() {
			@Override
			public Mono<Void> error(GetLastServiceOperationRequest request, Throwable t) {
				//
				// do something if an error occurs while getting the last operation
				//
				return Mono.empty();
			}
		};
	}

}