package tw.com.providers;
import com.amazonaws.services.cloudformation.AmazonCloudFormationClient;
import com.amazonaws.services.cloudformation.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tw.com.AwsFacade;
import tw.com.MonitorStackEvents;
import tw.com.entity.ProjectAndEnv;
import tw.com.entity.StackNameAndId;
import tw.com.entity.Tagging;
import tw.com.exceptions.CfnAssistException;
import tw.com.exceptions.MissingCapabilities;
import tw.com.exceptions.NotReadyException;
import tw.com.exceptions.WrongNumberOfStacksException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class CloudFormationClient {
private static final Logger logger = LoggerFactory.getLogger(CloudFormationClient.class);
private AmazonCloudFormationClient cfnClient;
public CloudFormationClient(AmazonCloudFormationClient cfnClient) {
this.cfnClient = cfnClient;
}
public Stack describeStack(String stackName) throws WrongNumberOfStacksException {
DescribeStacksRequest describeStacksRequest = new DescribeStacksRequest();
describeStacksRequest.setStackName(stackName);
DescribeStacksResult result = cfnClient.describeStacks(describeStacksRequest);
List<Stack> stacks = result.getStacks();
int numberOfStacks = stacks.size();
if (numberOfStacks != 1) {
logger.error("Wrong number of stacks found: " + numberOfStacks);
throw new WrongNumberOfStacksException(1, numberOfStacks);
}
return stacks.get(0);
}
public List<StackEvent> describeStackEvents(String stackName) {
DescribeStackEventsRequest request = new DescribeStackEventsRequest();
request.setStackName(stackName);
DescribeStackEventsResult result = cfnClient.describeStackEvents(request);
return result.getStackEvents();
}
public List<TemplateParameter> validateTemplate(String contents) {
ValidateTemplateRequest validateTemplateRequest = new ValidateTemplateRequest();
validateTemplateRequest.setTemplateBody(contents);
return cfnClient.validateTemplate(validateTemplateRequest).getParameters();
}
public void deleteStack(String stackName) {
DeleteStackRequest deleteStackRequest = new DeleteStackRequest();
deleteStackRequest.setStackName(stackName);
logger.info("Requesting deletion of stack " + stackName);
cfnClient.deleteStack(deleteStackRequest);
}
public List<StackResource> describeStackResources(String stackName) {
DescribeStackResourcesRequest request = new DescribeStackResourcesRequest();
request.setStackName(stackName);
DescribeStackResourcesResult results = cfnClient.describeStackResources(request);
return results.getStackResources();
}
public List<Stack> describeAllStacks() {
DescribeStacksResult results = cfnClient.describeStacks();
return results.getStacks();
}
private Collection<Tag> createTagsForStack(ProjectAndEnv projectAndEnv, Tagging tagging) {
Collection<Tag> tags = new ArrayList<>();
tags.add(createTag(AwsFacade.PROJECT_TAG, projectAndEnv.getProject()));
tags.add(createTag(AwsFacade.ENVIRONMENT_TAG, projectAndEnv.getEnv()));
if (projectAndEnv.hasBuildNumber()) {
Integer number = projectAndEnv.getBuildNumber();
tags.add(createTag(AwsFacade.BUILD_TAG, number.toString()));
}
tagging.addTagsTo(tags);
return tags;
}
private Tag createTag(String key, String value) {
Tag tag = new Tag();
tag.setKey(key);
tag.setValue(value);
return tag;
}
public StackNameAndId createStack(ProjectAndEnv projAndEnv,
String contents, String stackName,
Collection<Parameter> parameters, MonitorStackEvents monitor,
Tagging tagging) throws CfnAssistException {
CreateStackRequest createStackRequest = new CreateStackRequest();
createStackRequest.setTemplateBody(contents);
createStackRequest.setStackName(stackName);
createStackRequest.setParameters(parameters);
monitor.addMonitoringTo(createStackRequest);
Collection<Tag> tags = createTagsForStack(projAndEnv, tagging);
createStackRequest.setTags(tags);
if (projAndEnv.useCapabilityIAM()) {
logger.info("Adding CAPABILITY_IAM to create request");
List<String> capabilities = new ArrayList<>();
capabilities.add("CAPABILITY_IAM");
createStackRequest.setCapabilities(capabilities);
}
logger.info("Making createStack call to AWS");
try {
CreateStackResult result = cfnClient.createStack(createStackRequest);
return new StackNameAndId(stackName, result.getStackId());
}
catch (InsufficientCapabilitiesException exception) {
throw new MissingCapabilities(exception.getMessage());
}
}
public StackNameAndId updateStack(String contents, Collection<Parameter> parameters,
MonitorStackEvents monitor, String stackName) throws NotReadyException {
logger.info("Will attempt to update stack: " + stackName);
UpdateStackRequest updateStackRequest = new UpdateStackRequest();
updateStackRequest.setParameters(parameters);
updateStackRequest.setStackName(stackName);
updateStackRequest.setTemplateBody(contents);
monitor.addMonitoringTo(updateStackRequest);
UpdateStackResult result = cfnClient.updateStack(updateStackRequest);
return new StackNameAndId(stackName,result.getStackId());
}
}