Skip to content

Commit

Permalink
Merge pull request #774 from HubSpot/request-email-override
Browse files Browse the repository at this point in the history
allow requests to override their email notification settings
  • Loading branch information
Tom Petr committed Jan 4, 2016
2 parents 9339962 + 63c7eee commit 50de17f
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.hubspot.singularity;

public enum SingularityEmailDestination {
OWNERS, ACTION_TAKER, ADMINS
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.hubspot.singularity;

public enum SingularityEmailType {
TASK_LOST, TASK_KILLED, TASK_FINISHED_SCHEDULED, TASK_FINISHED_LONG_RUNNING, TASK_FINISHED_ON_DEMAND, TASK_FINISHED_RUN_ONCE, TASK_FAILED, TASK_SCHEDULED_OVERDUE_TO_FINISH,
TASK_KILLED_DECOMISSIONED, TASK_KILLED_UNHEALTHY, REQUEST_IN_COOLDOWN, SINGULARITY_ABORTING, REQUEST_REMOVED, REQUEST_PAUSED, REQUEST_UNPAUSED, TASK_FAILED_DECOMISSIONED
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public class SingularityRequest {
private final Optional<Set<String>> readOnlyGroups;
private final Optional<Boolean> bounceAfterScale;

private final Optional<Map<SingularityEmailType, List<SingularityEmailDestination>>> emailConfigurationOverrides;

@JsonCreator
public SingularityRequest(@JsonProperty("id") String id, @JsonProperty("requestType") RequestType requestType, @JsonProperty("owners") Optional<List<String>> owners,
@JsonProperty("numRetriesOnFailure") Optional<Integer> numRetriesOnFailure, @JsonProperty("schedule") Optional<String> schedule, @JsonProperty("daemon") Optional<Boolean> daemon, @JsonProperty("instances") Optional<Integer> instances,
Expand All @@ -55,7 +57,8 @@ public SingularityRequest(@JsonProperty("id") String id, @JsonProperty("requestT
@JsonProperty("quartzSchedule") Optional<String> quartzSchedule, @JsonProperty("rackAffinity") Optional<List<String>> rackAffinity,
@JsonProperty("slavePlacement") Optional<SlavePlacement> slavePlacement, @JsonProperty("requiredSlaveAttributes") Optional<Map<String, String>> requiredSlaveAttributes, @JsonProperty("allowedSlaveAttributes") Optional<Map<String, String>> allowedSlaveAttributes,
@JsonProperty("scheduledExpectedRuntimeMillis") Optional<Long> scheduledExpectedRuntimeMillis, @JsonProperty("waitAtLeastMillisAfterTaskFinishesForReschedule") Optional<Long> waitAtLeastMillisAfterTaskFinishesForReschedule, @JsonProperty("group") Optional<String> group,
@JsonProperty("readOnlyGroups") Optional<Set<String>> readOnlyGroups, @JsonProperty("bounceAfterScale") Optional<Boolean> bounceAfterScale) {
@JsonProperty("readOnlyGroups") Optional<Set<String>> readOnlyGroups, @JsonProperty("bounceAfterScale") Optional<Boolean> bounceAfterScale,
@JsonProperty("emailConfigurationOverrides") Optional<Map<SingularityEmailType, List<SingularityEmailDestination>>> emailConfigurationOverrides) {
this.id = id;
this.owners = owners;
this.numRetriesOnFailure = numRetriesOnFailure;
Expand All @@ -76,6 +79,7 @@ public SingularityRequest(@JsonProperty("id") String id, @JsonProperty("requestT
this.group = group;
this.readOnlyGroups = readOnlyGroups;
this.bounceAfterScale = bounceAfterScale;
this.emailConfigurationOverrides = emailConfigurationOverrides;

if (requestType == null) {
this.requestType = RequestType.fromDaemonAndScheduleAndLoadBalanced(schedule, daemon, loadBalanced);
Expand Down Expand Up @@ -103,7 +107,8 @@ public SingularityRequestBuilder toBuilder() {
.setScheduledExpectedRuntimeMillis(scheduledExpectedRuntimeMillis)
.setGroup(group)
.setReadOnlyGroups(readOnlyGroups)
.setBounceAfterScale(bounceAfterScale);
.setBounceAfterScale(bounceAfterScale)
.setEmailConfigurationOverrides(emailConfigurationOverrides);
}

public String getId() {
Expand Down Expand Up @@ -251,6 +256,10 @@ public Optional<Boolean> getBounceAfterScale() {
return bounceAfterScale;
}

public Optional<Map<SingularityEmailType, List<SingularityEmailDestination>>> getEmailConfigurationOverrides() {
return emailConfigurationOverrides;
}

@Override
public String toString() {
return "SingularityRequest[" +
Expand All @@ -275,6 +284,7 @@ public String toString() {
", group=" + group +
", readOnlyGroups=" + readOnlyGroups +
", bounceAfterScale=" + bounceAfterScale +
", emailConfigurationOverrides=" + emailConfigurationOverrides +
']';
}

Expand Down Expand Up @@ -306,11 +316,12 @@ public boolean equals(Object o) {
Objects.equals(loadBalanced, request.loadBalanced) &&
Objects.equals(group, request.group) &&
Objects.equals(readOnlyGroups, request.readOnlyGroups) &&
Objects.equals(bounceAfterScale, request.bounceAfterScale);
Objects.equals(bounceAfterScale, request.bounceAfterScale) &&
Objects.equals(emailConfigurationOverrides, request.emailConfigurationOverrides);
}

@Override
public int hashCode() {
return Objects.hash(id, requestType, owners, numRetriesOnFailure, schedule, quartzSchedule, scheduleType, killOldNonLongRunningTasksAfterMillis, scheduledExpectedRuntimeMillis, waitAtLeastMillisAfterTaskFinishesForReschedule, instances, rackSensitive, rackAffinity, slavePlacement, requiredSlaveAttributes, allowedSlaveAttributes, loadBalanced, group, readOnlyGroups, bounceAfterScale);
return Objects.hash(id, requestType, owners, numRetriesOnFailure, schedule, quartzSchedule, scheduleType, killOldNonLongRunningTasksAfterMillis, scheduledExpectedRuntimeMillis, waitAtLeastMillisAfterTaskFinishesForReschedule, instances, rackSensitive, rackAffinity, slavePlacement, requiredSlaveAttributes, allowedSlaveAttributes, loadBalanced, group, readOnlyGroups, bounceAfterScale, emailConfigurationOverrides);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class SingularityRequestBuilder {
private Optional<String> group;
private Optional<Set<String>> readOnlyGroups;
private Optional<Boolean> bounceAfterScale;
private Optional<Map<SingularityEmailType, List<SingularityEmailDestination>>> emailConfigurationOverrides;

public SingularityRequestBuilder(String id, RequestType requestType) {
this.id = id;
Expand All @@ -64,11 +65,12 @@ public SingularityRequestBuilder(String id, RequestType requestType) {
this.group = Optional.absent();
this.readOnlyGroups = Optional.absent();
this.bounceAfterScale = Optional.absent();
this.emailConfigurationOverrides = Optional.absent();
}

public SingularityRequest build() {
return new SingularityRequest(id, requestType, owners, numRetriesOnFailure, schedule, daemon, instances, rackSensitive, loadBalanced, killOldNonLongRunningTasksAfterMillis, scheduleType, quartzSchedule,
rackAffinity, slavePlacement, requiredSlaveAttributes, allowedSlaveAttributes, scheduledExpectedRuntimeMillis, waitAtLeastMillisAfterTaskFinishesForReschedule, group, readOnlyGroups, bounceAfterScale);
rackAffinity, slavePlacement, requiredSlaveAttributes, allowedSlaveAttributes, scheduledExpectedRuntimeMillis, waitAtLeastMillisAfterTaskFinishesForReschedule, group, readOnlyGroups, bounceAfterScale, emailConfigurationOverrides);
}


Expand Down Expand Up @@ -245,6 +247,15 @@ public SingularityRequestBuilder setBounceAfterScale(Optional<Boolean> bounceAft
return this;
}

public Optional<Map<SingularityEmailType, List<SingularityEmailDestination>>> getEmailConfigurationOverrides() {
return emailConfigurationOverrides;
}

public SingularityRequestBuilder setEmailConfigurationOverrides(Optional<Map<SingularityEmailType, List<SingularityEmailDestination>>> emailConfigurationOverrides) {
this.emailConfigurationOverrides = emailConfigurationOverrides;
return this;
}

@Override
public String toString() {
return "SingularityRequestBuilder[" +
Expand All @@ -269,6 +280,7 @@ public String toString() {
", group=" + group +
", readOnlyGroups=" + readOnlyGroups +
", bounceAfterScale=" + bounceAfterScale +
", emailConfigurationOverrides=" + emailConfigurationOverrides +
']';
}

Expand Down Expand Up @@ -300,11 +312,12 @@ public boolean equals(Object o) {
Objects.equals(loadBalanced, that.loadBalanced) &&
Objects.equals(group, that.group) &&
Objects.equals(readOnlyGroups, that.readOnlyGroups) &&
Objects.equals(bounceAfterScale, that.bounceAfterScale);
Objects.equals(bounceAfterScale, that.bounceAfterScale) &&
Objects.equals(emailConfigurationOverrides, that.emailConfigurationOverrides);
}

@Override
public int hashCode() {
return Objects.hash(id, requestType, owners, numRetriesOnFailure, schedule, quartzSchedule, scheduleType, killOldNonLongRunningTasksAfterMillis, scheduledExpectedRuntimeMillis, waitAtLeastMillisAfterTaskFinishesForReschedule, instances, rackSensitive, rackAffinity, slavePlacement, requiredSlaveAttributes, allowedSlaveAttributes, loadBalanced, group, readOnlyGroups, bounceAfterScale);
return Objects.hash(id, requestType, owners, numRetriesOnFailure, schedule, quartzSchedule, scheduleType, killOldNonLongRunningTasksAfterMillis, scheduledExpectedRuntimeMillis, waitAtLeastMillisAfterTaskFinishesForReschedule, instances, rackSensitive, rackAffinity, slavePlacement, requiredSlaveAttributes, allowedSlaveAttributes, loadBalanced, group, readOnlyGroups, bounceAfterScale, emailConfigurationOverrides);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
import com.google.common.net.HostAndPort;
import com.google.inject.Inject;
import com.hubspot.mesos.JavaUtils;
import com.hubspot.singularity.config.EmailConfigurationEnums.EmailDestination;
import com.hubspot.singularity.config.EmailConfigurationEnums.EmailType;
import com.hubspot.singularity.config.SMTPConfiguration;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.sentry.SingularityExceptionNotifier;
Expand Down Expand Up @@ -106,9 +104,9 @@ private void sendAbortMail(final String message, final Optional<Throwable> throw
return;
}

final List<EmailDestination> emailDestination = maybeSmtpConfiguration.get().getEmailConfiguration().get(EmailType.SINGULARITY_ABORTING);
final List<SingularityEmailDestination> emailDestination = maybeSmtpConfiguration.get().getEmailConfiguration().get(SingularityEmailType.SINGULARITY_ABORTING);

if (emailDestination.isEmpty() || !emailDestination.contains(EmailDestination.ADMINS)) {
if (emailDestination.isEmpty() || !emailDestination.contains(SingularityEmailDestination.ADMINS)) {
LOG.info("Not configured to send abort mail");
return;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.hubspot.singularity.config.EmailConfigurationEnums.EmailDestination;
import com.hubspot.singularity.config.EmailConfigurationEnums.EmailType;
import com.hubspot.singularity.SingularityEmailDestination;
import com.hubspot.singularity.SingularityEmailType;

public class SMTPConfiguration {

Expand Down Expand Up @@ -67,25 +67,25 @@ public class SMTPConfiguration {
private List<String> taskEmailTailFiles = Arrays.asList("stdout", "stderr");

@JsonProperty("emails")
private Map<EmailType, List<EmailDestination>> emailConfiguration = Maps.newHashMap(ImmutableMap.<EmailType, List<EmailDestination>>builder()
.put(EmailType.REQUEST_IN_COOLDOWN, ImmutableList.of(EmailDestination.ADMINS, EmailDestination.OWNERS))
.put(EmailType.SINGULARITY_ABORTING, ImmutableList.of(EmailDestination.ADMINS))
.put(EmailType.TASK_FAILED, ImmutableList.of(EmailDestination.ADMINS, EmailDestination.OWNERS, EmailDestination.ACTION_TAKER))
.put(EmailType.TASK_LOST, ImmutableList.of(EmailDestination.ADMINS, EmailDestination.ACTION_TAKER))
.put(EmailType.TASK_FINISHED_LONG_RUNNING, ImmutableList.of(EmailDestination.OWNERS, EmailDestination.ADMINS))
.put(EmailType.TASK_FINISHED_ON_DEMAND, ImmutableList.of(EmailDestination.OWNERS, EmailDestination.ACTION_TAKER))
.put(EmailType.TASK_SCHEDULED_OVERDUE_TO_FINISH, ImmutableList.of(EmailDestination.OWNERS, EmailDestination.ADMINS))
.put(EmailType.TASK_KILLED_UNHEALTHY, ImmutableList.of(EmailDestination.OWNERS, EmailDestination.ADMINS))
.put(EmailType.REQUEST_PAUSED, ImmutableList.of(EmailDestination.OWNERS, EmailDestination.ADMINS))
.put(EmailType.REQUEST_REMOVED, ImmutableList.of(EmailDestination.OWNERS, EmailDestination.ADMINS))
.put(EmailType.REQUEST_UNPAUSED, ImmutableList.of(EmailDestination.OWNERS, EmailDestination.ADMINS))
private Map<SingularityEmailType, List<SingularityEmailDestination>> emailConfiguration = Maps.newHashMap(ImmutableMap.<SingularityEmailType, List<SingularityEmailDestination>>builder()
.put(SingularityEmailType.REQUEST_IN_COOLDOWN, ImmutableList.of(SingularityEmailDestination.ADMINS, SingularityEmailDestination.OWNERS))
.put(SingularityEmailType.SINGULARITY_ABORTING, ImmutableList.of(SingularityEmailDestination.ADMINS))
.put(SingularityEmailType.TASK_FAILED, ImmutableList.of(SingularityEmailDestination.ADMINS, SingularityEmailDestination.OWNERS, SingularityEmailDestination.ACTION_TAKER))
.put(SingularityEmailType.TASK_LOST, ImmutableList.of(SingularityEmailDestination.ADMINS, SingularityEmailDestination.ACTION_TAKER))
.put(SingularityEmailType.TASK_FINISHED_LONG_RUNNING, ImmutableList.of(SingularityEmailDestination.OWNERS, SingularityEmailDestination.ADMINS))
.put(SingularityEmailType.TASK_FINISHED_ON_DEMAND, ImmutableList.of(SingularityEmailDestination.OWNERS, SingularityEmailDestination.ACTION_TAKER))
.put(SingularityEmailType.TASK_SCHEDULED_OVERDUE_TO_FINISH, ImmutableList.of(SingularityEmailDestination.OWNERS, SingularityEmailDestination.ADMINS))
.put(SingularityEmailType.TASK_KILLED_UNHEALTHY, ImmutableList.of(SingularityEmailDestination.OWNERS, SingularityEmailDestination.ADMINS))
.put(SingularityEmailType.REQUEST_PAUSED, ImmutableList.of(SingularityEmailDestination.OWNERS, SingularityEmailDestination.ADMINS))
.put(SingularityEmailType.REQUEST_REMOVED, ImmutableList.of(SingularityEmailDestination.OWNERS, SingularityEmailDestination.ADMINS))
.put(SingularityEmailType.REQUEST_UNPAUSED, ImmutableList.of(SingularityEmailDestination.OWNERS, SingularityEmailDestination.ADMINS))
.build());

public Map<EmailType, List<EmailDestination>> getEmailConfiguration() {
public Map<SingularityEmailType, List<SingularityEmailDestination>> getEmailConfiguration() {
return emailConfiguration;
}

public void setEmailConfiguration(Map<EmailType, List<EmailDestination>> emailConfiguration) {
public void setEmailConfiguration(Map<SingularityEmailType, List<SingularityEmailDestination>> emailConfiguration) {
this.emailConfiguration.putAll(emailConfiguration);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import com.google.common.base.Optional;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.hubspot.singularity.SingularityEmailType;
import com.hubspot.singularity.SingularityRequest;
import com.hubspot.singularity.config.EmailConfigurationEnums.EmailType;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.transcoders.StringTranscoder;

Expand Down Expand Up @@ -58,7 +58,7 @@ public void setZkDataVersion(String newVersion) {
save(ZK_DATA_VERSION_PATH, Optional.of(newVersion.getBytes(UTF_8)));
}

public void saveMailRecord(SingularityRequest request, EmailType emailType) {
public void saveMailRecord(SingularityRequest request, SingularityEmailType emailType) {
create(getMailRecordPathForRequestAndTypeAndTime(request.getId(), emailType.name(), Long.toString(System.currentTimeMillis())));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
import com.hubspot.mesos.MesosUtils;
import com.hubspot.mesos.json.MesosFileChunkObject;
import com.hubspot.singularity.ExtendedTaskState;
import com.hubspot.singularity.SingularityEmailType;
import com.hubspot.singularity.SingularityTask;
import com.hubspot.singularity.SingularityTaskHistoryUpdate;
import com.hubspot.singularity.SingularityTaskId;
import com.hubspot.singularity.config.EmailConfigurationEnums;
import com.hubspot.singularity.config.SMTPConfiguration;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.SandboxManager;
Expand Down Expand Up @@ -212,8 +212,8 @@ public String getSingularityLogLink(String logPath, String taskId) {
* @param history task history.
* @return subject line string.
*/
public String getSubjectForTaskHistory(SingularityTaskId taskId, ExtendedTaskState state, EmailConfigurationEnums.EmailType type, Collection<SingularityTaskHistoryUpdate> history) {
if (type == EmailConfigurationEnums.EmailType.TASK_SCHEDULED_OVERDUE_TO_FINISH) {
public String getSubjectForTaskHistory(SingularityTaskId taskId, ExtendedTaskState state, SingularityEmailType type, Collection<SingularityTaskHistoryUpdate> history) {
if (type == SingularityEmailType.TASK_SCHEDULED_OVERDUE_TO_FINISH) {
return String.format("Task is overdue to finish (%s)", taskId.toString());
}

Expand Down
Loading

0 comments on commit 50de17f

Please sign in to comment.