package com.sequenceiq.cloudbreak.service.cluster.flow;
import static org.springframework.ui.freemarker.FreeMarkerTemplateUtils.processTemplateIntoString;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import org.apache.commons.lang3.time.DurationFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.google.api.client.repackaged.com.google.common.base.Strings;
import com.sequenceiq.cloudbreak.domain.CbUser;
import com.sequenceiq.cloudbreak.domain.Cluster;
import com.sequenceiq.cloudbreak.domain.InstanceGroup;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.service.CloudbreakServiceException;
import com.sequenceiq.cloudbreak.service.ComponentConfigProvider;
import com.sequenceiq.cloudbreak.service.image.ImageService;
import com.sequenceiq.cloudbreak.service.user.UserDetailsService;
import com.sequenceiq.cloudbreak.service.user.UserFilterField;
import freemarker.template.Configuration;
@Service
public class EmailSenderService {
private static final Logger LOGGER = LoggerFactory.getLogger(EmailSenderService.class);
private static final String CLUSTER_READY_SUBJECT = "Your cluster '%s' is ready";
@Value("${cb.smtp.sender.from:}")
private String msgFrom;
@Value("${cb.success.cluster.installer.mail.template.path:}")
private String successClusterMailTemplatePath;
@Value("${cb.failed.cluster.installer.mail.template.path:}")
private String failedClusterMailTemplatePath;
@Value("${cb.smartsense.configure:false}")
private boolean configureSmartSense;
@Value("${hwx.cloud.template.version:}")
private String templateVersion;
@Value("${hwx.cloud.address:}")
private String cloudAddress;
@Value("${aws.instance.id:}")
private String awsInstanceId;
@Value("${aws.account.id:}")
private String accountId;
@Inject
private EmailMimeMessagePreparator emailMimeMessagePreparator;
@Inject
private JavaMailSender mailSender;
@Inject
private ImageService imageService;
@Inject
private Configuration freemarkerConfiguration;
@Inject
private UserDetailsService userDetailsService;
@Inject
private ComponentConfigProvider componentConfigProvider;
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private enum State {
PROVISIONING_SUCCESS("SUCCESS", "Cluster Install Success",
"Your cluster '%s' is ready"),
PROVISIONING_FAILURE("FAILED", "Cluster Install Failed",
"Something went terribly wrong - we are happy to help, please let us know your cluster details, "
+ "time, etc - and we will check the logs and get a fix for you."),
START_SUCCESS("SUCCESS", "Cluster Start Success",
"Your cluster '%s' is ready"),
START_FAILURE("FAILED", "Cluster Start Failed",
"Failed to start your cluster: %s - we are happy to help, please let us know your cluster details, time, etc - and we will check the"
+ " logs and get a fix for you."),
STOP_SUCCESS("SUCCESS", "Cluster Stop Success",
"Your cluster '%s' was successfully stopped. If you want to use again just restart."),
STOP_FAILURE("FAILED", "Cluster Stop Failed",
"Failed to stop your cluster: %s - we are happy to help, please let us know your cluster details, time, etc - and we will check the "
+ "logs and get a fix for you."),
UPSCALE_SUCCESS("SUCCESS", "Cluster Upscale Success",
"Your cluster '%s' is ready"),
DOWN_SCALE_SUCCESS("SUCCESS", "Cluster Downscale Success",
"Your cluster '%s' is ready"),
TERMINATION_SUCCESS("SUCCESS", "Cluster Termination Success",
"Your cluster '%s' was successfully terminated."),
TERMINATION_FAILURE("FAILED", "Cluster Termination Failed",
"Failed to terminate your cluster: '%s'. Please try again... - we are happy to help, please let us know your cluster details, time, "
+ "etc - and we will check the logs and get a fix for you.");
private final String status;
private final String title;
private final String text;
State(String status, String title, String text) {
this.status = status;
this.title = title;
this.text = text;
}
}
private static String getRunningTime(Cluster cluster) {
long upTime = cluster.getUpSince() == null || !cluster.isAvailable() ? 0L : new Date().getTime() - cluster.getUpSince();
return uptimeToFormattedString(upTime);
}
private static String uptimeToFormattedString(long upTime) {
return DurationFormatUtils.formatDuration(upTime, "HH:mm:ss");
}
private boolean isHwxCloud() {
return !Strings.isNullOrEmpty(templateVersion);
}
@Async
public void sendProvisioningSuccessEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, successClusterMailTemplatePath, String.format(CLUSTER_READY_SUBJECT, clusterName), getEmailModel(user.getGivenName(),
ambariServer, State.PROVISIONING_SUCCESS, clusterName));
}
@Async
public void sendProvisioningFailureEmail(String owner, String email, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, failedClusterMailTemplatePath, "Cluster install failed", getEmailModel(user.getGivenName(),
null, State.PROVISIONING_FAILURE, clusterName));
}
@Async
public void sendStartSuccessEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, successClusterMailTemplatePath, String.format(CLUSTER_READY_SUBJECT, clusterName), getEmailModel(user.getGivenName(),
ambariServer, State.START_SUCCESS, clusterName));
}
@Async
public void sendStartFailureEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, failedClusterMailTemplatePath, "Cluster start failed", getEmailModel(user.getGivenName(),
ambariServer, State.START_FAILURE, clusterName));
}
@Async
public void sendStopSuccessEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, successClusterMailTemplatePath, "Your cluster has been stopped", getEmailModel(user.getGivenName(),
ambariServer, State.STOP_SUCCESS, clusterName));
}
@Async
public void sendStopFailureEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, failedClusterMailTemplatePath, "Cluster stop failed", getEmailModel(user.getGivenName(),
ambariServer, State.STOP_FAILURE, clusterName));
}
public void sendUpscaleSuccessEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, successClusterMailTemplatePath, String.format(CLUSTER_READY_SUBJECT, clusterName), getEmailModel(user.getGivenName(),
ambariServer, State.UPSCALE_SUCCESS, clusterName));
}
@Async
public void sendDownScaleSuccessEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, successClusterMailTemplatePath, String.format(CLUSTER_READY_SUBJECT, clusterName), getEmailModel(user.getGivenName(),
ambariServer, State.DOWN_SCALE_SUCCESS, clusterName));
}
@Async
public void sendTerminationSuccessEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, successClusterMailTemplatePath, "Your cluster has been terminated", getEmailModel(user.getGivenName(),
ambariServer, State.TERMINATION_SUCCESS, clusterName));
}
@Async
public void sendTerminationFailureEmail(String owner, String email, String ambariServer, String clusterName) {
CbUser user = userDetailsService.getDetails(owner, UserFilterField.USERID);
sendEmail(user, email, failedClusterMailTemplatePath, "Cluster termination failed", getEmailModel(user.getGivenName(),
ambariServer, State.TERMINATION_FAILURE, clusterName));
}
private String getInstanceTypes(Stack stack) {
StringBuilder instanceTypesStringBuilder = new StringBuilder();
for (InstanceGroup instanceGroup : stack.getInstanceGroups()) {
String instanceType = instanceGroup.getTemplate().getInstanceType();
instanceTypesStringBuilder.append("<br />").append(" - ");
instanceTypesStringBuilder.append(instanceGroup.getGroupName()).append(" (").append(instanceGroup.getNodeCount()).append(") : ");
instanceTypesStringBuilder.append(instanceType);
}
return instanceTypesStringBuilder.toString();
}
private String getMasterInstanceId(Stack stack) {
return stack.getPrimaryGatewayInstance().getInstanceId();
}
private void sendEmail(CbUser user, String mail, String template, String subject, Map<String, Object> model) {
try {
String emailBody = processTemplateIntoString(freemarkerConfiguration.getTemplate(template, "UTF-8"), model);
LOGGER.debug("Sending email. Content: {}", emailBody);
mailSender.send(emailMimeMessagePreparator.prepareMessage(Strings.isNullOrEmpty(mail) ? user.getUsername() : mail, subject, emailBody));
} catch (Exception e) {
LOGGER.error("Could not send email. User: {}", user.getUserId());
throw new CloudbreakServiceException(e);
}
}
private Map<String, Object> getEmailModel(String name, String server, State state, String clusterName) {
Map<String, Object> model = new HashMap<>();
model.put("status", state.status);
model.put("name", name);
model.put("text", String.format(state.text, clusterName, server));
model.put("title", state.title);
model.put("state", state);
model.put("clusterName", clusterName);
model.put("hwx_cloud", isHwxCloud());
model.put("server", isHwxCloud() ? cloudAddress : server);
return model;
}
}