001package org.kuali.common.devops.ci; 002 003import static com.google.common.base.Preconditions.checkState; 004import static com.google.common.base.Stopwatch.createStarted; 005import static java.lang.String.format; 006import static java.util.Collections.reverse; 007import static java.util.Collections.sort; 008import static org.apache.commons.lang3.StringUtils.equalsIgnoreCase; 009import static org.kuali.common.devops.aws.EncryptedAWSCredentials.ENCRYPTED_AWS_CREDENTIALS_FOUNDATION; 010import static org.kuali.common.devops.ci.CreateBuildSlaveAMI.CI_SLAVE_STARTS_WITH_TOKEN; 011import static org.kuali.common.devops.ci.CreateBuildSlaveAMI.CONTEXTS; 012import static org.kuali.common.devops.ci.CreateBuildSlaveAMI.DEVOPS_KEYPAIR; 013import static org.kuali.common.devops.ci.CreateBuildSlaveAMI.getEC2Service; 014import static org.kuali.common.devops.ci.CreateBuildSlaveAMI.getFilteredImages; 015import static org.kuali.common.devops.ci.CreateBuildSlaveAMI.getJenkinsMaster; 016import static org.kuali.common.devops.ci.SpinUpJenkinsMaster.exec; 017import static org.kuali.common.devops.ci.SpinUpJenkinsMaster.getJenkinsContext; 018import static org.kuali.common.devops.ci.SpinUpJenkinsMaster.getResource; 019import static org.kuali.common.devops.ci.SpinUpJenkinsMaster.openSecureChannel; 020import static org.kuali.common.devops.ci.SpinUpJenkinsMaster.publishProject; 021import static org.kuali.common.devops.ci.model.Constants.DISTRO; 022import static org.kuali.common.devops.ci.model.Constants.DISTRO_VERSION; 023import static org.kuali.common.devops.ci.model.Constants.ROOT; 024import static org.kuali.common.devops.project.KualiDevOpsProjectConstants.KUALI_DEVOPS_PROJECT_IDENTIFIER; 025import static org.kuali.common.util.encrypt.Encryption.getDefaultEncryptor; 026import static org.kuali.common.util.log.Loggers.newLogger; 027 028import java.io.IOException; 029import java.util.List; 030 031import org.junit.Test; 032import org.kuali.common.aws.ec2.api.EC2Service; 033import org.kuali.common.core.system.VirtualSystem; 034import org.kuali.common.devops.ci.CreateBuildSlaveAMI.ImageTagsComparator; 035import org.kuali.common.devops.ci.model.JenkinsContext; 036import org.kuali.common.util.FormatUtils; 037import org.kuali.common.util.channel.api.SecureChannel; 038import org.kuali.common.util.encrypt.Encryptor; 039import org.kuali.common.util.project.model.ProjectIdentifier; 040import org.slf4j.Logger; 041 042import com.amazonaws.services.ec2.model.Image; 043import com.amazonaws.services.ec2.model.Tag; 044import com.google.common.base.Stopwatch; 045 046public class UpdateBuildSlaveAMI { 047 048 private static final Logger logger = newLogger(); 049 050 private final Stopwatch stopwatch = createStarted(); 051 private final Encryptor encryptor = getDefaultEncryptor(); 052 private final String kisUsernameEncrypted = "U2FsdGVkX18yas/kI9ymLV41TRC9tcoE8P2YaoQmtOc="; 053 private final String kisPasswordEncrypted = "U2FsdGVkX18M5faj1sGRINZ0p5dNNW3FFEPxM1lx3Gw="; 054 private final ProjectIdentifier PID = KUALI_DEVOPS_PROJECT_IDENTIFIER; 055 056 @Test 057 public void test() throws Exception { 058 VirtualSystem vs = VirtualSystem.build(); 059 // Default to quiet mode unless they've supplied -Dec2.quiet=false 060 boolean quiet = equalsIgnoreCase(vs.getProperties().getProperty("ec2.quiet"), "false") ? false : true; 061 JenkinsContext jenkinsContext = getJenkinsContext(vs, CONTEXTS); 062 EC2Service service = getEC2Service(ENCRYPTED_AWS_CREDENTIALS_FOUNDATION, jenkinsContext.getRegion()); 063 String ami = getMostRecentAMI(service, jenkinsContext); 064 String privateKey = DEVOPS_KEYPAIR.getPrivateKey(); 065 String jenkinsMaster = getJenkinsMaster(jenkinsContext); 066 updateMasterAMI(jenkinsMaster, privateKey, quiet, ami); 067 info("updated %s with ami %s - %s", jenkinsMaster, ami, FormatUtils.getTime(stopwatch)); 068 } 069 070 protected void updateMasterAMI(String jenkinsMaster, String privateKey, boolean quiet, String ami) throws IOException { 071 info("updating %s with ami [%s]", jenkinsMaster, ami); 072 String kisUsername = encryptor.decrypt(kisUsernameEncrypted); 073 String kisPassword = encryptor.decrypt(kisPasswordEncrypted); 074 SecureChannel channel = openSecureChannel(ROOT, jenkinsMaster, privateKey, quiet); 075 String basedir = publishProject(channel, PID, ROOT, jenkinsMaster, quiet); 076 String rubyScript = getResource(basedir, PID, DISTRO, DISTRO_VERSION, "jenkins/update_jenkins_ami_headless.rb"); 077 exec(channel, "ruby", rubyScript, kisUsername, kisPassword, ami, jenkinsMaster); 078 } 079 080 protected static String getMostRecentAMI(EC2Service service, JenkinsContext context) { 081 return getMostRecentAMI(service, context.getStack().getTag(), context.getName().getTag()); 082 } 083 084 protected static String getMostRecentAMI(EC2Service service, Tag stack, Tag name) { 085 086 List<Image> images = service.getMyImages(); 087 088 // Extract just the ci.slave AMI's for this stack 089 List<Image> filtered = getFilteredImages(images, stack, name.getKey(), CI_SLAVE_STARTS_WITH_TOKEN); 090 091 // This sorts them by date 092 sort(filtered, new ImageTagsComparator()); 093 094 // Most recent images are at the bottom, this brings them to the top 095 reverse(filtered); 096 097 // Make sure we have at least one image 098 checkState(filtered.size() > 0, "need at least one image"); 099 100 // Return the most recent one 101 return filtered.get(0).getImageId(); 102 } 103 104 private static void info(String msg, Object... args) { 105 if (args == null) { 106 logger.info(msg); 107 } else { 108 logger.info(format(msg, args)); 109 } 110 } 111 112}