diff --git a/src/main/java/com/netflix/simianarmy/aws/janitor/crawler/InstanceJanitorCrawler.java b/src/main/java/com/netflix/simianarmy/aws/janitor/crawler/InstanceJanitorCrawler.java index 508e2fd3..76e00ac3 100644 --- a/src/main/java/com/netflix/simianarmy/aws/janitor/crawler/InstanceJanitorCrawler.java +++ b/src/main/java/com/netflix/simianarmy/aws/janitor/crawler/InstanceJanitorCrawler.java @@ -45,6 +45,9 @@ public class InstanceJanitorCrawler extends AbstractAWSJanitorCrawler { /** The name representing the additional field name of ASG's name. */ public static final String INSTANCE_FIELD_ASG_NAME = "ASG_NAME"; + /** The name representing the additional field name of the OpsWork stack name. */ + public static final String INSTANCE_FIELD_OPSWORKS_STACK_NAME = "OPSWORKS_STACK_NAME"; + /** The Constant LOGGER. */ private static final Logger LOGGER = LoggerFactory.getLogger(InstanceJanitorCrawler.class); @@ -101,6 +104,11 @@ private List getInstanceResources(String... instanceIds) { instanceResource.setAdditionalField(INSTANCE_FIELD_ASG_NAME, asgName); LOGGER.info(String.format("instance %s has a ASG tag name %s.", instanceResource.getId(), asgName)); } + String opsworksStackName = getOpsWorksStackName(instanceResource); + if (opsworksStackName != null) { + instanceResource.setAdditionalField(INSTANCE_FIELD_OPSWORKS_STACK_NAME, opsworksStackName); + LOGGER.info(String.format("instance %s is part of an OpsWorks stack named %s.", instanceResource.getId(), opsworksStackName)); + } if (instance.getState() != null) { ((AWSResource) instanceResource).setAWSResourceState(instance.getState().getName()); } @@ -122,4 +130,8 @@ private String getAsgName(Resource instanceResource, Map= 0); Validate.isTrue(retentionDaysWithOwner >= 0); @@ -75,6 +80,12 @@ public OrphanedInstanceRule(MonkeyCalendar calendar, this.instanceAgeThreshold = instanceAgeThreshold; this.retentionDaysWithOwner = retentionDaysWithOwner; this.retentionDaysWithoutOwner = retentionDaysWithoutOwner; + this.respectOpsWorksParentage = respectOpsWorksParentage; + } + + public OrphanedInstanceRule(MonkeyCalendar calendar, + int instanceAgeThreshold, int retentionDaysWithOwner, int retentionDaysWithoutOwner) { + this(calendar, instanceAgeThreshold, retentionDaysWithOwner, retentionDaysWithoutOwner, false); } @Override @@ -92,7 +103,9 @@ public boolean isValid(Resource resource) { } AWSResource instanceResource = (AWSResource) resource; String asgName = instanceResource.getAdditionalField(InstanceJanitorCrawler.INSTANCE_FIELD_ASG_NAME); - if (StringUtils.isEmpty(asgName)) { + String opsworkStackName = instanceResource.getAdditionalField(InstanceJanitorCrawler.INSTANCE_FIELD_OPSWORKS_STACK_NAME); + // If there is no ASG AND it isn't an OpsWorks stack (or OpsWorks isn't respected as a parent), we have an orphan + if (StringUtils.isEmpty(asgName) && (!respectOpsWorksParentage || StringUtils.isEmpty(opsworkStackName))) { if (resource.getLaunchTime() == null) { LOGGER.error(String.format("The instance %s has no launch time.", resource.getId())); return true; @@ -113,7 +126,7 @@ public boolean isValid(Resource resource) { } Date terminationTime = calendar.getBusinessDay(new Date(now.getMillis()), retentionDays); resource.setExpectedTerminationTime(terminationTime); - resource.setTerminationReason(TERMINATION_REASON); + resource.setTerminationReason((respectOpsWorksParentage) ? ASG_OR_OPSWORKS_TERMINATION_REASON : TERMINATION_REASON); } return false; } diff --git a/src/main/java/com/netflix/simianarmy/basic/janitor/BasicJanitorMonkeyContext.java b/src/main/java/com/netflix/simianarmy/basic/janitor/BasicJanitorMonkeyContext.java index f0860a7c..dac30086 100644 --- a/src/main/java/com/netflix/simianarmy/basic/janitor/BasicJanitorMonkeyContext.java +++ b/src/main/java/com/netflix/simianarmy/basic/janitor/BasicJanitorMonkeyContext.java @@ -208,7 +208,10 @@ private InstanceJanitor getInstanceJanitor() { "simianarmy.janitor.rule.orphanedInstanceRule.retentionDaysWithOwner", 3), (int) configuration().getNumOrElse( "simianarmy.janitor.rule.orphanedInstanceRule.retentionDaysWithoutOwner", - 8))); + 8), + configuration().getBoolOrElse( + "simianarmy.janitor.rule.orphanedInstanceRule.opsworks.parentage", + false))); } JanitorCrawler instanceCrawler; if (configuration().getBoolOrElse("simianarmy.janitor.edda.enabled", false)) { diff --git a/src/main/resources/janitor.properties b/src/main/resources/janitor.properties index 3c5a08b2..d588338f 100644 --- a/src/main/resources/janitor.properties +++ b/src/main/resources/janitor.properties @@ -59,6 +59,8 @@ simianarmy.janitor.rule.orphanedInstanceRule.retentionDaysWithOwner = 3 # The number of business days the instance is kept after a notification is sent for the termination # when the instance has no owner. simianarmy.janitor.rule.orphanedInstanceRule.retentionDaysWithoutOwner = 8 +# If true, don't consider members of an OpsWorks stack as orphans +simianarmy.janitor.rule.orphanedInstanceRule.opsworks.parentage = false # The following properties are used by the Janitor rule for cleaning up volumes that have been # detached from instances for certain days.