package com.intuit.tank.vmManager.environment.amazon;
/*
* #%L
* VmManager
* %%
* Copyright (C) 2011 - 2015 Intuit Inc.
* %%
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* #L%
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClient;
import com.amazonaws.services.cloudwatch.model.ComparisonOperator;
import com.amazonaws.services.cloudwatch.model.DeleteAlarmsRequest;
import com.amazonaws.services.cloudwatch.model.Dimension;
import com.amazonaws.services.cloudwatch.model.MetricAlarm;
import com.amazonaws.services.cloudwatch.model.PutMetricAlarmRequest;
import com.amazonaws.services.cloudwatch.model.Statistic;
import com.amazonaws.services.sns.AmazonSNSAsyncClient;
import com.amazonaws.services.sns.model.CreateTopicResult;
import com.amazonaws.services.sns.model.ListTopicsResult;
import com.amazonaws.services.sns.model.SubscribeRequest;
import com.amazonaws.services.sns.model.Topic;
import com.intuit.tank.vm.api.enumerated.VMRegion;
import com.intuit.tank.vm.settings.CloudCredentials;
import com.intuit.tank.vm.settings.CloudProvider;
import com.intuit.tank.vm.settings.TankConfig;
/**
*
* CloudwatchInstance
*
* @author dangleton
*
*/
public class CloudwatchInstance {
protected static final long ASSOCIATE_IP_MAX_WAIT_MILIS = 1000 * 60 * 10;// ten minutes
private static Logger logger = LogManager.getLogger(CloudwatchInstance.class);
private AmazonCloudWatchAsyncClient asynchCloudWatchClient;
private AmazonSNSAsyncClient asyncSnsClient;
private TankConfig config = new TankConfig();
/**
*
* @param request
* @param vmRegion
*/
public CloudwatchInstance(VMRegion vmRegion) {
// In case vmRegion is passed as null, use default region from settings file
if (vmRegion == null) {
vmRegion = config.getVmManagerConfig().getDefaultRegion();
}
try {
CloudCredentials creds = config.getVmManagerConfig().getCloudCredentials(CloudProvider.amazon);
AWSCredentials credentials = new BasicAWSCredentials(creds.getKeyId(), creds.getKey());
ClientConfiguration clientConfig = new ClientConfiguration();
clientConfig.setMaxConnections(2);
if (StringUtils.isNotBlank(creds.getProxyHost())) {
try {
clientConfig.setProxyHost(creds.getProxyHost());
if (StringUtils.isNotBlank(creds.getProxyPort())) {
clientConfig.setProxyPort(Integer.valueOf(creds.getProxyPort()));
}
} catch (NumberFormatException e) {
logger.error("invalid proxy setup.");
}
}
if (StringUtils.isNotBlank(creds.getKeyId()) && StringUtils.isNotBlank(creds.getKey())) {
asynchCloudWatchClient = new AmazonCloudWatchAsyncClient(credentials, clientConfig,
Executors.newFixedThreadPool(2));
asyncSnsClient = new AmazonSNSAsyncClient(credentials, clientConfig, Executors.newFixedThreadPool(2));
} else {
asynchCloudWatchClient = new AmazonCloudWatchAsyncClient(clientConfig);
asyncSnsClient = new AmazonSNSAsyncClient(clientConfig);
}
asynchCloudWatchClient.setRegion(Region.getRegion(Regions.fromName(vmRegion.getRegion())));
asyncSnsClient.setRegion(Region.getRegion(Regions.fromName(vmRegion.getRegion())));
} catch (Exception ex) {
logger.error(ex.getMessage());
throw new RuntimeException(ex);
}
}
/**
*
* @param email
* @param jobId
*/
public void removeWatch(String email, String jobId) {
String alarmName = getAlarmName(email, jobId);
for (MetricAlarm a : asynchCloudWatchClient.describeAlarms().getMetricAlarms()) {
if (a.getAlarmName().equalsIgnoreCase(alarmName)) {
DeleteAlarmsRequest req = new DeleteAlarmsRequest().withAlarmNames(alarmName);
asynchCloudWatchClient.deleteAlarmsAsync(req);
}
}
}
/**
*
* @param instances
* @param email
* @param jobId
*/
public void addWatch(Collection<String> instances, String email, String jobId) {
String alarmName = getAlarmName(email, jobId);
for (MetricAlarm a : asynchCloudWatchClient.describeAlarms().getMetricAlarms()) {
if (a.getAlarmName().equalsIgnoreCase(alarmName)) {
logger.info("Alarm for job " + jobId + " and email " + email + " already exists.");
return;
}
}
List<Dimension> dimensions = new ArrayList<Dimension>();
for (String instanceId : instances) {
Dimension d = new Dimension().withName("InstanceId").withValue(instanceId);
dimensions.add(d);
}
PutMetricAlarmRequest request = new PutMetricAlarmRequest()
.withActionsEnabled(true).withAlarmName(alarmName)
.withComparisonOperator(ComparisonOperator.GreaterThanOrEqualToThreshold)
.withDimensions(dimensions)
.withAlarmActions(getOrCreateNotification(email))
.withEvaluationPeriods(1)
.withPeriod(60)
.withThreshold(60.0D)
.withStatistic(Statistic.Average)
.withMetricName("CPUUtilization")
.withNamespace("AWS/EC2");
asynchCloudWatchClient.putMetricAlarm(request);
logger.info("Created alarm " + alarmName);
}
/**
*
* @param email
* @return
*/
public String getOrCreateNotification(String email) {
String ret = null;
String topicName = getTopicName(email);
String nextToken = null;
do {
ListTopicsResult listTopics = asyncSnsClient.listTopics(nextToken);
List<Topic> topics = listTopics.getTopics();
for (Topic s : topics) {
if (s.getTopicArn().endsWith(topicName)) {
ret = s.getTopicArn();
break;
}
}
nextToken = listTopics.getNextToken();
} while (ret == null && nextToken != null);
if (ret == null) {
// create the topic and the subscription
CreateTopicResult topic = asyncSnsClient.createTopic(topicName);
SubscribeRequest req = new SubscribeRequest(topic.getTopicArn(), "email", email);
asyncSnsClient.subscribeAsync(req);
ret = topic.getTopicArn();
}
return ret;
}
private String getTopicName(String email) {
String ret = "AgentEmailTopicFor_" + email.replaceAll("\\W+", "_");
return ret;
}
private String getAlarmName(String email, String jobId) {
String ret = "Job " + jobId + " Alarm Excessive CPU for Email " + email;
ret = ret.replaceAll("\\W+", "_");
return ret;
}
}