package tw.com;
import com.amazonaws.services.cloudformation.model.*;
import com.amazonaws.services.cloudformation.model.Stack;
import com.amazonaws.services.ec2.model.AvailabilityZone;
import com.amazonaws.services.ec2.model.KeyPair;
import com.amazonaws.services.ec2.model.Vpc;
import com.amazonaws.services.elasticloadbalancing.model.Instance;
import com.amazonaws.services.elasticloadbalancing.model.LoadBalancerDescription;
import com.amazonaws.services.identitymanagement.model.User;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tw.com.entity.*;
import tw.com.exceptions.*;
import tw.com.parameters.*;
import tw.com.providers.SavesFile;
import tw.com.providers.IdentityProvider;
import tw.com.providers.NotificationSender;
import tw.com.providers.ProvidesCurrentIp;
import tw.com.repository.CloudFormRepository;
import tw.com.repository.CloudRepository;
import tw.com.repository.ELBRepository;
import tw.com.repository.VpcRepository;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.util.*;
import static java.lang.String.format;
public class AwsFacade implements ProvidesZones {
@Deprecated
private static final String UPDATE_EXTENSTION_LEGACY = ".delta"; // use update instead
private static final String UPDATE_EXTENSTION = ".update";
private static final Logger logger = LoggerFactory.getLogger(AwsFacade.class);
public static final String ENVIRONMENT_TAG = "CFN_ASSIST_ENV";
public static final String PROJECT_TAG = "CFN_ASSIST_PROJECT";
public static final String INDEX_TAG = "CFN_ASSIST_DELTA";
public static final String UPDATE_INDEX_TAG = "CFN_ASSIST_UPDATE";
public static final String BUILD_TAG = "CFN_ASSIST_BUILD_NUMBER";
public static final String TYPE_TAG = "CFN_ASSIST_TYPE";
public static final String ENV_S3_BUCKET = "CFN_ASSIST_BUCKET";
public static final String KEYNAME_TAG = "keypairname";
public static final String PARAMETER_STACKNAME = "stackname";
public static final String NAT_EIP = "natEip";
private VpcRepository vpcRepository;
private CloudFormRepository cfnRepository;
private ELBRepository elbRepository;
private CloudRepository cloudRepository;
private NotificationSender notificationSender;
private MonitorStackEvents monitor;
private IdentityProvider identityProvider;
private String regionName;
public AwsFacade(MonitorStackEvents monitor, CloudFormRepository cfnRepository, VpcRepository vpcRepository,
ELBRepository elbRepository, CloudRepository cloudRepository, NotificationSender notificationSender,
IdentityProvider identityProvider, String regionName) {
this.monitor = monitor;
this.cfnRepository = cfnRepository;
this.vpcRepository = vpcRepository;
this.elbRepository = elbRepository;
this.cloudRepository = cloudRepository;
this.notificationSender = notificationSender;
this.identityProvider = identityProvider;
this.regionName = regionName;
}
public List<TemplateParameter> validateTemplate(String templateBody) {
List<TemplateParameter> parameters = cfnRepository.validateStackTemplate(templateBody);
logger.info(format("Found %s parameters", parameters.size()));
return parameters;
}
public List<TemplateParameter> validateTemplate(File file) throws IOException {
logger.info("Validating template and discovering parameters for file " + file.getAbsolutePath());
String contents = loadFileContents(file);
return validateTemplate(contents);
}
public StackNameAndId applyTemplate(String filename, ProjectAndEnv projAndEnv) throws CfnAssistException, IOException, InterruptedException {
File file = new File(filename);
return applyTemplate(file, projAndEnv);
}
public StackNameAndId applyTemplate(File file, ProjectAndEnv projAndEnv)
throws IOException, InterruptedException, CfnAssistException {
return applyTemplate(file, projAndEnv, new HashSet<>());
}
public StackNameAndId applyTemplate(File file, ProjectAndEnv projAndEnv, Collection<Parameter> userParameters) throws
IOException, InterruptedException, CfnAssistException {
Tagging tagging = new Tagging();
return applyTemplate(file, projAndEnv, userParameters, tagging);
}
private StackNameAndId applyTemplate(File file, ProjectAndEnv projAndEnv, Collection<Parameter> userParameters,
Tagging tagging) throws CfnAssistException, IOException, InterruptedException {
logger.info(format("Applying template %s for %s", file.getAbsoluteFile(), projAndEnv));
Vpc vpcForEnv = findVpcForEnv(projAndEnv);
List<TemplateParameter> declaredParameters = validateTemplate(file);
List<PopulatesParameters> populators = new LinkedList<>();
populators.add(new CfnBuiltInParams(vpcForEnv.getVpcId()));
populators.add(new AutoDiscoverParams(file, vpcRepository, cfnRepository));
populators.add(new EnvVarParams());
ParameterFactory parameterFactory = new ParameterFactory(populators);
if (projAndEnv.hasComment()) {
tagging.setCommentTag(projAndEnv.getComment());
}
String contents = loadFileContents(file);
if (isUpdate(file)) {
logger.info("Request to update a stack, filename is " + file.getAbsolutePath());
return updateStack(projAndEnv, userParameters, declaredParameters, contents, parameterFactory);
} else {
return createStack(file, projAndEnv, userParameters, declaredParameters, contents, parameterFactory,tagging);
}
}
private boolean isUpdate(File file) {
String name = file.getName();
return (name.contains(UPDATE_EXTENSTION) || name.contains(UPDATE_EXTENSTION_LEGACY));
}
private boolean updateSuffix(String name) {
return name.endsWith(UPDATE_EXTENSTION) || name.endsWith(UPDATE_EXTENSTION_LEGACY);
}
private StackNameAndId updateStack(ProjectAndEnv projAndEnv, Collection<Parameter> userParameters,
List<TemplateParameter> declaredParameters, String contents,
ParameterFactory parameterFactory) throws CfnAssistException, IOException, InterruptedException {
Collection<Parameter> parameters = parameterFactory.createRequiredParameters(projAndEnv, userParameters,
declaredParameters, this);
String stackName = findStackToUpdate(declaredParameters, projAndEnv);
StackNameAndId id = cfnRepository.updateStack(contents, parameters, monitor, stackName);
try {
monitor.waitForUpdateFinished(id);
} catch (WrongStackStatus stackFailedToUpdate) {
logger.error("Failed to update stack",stackFailedToUpdate);
cfnRepository.updateFail(id);
throw stackFailedToUpdate;
}
Stack createdStack = cfnRepository.updateSuccess(id);
createOutputTags(createdStack, projAndEnv);
return id;
}
private String findStackToUpdate(List<TemplateParameter> declaredParameters, ProjectAndEnv projAndEnv) throws InvalidStackParameterException {
for(TemplateParameter param : declaredParameters) {
if (param.getParameterKey().equals(PARAMETER_STACKNAME)) {
String defaultValue = param.getDefaultValue();
if ((defaultValue!=null) && (!defaultValue.isEmpty())) {
return createName(projAndEnv, defaultValue);
} else {
logger.error(format("Found parameter %s but no default given", PARAMETER_STACKNAME));
throw new InvalidStackParameterException(PARAMETER_STACKNAME);
}
}
}
logger.error(format("Unable to find parameter call '%s' which is required to peform a stack update", PARAMETER_STACKNAME));
throw new InvalidStackParameterException(PARAMETER_STACKNAME);
}
private StackNameAndId createStack(File file, ProjectAndEnv projAndEnv,
Collection<Parameter> userParameters,
List<TemplateParameter> declaredParameters,
String contents,
ParameterFactory parameterFactory, Tagging tagging)
throws CfnAssistException, InterruptedException, IOException {
String stackName = createStackName(file, projAndEnv);
logger.info("Stackname is " + stackName);
handlePossibleRollback(stackName);
Collection<Parameter> parameters = parameterFactory.createRequiredParameters(projAndEnv, userParameters, declaredParameters, this);
StackNameAndId id = cfnRepository.createStack(projAndEnv, contents, stackName, parameters, monitor, tagging);
try {
monitor.waitForCreateFinished(id);
} catch (WrongStackStatus stackFailedToCreate) {
logger.error("Failed to create stack",stackFailedToCreate);
cfnRepository.createFail(id);
throw stackFailedToCreate;
}
Stack createdStack = cfnRepository.createSuccess(id);
createOutputTags(createdStack, projAndEnv);
sendNotification(stackName, StackStatus.CREATE_COMPLETE.toString());
return id;
}
private void sendNotification(String stackName, String status)
throws CfnAssistException {
User userId = identityProvider.getUserId();
notificationSender.sendNotification(new CFNAssistNotification(stackName, status, userId));
}
private void createOutputTags(Stack createdStack, ProjectAndEnv projAndEnv) {
List<Output> outputs = createdStack.getOutputs();
for(Output output : outputs) {
if (shouldCreateTag(output.getDescription())) {
logger.info("Should create output tag for " + output.toString());
vpcRepository.setVpcTag(projAndEnv, output.getOutputKey(), output.getOutputValue());
}
}
}
private boolean shouldCreateTag(String description) {
return description.equals(PopulatesParameters.CFN_TAG_ON_OUTPUT);
}
private void handlePossibleRollback(String stackName)
throws WrongNumberOfStacksException, NotReadyException,
WrongStackStatus, InterruptedException, DuplicateStackException {
String currentStatus = cfnRepository.getStackStatus(stackName);
if (currentStatus.length()!=0) {
logger.warn("Stack already exists: " + stackName);
StackNameAndId stackId = cfnRepository.getStackNameAndId(stackName);
if (isRollingBack(stackId,currentStatus)) {
logger.warn("Stack is rolled back so delete it and recreate " + stackId);
cfnRepository.deleteStack(stackName);
} else {
logger.error("Stack exists and is not rolled back, cannot create another stack with name:" +stackName);
throw new DuplicateStackException(stackName);
}
}
}
private boolean isRollingBack(StackNameAndId id, String currentStatus) throws NotReadyException, WrongNumberOfStacksException, WrongStackStatus, InterruptedException {
if (currentStatus.equals(StackStatus.ROLLBACK_IN_PROGRESS.toString())) {
monitor.waitForRollbackComplete(id);
return true;
} else if (currentStatus.equals(StackStatus.ROLLBACK_COMPLETE.toString())) {
return true;
}
return false;
}
private Vpc findVpcForEnv(ProjectAndEnv projAndEnv) throws InvalidStackParameterException {
Vpc vpcForEnv = vpcRepository.getCopyOfVpc(projAndEnv);
if (vpcForEnv==null) {
logger.error("Unable to find VPC tagged as environment:" + projAndEnv);
throw new InvalidStackParameterException(projAndEnv.toString());
}
logger.info(format("Found VPC %s corresponding to %s", vpcForEnv.getVpcId(), projAndEnv));
return vpcForEnv;
}
public String createStackName(File file, ProjectAndEnv projAndEnv) {
// note: aws only allows [a-zA-Z][-a-zA-Z0-9]* in stacknames
String filename = file.getName();
String name = FilenameUtils.removeExtension(filename);
if (updateSuffix(name)) {
logger.debug("Detected delta filename, remove additional extension");
name = FilenameUtils.removeExtension(name);
}
return createName(projAndEnv, name);
}
private String createName(ProjectAndEnv projAndEnv, String name) {
String project = projAndEnv.getProject();
String env = projAndEnv.getEnv();
if (projAndEnv.hasBuildNumber()) {
return project+projAndEnv.getBuildNumber()+env+name;
} else {
return project+env+name;
}
}
public void deleteStackFrom(File templateFile, ProjectAndEnv projectAndEnv) throws CfnAssistException {
String fullName = createStackName(templateFile, projectAndEnv);
deleteStack(fullName);
}
public void deleteStackByName(String partialName, ProjectAndEnv projectAndEnv) throws CfnAssistException {
String fullname = createName(projectAndEnv, partialName);
deleteStack(fullname);
}
private void deleteStack(String stackName) throws CfnAssistException {
StackNameAndId stackId;
try {
stackId = cfnRepository.getStackNameAndId(stackName);
} catch (WrongNumberOfStacksException e) {
logger.warn("Unable to find stack " + stackName);
return;
}
logger.info("Found ID for stack: " + stackId);
cfnRepository.deleteStack(stackName);
try {
monitor.waitForDeleteFinished(stackId);
sendNotification(stackName, StackStatus.DELETE_COMPLETE.toString());
} catch (WrongNumberOfStacksException | NotReadyException
| WrongStackStatus | InterruptedException e) {
logger.error("Unable to delete stack " + stackName);
logger.error(e.getMessage());
logger.error(e.getStackTrace().toString());
}
}
private String loadFileContents(File file) throws IOException {
return FileUtils.readFileToString(file, Charset.defaultCharset());
}
public ArrayList<StackNameAndId> applyTemplatesFromFolder(String folderPath,
ProjectAndEnv projAndEnv, Collection<Parameter> cfnParams)
throws IOException, InterruptedException, CfnAssistException {
ArrayList<StackNameAndId> updatedStacks = new ArrayList<>();
File folder = validFolder(folderPath);
logger.info("Invoking templates from folder: " + folderPath);
List<File> files = loadFiles(folder);
logger.info("Attempt to Validate all files");
for(File file : files) {
validateTemplate(file);
}
int highestAppliedDelta = getDeltaIndex(projAndEnv);
logger.info("Current index is " + highestAppliedDelta);
logger.info("Validation ok, apply template files");
for(File file : files) {
int deltaIndex = extractIndexFrom(file);
if (deltaIndex>highestAppliedDelta) {
logger.info(format("Apply template file: %s, index is %s", file.getAbsolutePath(), deltaIndex));
Tagging tagging = new Tagging();
tagging.setIndexTag(deltaIndex);
StackNameAndId stackId = applyTemplate(file, projAndEnv, cfnParams, tagging);
logger.info("Create/Updated stack " + stackId);
updatedStacks.add(stackId);
setDeltaIndex(projAndEnv, deltaIndex);
} else {
logger.info(format("Skipping file %s as already applied, index was %s", file.getAbsolutePath(), deltaIndex));
}
}
logger.info("All templates successfully invoked");
return updatedStacks;
}
private List<File> loadFiles(File folder) {
FilenameFilter jsonFilter = new JsonExtensionFilter();
File[] files = folder.listFiles(jsonFilter);
Arrays.sort(files); // place in lexigraphical order
return Arrays.asList(files);
}
private File validFolder(String folderPath)
throws InvalidStackParameterException {
File folder = new File(folderPath);
if (!folder.isDirectory()) {
throw new InvalidStackParameterException(folderPath + " is not a directory");
}
return folder;
}
public List<String> stepbackLastChange(ProjectAndEnv projAndEnv) throws CfnAssistException {
DeletionsPending pending = new DeletionsPending();
int highestAppliedDelta = getDeltaIndex(projAndEnv);
logger.info("Current delta is " + highestAppliedDelta);
SetsDeltaIndex setsDeltaIndex = vpcRepository.getSetsDeltaIndexFor(projAndEnv);
try {
StackEntry stackEntry = cfnRepository.getStacknameByIndex(projAndEnv.getEnvTag(), highestAppliedDelta);
// important to get id's before deletion request, may throw otherwise
StackNameAndId id = cfnRepository.getStackNameAndId(stackEntry.getStackName());
cfnRepository.deleteStack(stackEntry.getStackName());
pending.add(highestAppliedDelta,id);
}
catch (WrongNumberOfStacksException notFound) {
logger.error("Could not find stack with correct index to delete, index was "+highestAppliedDelta, notFound);
}
return monitor.waitForDeleteFinished(pending, setsDeltaIndex);
}
// use stepbackLastChange
@Deprecated
public List<String> stepbackLastChangeFromFolder(String folderPath, ProjectAndEnv projAndEnv) throws CfnAssistException {
DeletionsPending pending = new DeletionsPending();
File folder = validFolder(folderPath);
List<File> files = loadFiles(folder);
Collections.reverse(files); // delete in reverse direction
int highestAppliedDelta = getDeltaIndex(projAndEnv);
logger.info("Current delta is " + highestAppliedDelta);
File toDelete = findFileToStepBack(files, highestAppliedDelta);
if (toDelete==null) {
logger.warn("No suitable stack/file found to step back from");
return new LinkedList<>();
}
logger.info("Need to step back for file " + toDelete.getAbsolutePath());
int deltaIndex = extractIndexFrom(toDelete);
SetsDeltaIndex setsDeltaIndex = vpcRepository.getSetsDeltaIndexFor(projAndEnv);
String stackName = createStackName(toDelete, projAndEnv);
if (isUpdate(toDelete)) {
logger.warn("Rolling back a stack change/delta does nothing except update delta index on VPC");
setsDeltaIndex.setDeltaIndex(deltaIndex-1);
return new LinkedList<>();
}
else {
StackNameAndId id = cfnRepository.getStackNameAndId(stackName); // important to get id's before deletion request, may throw otherwise
cfnRepository.deleteStack(stackName);
pending.add(deltaIndex,id);
return monitor.waitForDeleteFinished(pending, setsDeltaIndex);
}
}
private File findFileToStepBack(List<File> files, int highestAppliedDelta) {
File toDelete = null;
for(File file : files) {
int deltaIndex = extractIndexFrom(file);
if (deltaIndex==highestAppliedDelta) {
toDelete = file;
break;
}
}
return toDelete;
}
public List<String> rollbackTemplatesByIndexTag(ProjectAndEnv projAndEnv) throws CfnAssistException {
DeletionsPending pending = new DeletionsPending();
int highestAppliedDelta = getDeltaIndex(projAndEnv);
while (highestAppliedDelta>0) {
try {
logger.info("Current delta is " + highestAppliedDelta);
StackEntry stackToDelete = cfnRepository.getStacknameByIndex(projAndEnv.getEnvTag(), highestAppliedDelta);
// TODO add ID to StackEntry
StackNameAndId id = cfnRepository.getStackNameAndId(stackToDelete.getStackName());
logger.info(format("Found stack %s matching index", id));
cfnRepository.deleteStack(stackToDelete.getStackName());
pending.add(highestAppliedDelta,id);
highestAppliedDelta--;
}
catch (WrongNumberOfStacksException notFound) {
logger.error("Unable to find a stack matching index " + highestAppliedDelta, notFound);
break;
}
}
SetsDeltaIndex setsDeltaIndex = vpcRepository.getSetsDeltaIndexFor(projAndEnv);
return monitor.waitForDeleteFinished(pending, setsDeltaIndex);
}
// use rollbackTemplatesByIndexTag
@Deprecated
public List<String> rollbackTemplatesInFolder(String folderPath, ProjectAndEnv projAndEnv) throws CfnAssistException {
DeletionsPending pending = new DeletionsPending();
File folder = validFolder(folderPath);
List<File> files = loadFiles(folder);
Collections.reverse(files); // delete in reverse direction
int highestAppliedDelta = getDeltaIndex(projAndEnv);
logger.info("Current delta is " + highestAppliedDelta);
File fileMatchingIndex = findFileToStepBack(files,highestAppliedDelta);
if (fileMatchingIndex==null) {
throw new CfnAssistException("Cannot find file that corresponds to current index, folder was " + folderPath);
}
for(File file : files) {
if (!isUpdate(file)) {
int deltaIndex = extractIndexFrom(file);
String stackName = createStackName(file, projAndEnv);
if (deltaIndex>highestAppliedDelta) {
logger.warn(format("Not deleting %s as index %s is greater than current delta %s", stackName, deltaIndex, highestAppliedDelta));
} else {
logger.info(format("About to request deletion of stackname %s", stackName));
StackNameAndId id = cfnRepository.getStackNameAndId(stackName); // important to get id's before deletion request, may throw otherwise
cfnRepository.deleteStack(stackName);
pending.add(deltaIndex,id);
}
} else {
logger.info(format("Skipping file %s as it is a stack update file", file.getAbsolutePath()));
}
}
SetsDeltaIndex setsDeltaIndex = vpcRepository.getSetsDeltaIndexFor(projAndEnv);
return monitor.waitForDeleteFinished(pending, setsDeltaIndex);
}
private int extractIndexFrom(File file) {
StringBuilder indexPart = new StringBuilder();
String name = file.getName();
int i = 0;
while(Character.isDigit(name.charAt(i))) {
indexPart.append(name.charAt(i));
i++;
}
return Integer.parseInt(indexPart.toString());
}
public void resetDeltaIndex(ProjectAndEnv projAndEnv) throws CannotFindVpcException {
vpcRepository.setVpcIndexTag(projAndEnv, "0");
}
public void setDeltaIndex(ProjectAndEnv projAndEnv, Integer index) throws CannotFindVpcException {
vpcRepository.setVpcIndexTag(projAndEnv, index.toString());
}
public int getDeltaIndex(ProjectAndEnv projAndEnv) throws CfnAssistException {
String tag = vpcRepository.getVpcIndexTag(projAndEnv);
int result;
try {
result = Integer.parseInt(tag);
return result;
}
catch(NumberFormatException exception) {
logger.error("Could not parse the delta index: " + tag);
throw new BadVPCDeltaIndexException(tag);
}
}
public void initEnvAndProjectForVPC(String targetVpcId, ProjectAndEnv projectAndEnvToSet) throws CfnAssistException {
Vpc result = vpcRepository.getCopyOfVpc(projectAndEnvToSet);
if (result!=null) {
logger.error(format("Managed to find vpc already present with tags %s and id %s", projectAndEnvToSet, result.getVpcId()));
throw new TagsAlreadyInit(targetVpcId);
}
vpcRepository.initAllTags(targetVpcId, projectAndEnvToSet);
}
public void setTagForVpc(ProjectAndEnv projectAndEnv, String tagName, String tagValue) {
vpcRepository.setVpcTag(projectAndEnv,tagName,tagValue);
}
public List<StackEntry> listStacks(ProjectAndEnv projectAndEnv) {
if (projectAndEnv.hasEnv()) {
return cfnRepository.getStacks(projectAndEnv.getEnvTag());
}
return cfnRepository.getStacks();
}
public void tidyNonLBAssocStacks(File file, ProjectAndEnv projectAndEnv, String typeTag) throws CfnAssistException {
String filename = file.getName();
String name = FilenameUtils.removeExtension(filename);
if (updateSuffix(name)) {
throw new InvalidStackParameterException("Cannot invoke for .delta files");
}
logger.info(format("Checking for non-instance-associated stacks for %s and name %s. Will use %s:%s if >1 ELB",
projectAndEnv, name, AwsFacade.TYPE_TAG, typeTag));
List<StackEntry> candidateStacks = cfnRepository.getStacksMatching(projectAndEnv.getEnvTag(), name);
if (candidateStacks.isEmpty()) {
logger.warn("No matching stacks found for possible deletion");
return;
}
List<String> regInstanceIds = currentlyRegisteredInstanceIDs(projectAndEnv, typeTag);
List<StackEntry> toDelete = new LinkedList<>();
for(StackEntry entry : candidateStacks) {
List<String> ids = cfnRepository.getInstancesFor(entry.getStackName());
if (ids.isEmpty()) {
logger.warn(format("Stack %s has no instances at all, will not be deleted", entry.getStackName()));
} else {
if (containsAny(regInstanceIds,ids)) {
logger.info(format("Stack %s contains instances registered to LB, will not be deleted", entry.getStackName()));
} else {
logger.warn(format("Stack %s has no registered instances, will be deleted", entry.getStackName()));
toDelete.add(entry);
}
}
}
if (toDelete.isEmpty()) {
logger.info("No stacks to delete");
} else {
for(StackEntry delete : toDelete) {
logger.warn("Deleting stack " + delete.getStackName());
deleteStack(delete.getStackName());
}
}
}
private List<String> currentlyRegisteredInstanceIDs(
ProjectAndEnv projectAndEnv, String typeTag)
throws TooManyELBException {
List<Instance> registeredInstances = elbRepository.findInstancesAssociatedWithLB(projectAndEnv, typeTag);
List<String> regInstanceIds = new LinkedList<>();
if (registeredInstances.isEmpty()) {
logger.warn("No instances associated with ELB");
} else {
for(Instance ins : registeredInstances) {
regInstanceIds.add(ins.getInstanceId());
}
}
return regInstanceIds;
}
public boolean containsAny(List<String> first, List<String> second) {
for(String candidate : second) {
if (first.contains(candidate)) {
return true;
}
}
return false;
}
public List<Instance> updateELBToInstancesMatchingBuild(ProjectAndEnv projectAndEnv, String typeTag) throws CfnAssistException {
logger.info(format("Update instances for ELB to match %s and type tag %s", projectAndEnv, typeTag));
return elbRepository.updateInstancesMatchingBuild(projectAndEnv, typeTag);
}
public void whitelistCurrentIpForPortToElb(ProjectAndEnv projectAndEnv, String type, ProvidesCurrentIp hasCurrentIp, Integer port) throws CfnAssistException {
InetAddress address = hasCurrentIp.getCurrentIp();
logger.info(format("Request to add %s port:%s for elb on %s of type %s", address.getHostAddress(), port, projectAndEnv, type));
String groupId = getSecGroupIdForELB(projectAndEnv, type);
logger.info("Found sec group: " + groupId);
cloudRepository.updateAddIpAndPortToSecGroup(groupId, address, port);
}
public void blacklistCurrentIpForPortToElb(ProjectAndEnv projectAndEnv, String type, ProvidesCurrentIp hasCurrentIp, Integer port) throws CfnAssistException {
InetAddress address = hasCurrentIp.getCurrentIp();
logger.info(format("Request to remove %s port:%s for elb on %s of type %s", address.getHostAddress(), port, projectAndEnv, type));
String groupId = getSecGroupIdForELB(projectAndEnv, type);
logger.info("Found sec group: " + groupId);
cloudRepository.updateRemoveIpAndPortFromSecGroup(groupId, address, port);
}
private String getSecGroupIdForELB(ProjectAndEnv projectAndEnv, String type)
throws CfnAssistException {
LoadBalancerDescription elb = elbRepository.findELBFor(projectAndEnv, type);
if (elb==null) {
throw new CfnAssistException("Did not find ELB for current vpc");
}
List<String> groups = elb.getSecurityGroups();
if (groups.size()>1) {
throw new CfnAssistException("Found multiple security groups associated with elb " + elb.getDNSName());
}
return groups.get(0);
}
public List<InstanceSummary> listInstances(SearchCriteria searchCriteria) throws CfnAssistException {
List<InstanceSummary> result = new LinkedList<>();
List<String> instanceIds = cfnRepository.getAllInstancesFor(searchCriteria);
for(String id: instanceIds) {
com.amazonaws.services.ec2.model.Instance instance = cloudRepository.getInstanceById(id);
InstanceSummary summary = new InstanceSummary(id, instance.getPrivateIpAddress(), instance.getTags());
result.add(summary);
}
return result;
}
@Override
public Map<String, AvailabilityZone> getZones() {
return cloudRepository.getZones(regionName);
}
public KeyPair createKeyPair(ProjectAndEnv projAndEnv, SavesFile destination, String filename) throws CfnAssistException {
if (destination.exists(filename)) {
throw new CfnAssistException(format("File '%s' already exists", filename));
}
String env = projAndEnv.getEnv();
String project = projAndEnv.getProject();
String keypairName = format("%s_%s", project,env);
logger.info("Create key pair with name " + keypairName);
KeyPair result = cloudRepository.createKeyPair(keypairName, destination, filename);
vpcRepository.setVpcTag(projAndEnv,KEYNAME_TAG, result.getKeyName());
return result;
}
public List<String> createSSHCommand(ProjectAndEnv projectAndEnv, String user) throws CfnAssistException {
String home = System.getenv("HOME");
String keyNameFromTag = vpcRepository.getVpcTag(AwsFacade.KEYNAME_TAG, projectAndEnv);
String keyName = keyNameFromTag.replaceFirst("_keypair","");
String eipAllocId = vpcRepository.getVpcTag(AwsFacade.NAT_EIP, projectAndEnv);
if (eipAllocId==null) {
throw new CfnAssistException(format("Unable to find tag %s for %s", AwsFacade.NAT_EIP, projectAndEnv));
}
String address = cloudRepository.getIpFor(eipAllocId);
List<String> command = new LinkedList<>();
command.add("ssh");
command.add("-i");
command.add(format("%s/.ssh/%s.pem",home, keyName));
command.add(format("%s@%s", user,address));
return command;
}
}