/*
* Copyright 2013 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// CHECKSTYLE IGNORE MagicNumberCheck
package com.netflix.simianarmy.basic.conformity;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.netflix.discovery.DiscoveryClient;
import com.netflix.discovery.DiscoveryManager;
import com.netflix.simianarmy.aws.conformity.SimpleDBConformityClusterTracker;
import com.netflix.simianarmy.aws.conformity.crawler.AWSClusterCrawler;
import com.netflix.simianarmy.aws.conformity.rule.BasicConformityEurekaClient;
import com.netflix.simianarmy.aws.conformity.rule.ConformityEurekaClient;
import com.netflix.simianarmy.aws.conformity.rule.CrossZoneLoadBalancing;
import com.netflix.simianarmy.aws.conformity.rule.InstanceHasHealthCheckUrl;
import com.netflix.simianarmy.aws.conformity.rule.InstanceHasStatusUrl;
import com.netflix.simianarmy.aws.conformity.rule.InstanceInSecurityGroup;
import com.netflix.simianarmy.aws.conformity.rule.InstanceInVPC;
import com.netflix.simianarmy.aws.conformity.rule.InstanceIsHealthyInEureka;
import com.netflix.simianarmy.aws.conformity.rule.InstanceTooOld;
import com.netflix.simianarmy.aws.conformity.rule.SameZonesInElbAndAsg;
import com.netflix.simianarmy.basic.BasicSimianArmyContext;
import com.netflix.simianarmy.client.aws.AWSClient;
import com.netflix.simianarmy.conformity.ClusterCrawler;
import com.netflix.simianarmy.conformity.ConformityClusterTracker;
import com.netflix.simianarmy.conformity.ConformityEmailBuilder;
import com.netflix.simianarmy.conformity.ConformityEmailNotifier;
import com.netflix.simianarmy.conformity.ConformityMonkey;
import com.netflix.simianarmy.conformity.ConformityRule;
import com.netflix.simianarmy.conformity.ConformityRuleEngine;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Map;
/**
* The basic implementation of the context class for Conformity monkey.
*/
public class BasicConformityMonkeyContext extends BasicSimianArmyContext implements ConformityMonkey.Context {
/** The Constant LOGGER. */
private static final Logger LOGGER = LoggerFactory.getLogger(BasicConformityMonkeyContext.class);
/** The email notifier. */
private final ConformityEmailNotifier emailNotifier;
private final ConformityClusterTracker clusterTracker;
private final Collection<String> regions;
private final ClusterCrawler clusterCrawler;
private final AmazonSimpleEmailServiceClient sesClient;
private final ConformityEmailBuilder conformityEmailBuilder;
private final String defaultEmail;
private final String[] ccEmails;
private final String sourceEmail;
private final ConformityRuleEngine ruleEngine;
private final boolean leashed;
private final Map<String, AWSClient> regionToAwsClient = Maps.newHashMap();
/**
* The constructor.
*/
public BasicConformityMonkeyContext() {
super("simianarmy.properties", "client.properties", "conformity.properties");
regions = Lists.newArrayList(region());
// By default, the monkey is leashed
leashed = configuration().getBoolOrElse("simianarmy.conformity.leashed", true);
LOGGER.info(String.format("Conformity Monkey is running in: %s", regions));
String sdbDomain = configuration().getStrOrElse("simianarmy.conformity.sdb.domain", "SIMIAN_ARMY");
clusterTracker = new SimpleDBConformityClusterTracker(awsClient(), sdbDomain);
ruleEngine = new ConformityRuleEngine();
boolean eurekaEnabled = configuration().getBoolOrElse("simianarmy.conformity.Eureka.enabled", false);
if (eurekaEnabled) {
LOGGER.info("Initializing Discovery client.");
DiscoveryClient discoveryClient = DiscoveryManager.getInstance().getDiscoveryClient();
ConformityEurekaClient conformityEurekaClient = new BasicConformityEurekaClient(discoveryClient);
if (configuration().getBoolOrElse(
"simianarmy.conformity.rule.InstanceIsHealthyInEureka.enabled", false)) {
ruleEngine.addRule(new InstanceIsHealthyInEureka(conformityEurekaClient));
}
if (configuration().getBoolOrElse(
"simianarmy.conformity.rule.InstanceHasHealthCheckUrl.enabled", false)) {
ruleEngine.addRule(new InstanceHasHealthCheckUrl(conformityEurekaClient));
}
if (configuration().getBoolOrElse(
"simianarmy.conformity.rule.InstanceHasStatusUrl.enabled", false)) {
ruleEngine.addRule(new InstanceHasStatusUrl(conformityEurekaClient));
}
} else {
LOGGER.info("Discovery/Eureka is not enabled, the conformity rules that need Eureka are not added.");
}
if (configuration().getBoolOrElse(
"simianarmy.conformity.rule.InstanceInSecurityGroup.enabled", false)) {
String requiredSecurityGroups = configuration().getStr(
"simianarmy.conformity.rule.InstanceInSecurityGroup.requiredSecurityGroups");
if (!StringUtils.isBlank(requiredSecurityGroups)) {
ruleEngine.addRule(new InstanceInSecurityGroup(getAwsCredentialsProvider(),
StringUtils.split(requiredSecurityGroups, ",")));
} else {
LOGGER.info("No required security groups is specified, "
+ "the conformity rule InstanceInSecurityGroup is ignored.");
}
}
if (configuration().getBoolOrElse(
"simianarmy.conformity.rule.InstanceTooOld.enabled", false)) {
ruleEngine.addRule(new InstanceTooOld(getAwsCredentialsProvider(), (int) configuration().getNumOrElse(
"simianarmy.conformity.rule.InstanceTooOld.instanceAgeThreshold", 180)));
}
if (configuration().getBoolOrElse(
"simianarmy.conformity.rule.SameZonesInElbAndAsg.enabled", false)) {
ruleEngine().addRule(new SameZonesInElbAndAsg(getAwsCredentialsProvider()));
}
if (configuration().getBoolOrElse(
"simianarmy.conformity.rule.InstanceInVPC.enabled", false)) {
ruleEngine.addRule(new InstanceInVPC(getAwsCredentialsProvider()));
}
if (configuration().getBoolOrElse(
"simianarmy.conformity.rule.CrossZoneLoadBalancing.enabled", false)) {
ruleEngine().addRule(new CrossZoneLoadBalancing(getAwsCredentialsProvider()));
}
createClient(region());
regionToAwsClient.put(region(), awsClient());
clusterCrawler = new AWSClusterCrawler(regionToAwsClient, configuration());
sesClient = new AmazonSimpleEmailServiceClient();
defaultEmail = configuration().getStrOrElse("simianarmy.conformity.notification.defaultEmail", null);
ccEmails = StringUtils.split(
configuration().getStrOrElse("simianarmy.conformity.notification.ccEmails", ""), ",");
sourceEmail = configuration().getStrOrElse("simianarmy.conformity.notification.sourceEmail", null);
conformityEmailBuilder = new BasicConformityEmailBuilder();
emailNotifier = new ConformityEmailNotifier(getConformityEmailNotifierContext());
}
public ConformityEmailNotifier.Context getConformityEmailNotifierContext() {
return new ConformityEmailNotifier.Context() {
@Override
public AmazonSimpleEmailServiceClient sesClient() {
return sesClient;
}
@Override
public int openHour() {
return (int) configuration().getNumOrElse("simianarmy.conformity.notification.openHour", 0);
}
@Override
public int closeHour() {
return (int) configuration().getNumOrElse("simianarmy.conformity.notification.closeHour", 24);
}
@Override
public String defaultEmail() {
return defaultEmail;
}
@Override
public Collection<String> regions() {
return regions;
}
@Override
public ConformityClusterTracker clusterTracker() {
return clusterTracker;
}
@Override
public ConformityEmailBuilder emailBuilder() {
return conformityEmailBuilder;
}
@Override
public String[] ccEmails() {
return ccEmails;
}
@Override
public Collection<ConformityRule> rules() {
return ruleEngine.rules();
}
@Override
public String sourceEmail() {
return sourceEmail;
}
};
}
@Override
public ClusterCrawler clusterCrawler() {
return clusterCrawler;
}
@Override
public ConformityRuleEngine ruleEngine() {
return ruleEngine;
}
/** {@inheritDoc} */
@Override
public ConformityEmailNotifier emailNotifier() {
return emailNotifier;
}
@Override
public Collection<String> regions() {
return regions;
}
@Override
public boolean isLeashed() {
return leashed;
}
@Override
public ConformityClusterTracker clusterTracker() {
return clusterTracker;
}
}