package org.cloudfoundry.community.servicebroker.brooklyn.service;
import java.util.Map;
import java.util.concurrent.Future;
import org.apache.brooklyn.rest.domain.TaskSummary;
import org.cloudfoundry.community.servicebroker.brooklyn.model.BlueprintPlan;
import org.cloudfoundry.community.servicebroker.brooklyn.model.BrooklynServiceInstance;
import org.cloudfoundry.community.servicebroker.brooklyn.repository.BrooklynServiceInstanceRepository;
import org.cloudfoundry.community.servicebroker.brooklyn.repository.Operations;
import org.springframework.cloud.servicebroker.exception.ServiceInstanceExistsException;
import org.springframework.cloud.servicebroker.exception.ServiceInstanceUpdateNotSupportedException;
import org.springframework.cloud.servicebroker.model.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.DeleteServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.DeleteServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.GetLastServiceOperationRequest;
import org.springframework.cloud.servicebroker.model.GetLastServiceOperationResponse;
import org.springframework.cloud.servicebroker.model.OperationState;
import org.springframework.cloud.servicebroker.model.Plan;
import org.springframework.cloud.servicebroker.model.ServiceDefinition;
import org.springframework.cloud.servicebroker.model.UpdateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.UpdateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.service.ServiceInstanceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.annotations.VisibleForTesting;
@Service
public class BrooklynServiceInstanceService implements ServiceInstanceService {
private static final Logger LOG = LoggerFactory.getLogger(BrooklynServiceInstanceService.class);
private BrooklynRestAdmin admin;
private BrooklynServiceInstanceRepository repository;
private BrooklynCatalogService catalogService;
@Autowired
public BrooklynServiceInstanceService(BrooklynRestAdmin admin, BrooklynServiceInstanceRepository repository, BrooklynCatalogService catalogService) {
this.admin = admin;
this.repository = repository;
this.catalogService = catalogService;
}
public BrooklynServiceInstance getServiceInstance(String serviceInstanceId) {
return repository.findOne(serviceInstanceId);
}
@Override
public CreateServiceInstanceResponse createServiceInstance(CreateServiceInstanceRequest request) {
admin.createRepositoryIfNotExists();
// check if exists already
BrooklynServiceInstance instance = getServiceInstance(request.getServiceInstanceId());
if (instance != null) {
throw new ServiceInstanceExistsException(instance.getServiceInstanceId(), instance.getServiceDefinitionId());
}
LOG.info("creating service: [serviceInstanceId={}, planID={}, organizationGuid={}, spaceGuid={}",
request.getServiceInstanceId(),
request.getPlanId(),
request.getOrganizationGuid(),
request.getSpaceGuid()
);
ServiceDefinition service = catalogService.getServiceDefinition(request.getServiceDefinitionId());
String blueprint = createBlueprint(service, request);
Future<TaskSummary> taskSummaryFuture = admin.createApplication(blueprint);
TaskSummary taskSummary = ServiceUtil.getFutureValueLoggingError(taskSummaryFuture);
instance = new BrooklynServiceInstance(request.getServiceInstanceId(), request.getServiceDefinitionId())
.withPlanId(request.getPlanId())
.withEntityId(taskSummary.getEntityId());
repository.save(instance.withOperation(Operations.CREATING).withOperationStatus(OperationState.IN_PROGRESS));
return new CreateServiceInstanceResponse().withAsync(request.isAsyncAccepted());
}
@Override
public GetLastServiceOperationResponse getLastOperation(GetLastServiceOperationRequest request) {
try {
OperationState serviceInstanceLastOperation = getServiceInstance(request.getServiceInstanceId()).getOperationState();
LOG.info("getting last operation for {}: {}", request, serviceInstanceLastOperation);
return new GetLastServiceOperationResponse().withOperationState(serviceInstanceLastOperation);
} catch (Exception e) {
LOG.info("exception thrown getting last operation for {}: {}", request, e);
throw e;
}
}
@VisibleForTesting
public String createBlueprint(ServiceDefinition serviceDefinition, CreateServiceInstanceRequest request) {
String location = "localhost"; // default
Plan selectedPlan = null;
for(Plan p : serviceDefinition.getPlans()){
if(p.getId().equals(request.getPlanId())){
selectedPlan = p;
}
}
Map<String, Object> metadata = serviceDefinition.getMetadata();
String brooklynCatalogId = (String) metadata.get("brooklynCatalogId");
String blueprint = ((BlueprintPlan)selectedPlan).toBlueprint(brooklynCatalogId, location, request);
LOG.info("launching from blueprint: [blueprint={}]", blueprint);
return blueprint;
}
@Override
public DeleteServiceInstanceResponse deleteServiceInstance(DeleteServiceInstanceRequest request) {
String serviceInstanceId = request.getServiceInstanceId();
BrooklynServiceInstance instance = getServiceInstance(serviceInstanceId);
if (instance != null) {
instance = instance.withOperation(Operations.DELETING).withOperationStatus(OperationState.IN_PROGRESS);
String entityId = instance.getEntityId();
admin.deleteApplication(entityId);
LOG.info("Deleting service: [Entity={}, ServiceInstanceId={}]", entityId, serviceInstanceId);
}
repository.save(instance);
return new DeleteServiceInstanceResponse().withAsync(request.isAsyncAccepted());
}
@Override
public UpdateServiceInstanceResponse updateServiceInstance(UpdateServiceInstanceRequest request) {
throw new ServiceInstanceUpdateNotSupportedException("Update not supported at this time");
}
}