package org.zstack.core.ansible; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.header.errorcode.OperationFailureException; import org.zstack.utils.ShellResult; import org.zstack.utils.ShellUtils; import org.zstack.utils.StringDSL.StringWrapper; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import org.zstack.utils.ssh.SshResult; import org.zstack.utils.ssh.SshShell; import static org.zstack.core.Platform.operr; import java.util.HashMap; import java.util.Map; import static org.zstack.utils.StringDSL.ln; /** * Created by frank on 12/6/2015. */ @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) public class SshFolderMd5Checker implements AnsibleChecker { private static final CLogger logger = Utils.getLogger(SshFolderMd5Checker.class); @Autowired private ErrorFacade errf; private String srcFolder; private String dstFolder; private String username; private String password; private String hostname; private int port = 22; private static StringWrapper script = ln( "if [ ! -d {0} ]; then", "echo \"cannot find the folder {0}\"", "exit 101", "fi", "files=`find {0} -type f`", "for f in $files", "do", "md5sum $f", "done", "exit 0" ); public String getSrcFolder() { return srcFolder; } public void setSrcFolder(String srcFolder) { this.srcFolder = srcFolder; } public String getDstFolder() { return dstFolder; } public void setDstFolder(String dstFolder) { this.dstFolder = dstFolder; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getHostname() { return hostname; } public void setHostname(String hostname) { this.hostname = hostname; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } @Override public boolean needDeploy() { String srcScript = script.format(srcFolder); ShellResult srcRes = ShellUtils.runAndReturn(srcScript, false); if (!srcRes.isReturnCode(0)) { throw new OperationFailureException(operr("cannot check md5sum of files in the folder[%s].\nstdout:%s\nstderr:%s", srcFolder, srcRes.getStdout(), srcRes.getStderr())); } String dstScript = script.format(dstFolder); SshShell ssh = new SshShell(); ssh.setHostname(hostname); ssh.setUsername(username); ssh.setPassword(password); ssh.setPort(port); SshResult dstRes = ssh.runScript(dstScript); if (dstRes.getReturnCode() == 101) { // dst folder doesn't existing return true; } else if (dstRes.getReturnCode() != 0) { throw new OperationFailureException(operr("cannot check md5sum of files in the folder[%s] on the host[ip:%s].\nstdout:%s\nstderr:%s", dstFolder, hostname, dstRes.getStdout(), dstRes.getStderr())); } Map<String, String> srcMd5sum = new HashMap<String, String>(); Map<String, String> dstMd5sum = new HashMap<String, String>(); for (String s : srcRes.getStdout().split("\n")) { if (StringUtils.isBlank(s)) { continue; } String[] pair = s.split(" +"); String fileName = pair[1].replaceAll(srcFolder, ""); srcMd5sum.put(fileName, pair[0]); } for (String s : dstRes.getStdout().split("\n")) { if (StringUtils.isBlank(s)) { continue; } String[] pair = s.split(" +"); String fileName = pair[1].replaceAll(dstFolder, ""); dstMd5sum.put(fileName, pair[0]); } if (dstMd5sum.size() != srcMd5sum.size()) { logger.debug(String.format("file number mismatch. the source folder[%s] contains %s files while the destination" + " folder[%s] on the host[ip:%s] contains %s files. Need to deploy the agent", srcFolder, dstFolder, srcMd5sum.size(), hostname, dstMd5sum.size())); return true; } for (Map.Entry<String, String> e : srcMd5sum.entrySet()) { String fileName = e.getKey(); String srcMd5 = e.getValue(); String dstMd5 = dstMd5sum.get(fileName); if (dstMd5 == null) { logger.debug(String.format("cannot find the file[%s] in the folder[%s] of the host[ip:%s]. Need to deploy agent", fileName, dstFolder, hostname)); return true; } if (!srcMd5.equals(dstMd5)) { logger.debug(String.format("md5[src md5: %s, dst md5: %s, dst host ip:%s] of the file[%s] changed. Need to deploy agent", srcMd5, dstMd5, hostname, fileName)); return true; } } logger.debug(String.format("no files changed on the dest host[ip:%s]", hostname)); return false; } @Override public void deleteDestFile() { // do nothing } }