/*
* Copyright 2008-2010 Xebia and the original author or authors.
*
* 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.
*/
package fr.xebia.cloud.amazon.aws.tools;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.annotation.Nonnull;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import com.amazonaws.services.identitymanagement.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClient;
import com.amazonaws.services.identitymanagement.model.StatusType;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailService;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Resources;
import fr.xebia.cloud.cloudinit.FreemarkerUtils;
/**
* Send Amazon AWS tools / command lines links and install instructions by email
*
* @author <a href="mailto:ebriand@xebia.fr">Eric Briand</a>
*/
public class AmazonAwsToolsSender {
public static void main(String[] args) throws Exception {
try {
AmazonAwsToolsSender amazonAwsToolsSender = new AmazonAwsToolsSender();
amazonAwsToolsSender.sendEmails();
} catch (Exception e) {
e.printStackTrace();
}
}
protected AmazonEC2 ec2;
protected AmazonIdentityManagement iam;
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected Session mailSession;
protected Transport mailTransport;
protected InternetAddress mailFrom;
protected AmazonSimpleEmailService ses;
public AmazonAwsToolsSender() {
try {
InputStream credentialsAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("AwsCredentials.properties");
Preconditions.checkNotNull(credentialsAsStream, "File '/AwsCredentials.properties' NOT found in the classpath");
AWSCredentials awsCredentials = new PropertiesCredentials(credentialsAsStream);
iam = new AmazonIdentityManagementClient(awsCredentials);
ses = new AmazonSimpleEmailServiceClient(awsCredentials);
ec2 = new AmazonEC2Client(awsCredentials);
ec2.setEndpoint("ec2.eu-west-1.amazonaws.com");
InputStream smtpPropertiesAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("smtp.properties");
Preconditions.checkNotNull(smtpPropertiesAsStream, "File '/smtp.properties' NOT found in the classpath");
final Properties smtpProperties = new Properties();
smtpProperties.load(smtpPropertiesAsStream);
mailSession = Session.getInstance(smtpProperties, null);
mailTransport = mailSession.getTransport();
if (smtpProperties.containsKey("mail.username")) {
mailTransport.connect(smtpProperties.getProperty("mail.username"), smtpProperties.getProperty("mail.password"));
} else {
mailTransport.connect();
}
try {
mailFrom = new InternetAddress(smtpProperties.getProperty("mail.from"));
} catch (Exception e) {
throw new MessagingException("Exception parsing 'mail.from' from 'smtp.properties'", e);
}
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
/**
* <p>
* Send the tools info by email.
* </p>
*
* @param userName
* valid email used as userName.
*/
public void sendEmail(@Nonnull final String userName) throws Exception {
Preconditions.checkNotNull(userName, "Given userName can NOT be null");
logger.debug("Process user {}", userName);
Map<String, String> templatesParams = Maps.newHashMap();
templatesParams.put("awsCredentialsHome", "~/.aws");
templatesParams.put("awsCommandLinesHome", "~/aws-tools");
templatesParams.put("awsCredentialsWindowsHome", "c:\\aws");
templatesParams.put("awsCommandLinesWindowsHome", "c:\\aws-tools");
templatesParams.put("userName", userName);
User user;
try {
user = iam.getUser(new GetUserRequest().withUserName(userName)).getUser();
} catch (NoSuchEntityException e) {
logger.debug("User {} does not exist,", userName, e);
throw e;
}
List<BodyPart> attachments = Lists.newArrayList();
templatesParams.put("credentialsFileName", "aws-credentials.txt");
// X509 SELF SIGNED CERTIFICATE
Collection<SigningCertificate> certificates = iam.listSigningCertificates(new ListSigningCertificatesRequest().withUserName(user.getUserName())).getCertificates();
// filter active certificates
certificates = Collections2.filter(certificates, new Predicate<SigningCertificate>() {
@Override
public boolean apply(SigningCertificate signingCertificate) {
return StatusType.Active.equals(StatusType.fromValue(signingCertificate.getStatus()));
}
});
SigningCertificate signingCertificate = Iterables.getFirst(certificates, null);
templatesParams.put("X509CertificateFileName", "cert-" + signingCertificate.getCertificateId() + ".pem");
templatesParams.put("X509PrivateKeyFileName", "pk-" + signingCertificate.getCertificateId() + ".pem");
sendEmail(templatesParams, attachments, userName);
}
public void sendEmails() {
URL emailsToVerifyURL = Thread.currentThread().getContextClassLoader().getResource("users-to-notify.txt");
Preconditions.checkNotNull(emailsToVerifyURL, "File 'users-to-notify.txt' NOT found in the classpath");
Collection<String> userNames;
try {
userNames = Resources.readLines(emailsToVerifyURL, Charsets.ISO_8859_1);
} catch (Exception e) {
throw Throwables.propagate(e);
}
for (String userName : userNames) {
try {
sendEmail(userName);
} catch (Exception e) {
logger.error("Failure to send email to user '{}'", userName, e);
}
// sleep 10 seconds to prevent "Throttling exception"
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
throw Throwables.propagate(e);
}
}
}
/**
*
* @param toAddress
* @throws MessagingException
*/
public void sendEmail(Map<String, String> templatesParams, List<BodyPart> attachments, String toAddress) throws MessagingException {
MimeBodyPart htmlAndPlainTextAlternativeBody = new MimeBodyPart();
// TEXT AND HTML MESSAGE (gmail requires plain text alternative,
// otherwise, it displays the 1st plain text attachment in the preview)
MimeMultipart cover = new MimeMultipart("alternative");
htmlAndPlainTextAlternativeBody.setContent(cover);
BodyPart textHtmlBodyPart = new MimeBodyPart();
String textHtmlBody = FreemarkerUtils.generate(templatesParams, "/fr/xebia/cloud/amazon/aws/tools/amazon-aws-tools-email.html.ftl");
textHtmlBodyPart.setContent(textHtmlBody, "text/html");
cover.addBodyPart(textHtmlBodyPart);
BodyPart textPlainBodyPart = new MimeBodyPart();
cover.addBodyPart(textPlainBodyPart);
String textPlainBody = FreemarkerUtils.generate(templatesParams, "/fr/xebia/cloud/amazon/aws/tools/amazon-aws-tools-email.txt.ftl");
textPlainBodyPart.setContent(textPlainBody, "text/plain");
MimeMultipart content = new MimeMultipart("related");
content.addBodyPart(htmlAndPlainTextAlternativeBody);
// ATTACHMENTS
for (BodyPart bodyPart : attachments) {
content.addBodyPart(bodyPart);
}
MimeMessage msg = new MimeMessage(mailSession);
msg.setFrom(mailFrom);
msg.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(toAddress));
msg.addRecipient(javax.mail.Message.RecipientType.CC, mailFrom);
msg.setSubject("[Xebia Amazon AWS Workshop] Tools installation procedure");
msg.setContent(content);
mailTransport.sendMessage(msg, msg.getAllRecipients());
}
}