package com.sequenceiq.cloudbreak.controller;
import static com.sequenceiq.cloudbreak.common.type.CloudConstants.BYOS;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;
import com.sequenceiq.cloudbreak.api.endpoint.StackEndpoint;
import com.sequenceiq.cloudbreak.api.model.AmbariAddressJson;
import com.sequenceiq.cloudbreak.api.model.AutoscaleStackResponse;
import com.sequenceiq.cloudbreak.api.model.CertificateResponse;
import com.sequenceiq.cloudbreak.api.model.PlatformVariantsJson;
import com.sequenceiq.cloudbreak.api.model.StackRequest;
import com.sequenceiq.cloudbreak.api.model.StackResponse;
import com.sequenceiq.cloudbreak.api.model.StackValidationRequest;
import com.sequenceiq.cloudbreak.api.model.UpdateStackJson;
import com.sequenceiq.cloudbreak.cloud.model.CloudCredential;
import com.sequenceiq.cloudbreak.cloud.model.PlatformVariants;
import com.sequenceiq.cloudbreak.controller.validation.filesystem.FileSystemValidator;
import com.sequenceiq.cloudbreak.controller.validation.stack.StackValidator;
import com.sequenceiq.cloudbreak.converter.spi.CredentialToCloudCredentialConverter;
import com.sequenceiq.cloudbreak.domain.CbUser;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.domain.StackValidation;
import com.sequenceiq.cloudbreak.logger.MDCBuilder;
import com.sequenceiq.cloudbreak.service.TlsSecurityService;
import com.sequenceiq.cloudbreak.service.account.AccountPreferencesValidationFailed;
import com.sequenceiq.cloudbreak.service.account.AccountPreferencesValidator;
import com.sequenceiq.cloudbreak.service.decorator.Decorator;
import com.sequenceiq.cloudbreak.service.stack.CloudParameterService;
import com.sequenceiq.cloudbreak.service.stack.StackService;
@Component
public class StackController implements StackEndpoint {
private static final Logger LOGGER = LoggerFactory.getLogger(StackController.class);
@Autowired
private StackService stackService;
@Autowired
private TlsSecurityService tlsSecurityService;
@Autowired
@Qualifier("conversionService")
private ConversionService conversionService;
@Autowired
private Decorator<Stack> stackDecorator;
@Autowired
private AccountPreferencesValidator accountPreferencesValidator;
@Autowired
private CloudParameterService parameterService;
@Autowired
private FileSystemValidator fileSystemValidator;
@Autowired
private AuthenticatedUserService authenticatedUserService;
@Autowired
private StackValidator stackValidator;
@Autowired
private CredentialToCloudCredentialConverter credentialToCloudCredentialConverter;
@Override
public StackResponse postPrivate(StackRequest stackRequest) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
return createStack(user, stackRequest, false);
}
@Override
public StackResponse postPublic(StackRequest stackRequest) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
return createStack(user, stackRequest, true);
}
@Override
public Set<StackResponse> getPrivates() {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
return stackService.retrievePrivateStacks(user);
}
@Override
public Set<StackResponse> getPublics() {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
return stackService.retrieveAccountStacks(user);
}
@Override
public StackResponse get(Long id) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
return stackService.getJsonById(id);
}
@Override
public StackResponse getPrivate(String name) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
return stackService.getPrivateStackJsonByName(name, user);
}
@Override
public StackResponse getPublic(String name) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
return stackService.getPublicStackJsonByName(name, user);
}
@Override
public Map<String, Object> status(Long id) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
return conversionService.convert(stackService.get(id), Map.class);
}
@Override
public void delete(Long id, Boolean forced, Boolean deleteDependencies) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
if (forced) {
stackService.forceDelete(id, user, deleteDependencies);
} else {
stackService.delete(id, user, deleteDependencies);
}
}
@Override
public void deletePrivate(String name, Boolean forced, Boolean deleteDependencies) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
if (forced) {
stackService.forceDelete(name, user, deleteDependencies);
} else {
stackService.delete(name, user, deleteDependencies);
}
}
@Override
public void deletePublic(String name, Boolean forced, Boolean deleteDependencies) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
if (forced) {
stackService.forceDelete(name, user, deleteDependencies);
} else {
stackService.delete(name, user, deleteDependencies);
}
}
@Override
public Response put(Long id, UpdateStackJson updateRequest) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
Stack stack = stackService.getById(id);
MDCBuilder.buildMdcContext(stack);
if (updateRequest.getStatus() != null) {
stackService.updateStatus(id, updateRequest.getStatus());
} else if (!BYOS.equals(stack.cloudPlatform())) {
Integer scalingAdjustment = updateRequest.getInstanceGroupAdjustment().getScalingAdjustment();
validateAccountPreferences(id, scalingAdjustment);
stackService.updateNodeCount(id, updateRequest.getInstanceGroupAdjustment());
} else if (BYOS.equals(stack.cloudPlatform())) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
return Response.status(Response.Status.ACCEPTED).build();
}
@Override
public CertificateResponse getCertificate(Long stackId) {
return new CertificateResponse(tlsSecurityService.getCertificate(stackId));
}
@Override
public StackResponse getStackForAmbari(AmbariAddressJson json) {
return stackService.get(json.getAmbariAddress());
}
@Override
public Set<AutoscaleStackResponse> getAllForAutoscale() {
LOGGER.info("Get all stack, autoscale authorized only.");
return stackService.getAllForAutoscale();
}
@Override
public Response validate(StackValidationRequest request) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildUserMdcContext(user);
StackValidation stackValidation = conversionService.convert(request, StackValidation.class);
stackService.validateStack(stackValidation);
CloudCredential cloudCredential = credentialToCloudCredentialConverter.convert(stackValidation.getCredential());
fileSystemValidator.validateFileSystem(request.getPlatform(), cloudCredential, request.getFileSystem());
return Response.status(Response.Status.ACCEPTED).build();
}
@Override
public Response deleteInstance(Long stackId, String instanceId) {
CbUser user = authenticatedUserService.getCbUser();
MDCBuilder.buildMdcContext(user);
stackService.removeInstance(user, stackId, instanceId);
return Response.status(Response.Status.ACCEPTED).build();
}
@Override
public PlatformVariantsJson variants() {
PlatformVariants pv = parameterService.getPlatformVariants();
return conversionService.convert(pv, PlatformVariantsJson.class);
}
private StackResponse createStack(CbUser user, StackRequest stackRequest, boolean publicInAccount) {
stackValidator.validate(stackRequest);
Stack stack = conversionService.convert(stackRequest, Stack.class);
MDCBuilder.buildMdcContext(stack);
stack = stackDecorator.decorate(stack, stackRequest.getCredentialId(), stackRequest.getNetworkId(), user, stackRequest.getFlexId());
stack.setPublicInAccount(publicInAccount);
validateAccountPreferences(stack, user);
if (stack.getOrchestrator() != null && stack.getOrchestrator().getApiEndpoint() != null) {
stackService.validateOrchestrator(stack.getOrchestrator());
}
stack = stackService.create(user, stack, stackRequest.getAmbariVersion(), stackRequest.getHdpVersion(),
stackRequest.getImageCatalog(), Optional.ofNullable(stackRequest.getCustomImage()));
return conversionService.convert(stack, StackResponse.class);
}
private void validateAccountPreferences(Stack stack, CbUser user) {
try {
accountPreferencesValidator.validate(stack, user.getAccount(), user.getUserId());
} catch (AccountPreferencesValidationFailed e) {
throw new BadRequestException(e.getMessage(), e);
}
}
private void validateAccountPreferences(Long stackId, Integer scalingAdjustment) {
try {
accountPreferencesValidator.validate(stackId, scalingAdjustment);
} catch (AccountPreferencesValidationFailed e) {
throw new BadRequestException(e.getMessage(), e);
}
}
}