package com.sequenceiq.cloudbreak.cloud.aws;
import static com.sequenceiq.cloudbreak.util.FreeMarkerTemplateUtils.processTemplateIntoString;
import static org.apache.commons.lang3.StringUtils.isNoneEmpty;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import com.google.common.collect.Lists;
import com.sequenceiq.cloudbreak.cloud.aws.view.AwsGroupView;
import com.sequenceiq.cloudbreak.cloud.aws.view.AwsInstanceProfileView;
import com.sequenceiq.cloudbreak.cloud.aws.view.AwsInstanceView;
import com.sequenceiq.cloudbreak.cloud.context.AuthenticatedContext;
import com.sequenceiq.cloudbreak.cloud.exception.CloudConnectorException;
import com.sequenceiq.cloudbreak.cloud.model.CloudStack;
import com.sequenceiq.cloudbreak.cloud.model.Group;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
@Service("CloudFormationTemplateBuilder")
public class CloudFormationTemplateBuilder {
@Inject
private Configuration freemarkerConfiguration;
public String build(ModelContext context) {
Map<String, Object> model = new HashMap<>();
AwsInstanceProfileView awsInstanceProfileView = new AwsInstanceProfileView(context.stack);
List<AwsGroupView> awsGroupViews = new ArrayList<>();
for (Group group : context.stack.getGroups()) {
AwsInstanceView awsInstanceView = new AwsInstanceView(group.getReferenceInstanceConfiguration().getTemplate());
awsGroupViews.add(
new AwsGroupView(
group.getInstancesSize(),
group.getType().name(),
awsInstanceView.getFlavor(),
group.getName(),
awsInstanceView.getVolumes().size(),
awsInstanceView.isEncryptedVolumes(),
awsInstanceView.getVolumeSize(),
awsInstanceView.getVolumeType(),
awsInstanceView.getSpotPrice(),
group.getSecurity().getRules(),
group.getSecurity().getCloudSecurityId()
)
);
}
model.put("instanceGroups", awsGroupViews);
model.put("existingVPC", context.existingVPC);
model.put("existingIGW", context.existingIGW);
model.put("existingSubnet", !isNullOrEmptyList(context.existingSubnetCidr));
model.put("enableInstanceProfile", context.enableInstanceProfile || context.instanceProfileAvailable);
model.put("existingRole", context.instanceProfileAvailable);
model.put("cbSubnet", (isNullOrEmptyList(context.existingSubnetCidr)) ? Lists.newArrayList(context.defaultSubnet)
: context.existingSubnetCidr);
if (isNoneEmpty(context.cloudbreakPublicIp)) {
model.put("cloudbreakPublicIp", context.cloudbreakPublicIp);
}
if (isNoneEmpty(context.defaultGatewayCidr)) {
model.put("defaultGatewayCidr", context.defaultGatewayCidr);
}
if (isNoneEmpty(context.defaultInboundSecurityGroup)) {
model.put("defaultInboundSecurityGroup", context.defaultInboundSecurityGroup);
}
model.put("gatewayPort", context.gatewayPort);
model.put("dedicatedInstances", areDedicatedInstancesRequested(context.stack));
model.put("availabilitySetNeeded", context.ac.getCloudContext().getLocation().getAvailabilityZone().value() != null);
model.put("mapPublicIpOnLaunch", context.mapPublicIpOnLaunch);
try {
String template = processTemplateIntoString(new Template("aws-template", context.template, freemarkerConfiguration), model);
return template.replaceAll("\\t|\\n| [\\s]+", "");
} catch (IOException | TemplateException e) {
throw new CloudConnectorException("Failed to process CloudFormation freemarker template", e);
}
}
private boolean isNullOrEmptyList(List<?> list) {
return list == null || list.isEmpty();
}
public boolean areDedicatedInstancesRequested(CloudStack cloudStack) {
boolean result = false;
if (isDedicatedInstancesParamExistAndTrue(cloudStack)) {
result = true;
}
return result;
}
private boolean isDedicatedInstancesParamExistAndTrue(CloudStack stack) {
return stack.getParameters().containsKey("dedicatedInstances")
&& Boolean.valueOf(stack.getParameters().get("dedicatedInstances"));
}
public static class ModelContext {
private AuthenticatedContext ac;
private CloudStack stack;
private boolean existingVPC;
private boolean existingIGW;
private List<String> existingSubnetCidr;
private boolean mapPublicIpOnLaunch;
private String template;
private boolean enableInstanceProfile;
private boolean instanceProfileAvailable;
private String defaultSubnet;
private String defaultInboundSecurityGroup;
private String cloudbreakPublicIp;
private int gatewayPort;
private String defaultGatewayCidr;
public ModelContext withAuthenticatedContext(AuthenticatedContext ac) {
this.ac = ac;
return this;
}
public ModelContext withStack(CloudStack stack) {
this.stack = stack;
return this;
}
public ModelContext withExistingVpc(boolean existingVpc) {
this.existingVPC = existingVpc;
return this;
}
public ModelContext withExistingIGW(boolean existingIGW) {
this.existingIGW = existingIGW;
return this;
}
public ModelContext withExistingSubnetCidr(List<String> cidr) {
this.existingSubnetCidr = cidr;
return this;
}
public ModelContext mapPublicIpOnLaunch(boolean mapPublicIpOnLaunch) {
this.mapPublicIpOnLaunch = mapPublicIpOnLaunch;
return this;
}
public ModelContext withEnableInstanceProfile(boolean enableInstanceProfile) {
this.enableInstanceProfile = enableInstanceProfile;
return this;
}
public ModelContext withInstanceProfileAvailable(boolean instanceProfileAvailable) {
this.instanceProfileAvailable = instanceProfileAvailable;
return this;
}
public ModelContext withTemplate(String template) {
this.template = template;
return this;
}
public ModelContext withDefaultSubnet(String subnet) {
this.defaultSubnet = subnet;
return this;
}
public ModelContext withCloudbreakPublicIp(String publicIp) {
this.cloudbreakPublicIp = publicIp;
return this;
}
public ModelContext withDefaultInboundSecurityGroup(String securityGroup) {
this.defaultInboundSecurityGroup = securityGroup;
return this;
}
public ModelContext withGatewayPort(int gatewayPort) {
this.gatewayPort = gatewayPort;
return this;
}
public ModelContext withDefaultGatewayCidr(String defaultGatewayCidr) {
this.defaultGatewayCidr = defaultGatewayCidr;
return this;
}
}
}