package com.sequenceiq.cloudbreak.converter;
import static com.sequenceiq.cloudbreak.common.type.CloudConstants.BYOS;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Component;
import com.google.common.collect.FluentIterable;
import com.sequenceiq.cloudbreak.api.model.HostGroupRequest;
import com.sequenceiq.cloudbreak.api.model.InstanceGroupRequest;
import com.sequenceiq.cloudbreak.api.model.StackValidationRequest;
import com.sequenceiq.cloudbreak.controller.BadRequestException;
import com.sequenceiq.cloudbreak.domain.Blueprint;
import com.sequenceiq.cloudbreak.domain.Constraint;
import com.sequenceiq.cloudbreak.domain.Credential;
import com.sequenceiq.cloudbreak.domain.HostGroup;
import com.sequenceiq.cloudbreak.domain.InstanceGroup;
import com.sequenceiq.cloudbreak.domain.Network;
import com.sequenceiq.cloudbreak.domain.StackValidation;
import com.sequenceiq.cloudbreak.service.blueprint.BlueprintService;
import com.sequenceiq.cloudbreak.service.credential.CredentialService;
import com.sequenceiq.cloudbreak.service.network.NetworkService;
@Component
public class JsonToStackValidationConverter extends AbstractConversionServiceAwareConverter<StackValidationRequest, StackValidation> {
@Inject
private BlueprintService blueprintService;
@Inject
private NetworkService networkService;
@Inject
private CredentialService credentialService;
@Inject
@Qualifier("conversionService")
private ConversionService conversionService;
@Override
public StackValidation convert(StackValidationRequest stackValidationRequest) {
StackValidation stackValidation = new StackValidation();
Set<InstanceGroup> instanceGroups = convertInstanceGroups(stackValidationRequest.getInstanceGroups());
stackValidation.setInstanceGroups(instanceGroups);
stackValidation.setHostGroups(convertHostGroupsFromJson(instanceGroups, stackValidationRequest.getHostGroups()));
try {
validateBlueprint(stackValidationRequest, stackValidation);
} catch (AccessDeniedException e) {
throw new AccessDeniedException(
String.format("Access to blueprint '%s' is denied or blueprint doesn't exist.", stackValidationRequest.getBlueprintId()), e);
}
try {
validateCredential(stackValidationRequest, stackValidation);
} catch (AccessDeniedException e) {
throw new AccessDeniedException(
String.format("Access to network '%s' is denied or network doesn't exist.", stackValidationRequest.getNetworkId()), e);
}
try {
validateNetwork(stackValidationRequest, stackValidation);
} catch (AccessDeniedException e) {
throw new AccessDeniedException(
String.format("Access to network '%s' is denied or network doesn't exist.", stackValidationRequest.getNetworkId()), e);
}
return stackValidation;
}
private void validateNetwork(StackValidationRequest stackValidationRequest, StackValidation stackValidation) {
if (stackValidationRequest.getNetworkId() != null) {
Network network = networkService.get(stackValidationRequest.getNetworkId());
stackValidation.setNetwork(network);
} else if (stackValidationRequest.getNetwork() != null) {
Network network = conversionService.convert(stackValidationRequest.getNetwork(), Network.class);
stackValidation.setNetwork(network);
} else if (!BYOS.equals(stackValidation.getCredential().cloudPlatform())) {
throw new BadRequestException("Network does not configured for the validation request!");
}
}
private void validateCredential(StackValidationRequest stackValidationRequest, StackValidation stackValidation) {
if (stackValidationRequest.getCredentialId() != null) {
Credential credential = credentialService.get(stackValidationRequest.getCredentialId());
stackValidation.setCredential(credential);
} else if (stackValidationRequest.getCredential() != null) {
Credential credential = conversionService.convert(stackValidationRequest.getCredential(), Credential.class);
stackValidation.setCredential(credential);
} else {
throw new BadRequestException("Credential does not configured for the validation request!");
}
}
private void validateBlueprint(StackValidationRequest stackValidationRequest, StackValidation stackValidation) {
if (stackValidationRequest.getBlueprintId() != null) {
Blueprint blueprint = blueprintService.get(stackValidationRequest.getBlueprintId());
stackValidation.setBlueprint(blueprint);
} else if (stackValidationRequest.getBlueprint() != null) {
Blueprint blueprint = conversionService.convert(stackValidationRequest.getBlueprint(), Blueprint.class);
stackValidation.setBlueprint(blueprint);
} else {
throw new BadRequestException("Blueprint does not configured for the validation request!");
}
}
private Set<HostGroup> convertHostGroupsFromJson(Set<InstanceGroup> instanceGroups, final Set<HostGroupRequest> hostGroupsJsons) {
Set<HostGroup> hostGroups = new HashSet<>();
for (final HostGroupRequest json : hostGroupsJsons) {
HostGroup hostGroup = new HostGroup();
hostGroup.setName(json.getName());
Constraint constraint = getConversionService().convert(json.getConstraint(), Constraint.class);
final String instanceGroupName = json.getConstraint().getInstanceGroupName();
if (instanceGroupName != null) {
InstanceGroup instanceGroup =
FluentIterable.from(instanceGroups).firstMatch(instanceGroup1 -> instanceGroup1.getGroupName().equals(instanceGroupName)).get();
if (instanceGroup == null) {
throw new BadRequestException(String.format("Cannot find instance group named '%s' in instance group list", instanceGroupName));
}
constraint.setInstanceGroup(instanceGroup);
}
hostGroup.setConstraint(constraint);
hostGroups.add(hostGroup);
}
return hostGroups;
}
private Set<InstanceGroup> convertInstanceGroups(Set<InstanceGroupRequest> instanceGroupRequests) {
return (Set<InstanceGroup>) getConversionService().convert(instanceGroupRequests, TypeDescriptor.forObject(instanceGroupRequests),
TypeDescriptor.collection(Set.class, TypeDescriptor.valueOf(InstanceGroup.class)));
}
}