001package io.ebean.docker.commands; 002 003import io.ebean.docker.commands.process.ProcessHandler; 004import io.ebean.docker.commands.process.ProcessResult; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008import java.util.ArrayList; 009import java.util.Arrays; 010import java.util.List; 011 012/** 013 * Common Docker container commands. 014 */ 015public class Commands { 016 017 private static final Logger log = LoggerFactory.getLogger(Commands.class); 018 019 private final String docker; 020 021 /** 022 * Create with 'docker' as the command. 023 */ 024 public Commands() { 025 this("docker"); 026 } 027 028 /** 029 * Construct with explicit docker command. 030 */ 031 public Commands(String docker) { 032 this.docker = docker; 033 } 034 035 /** 036 * Stop the container checking to see if it is running first. 037 */ 038 public void stopIfRunning(String containerName) { 039 if (isRunning(containerName)) { 040 stop(containerName); 041 } 042 } 043 044 /** 045 * Stop and remove the container. 046 */ 047 public void stopRemove(String containerName) { 048 if (isRunning(containerName)) { 049 stop(containerName); 050 } 051 052 if (isRegistered(containerName)) { 053 remove(containerName); 054 } 055 } 056 057 /** 058 * Remove the container. 059 */ 060 public void remove(String containerName) { 061 log.debug("remove {}", containerName); 062 ProcessHandler.command(docker, "rm", containerName); 063 } 064 065 /** 066 * Start the container. 067 */ 068 public void start(String containerName) { 069 log.debug("start {}", containerName); 070 ProcessHandler.command(docker, "start", containerName); 071 } 072 073 /** 074 * Stop the container. 075 */ 076 public void stop(String containerName) { 077 log.debug("stop {}", containerName); 078 ProcessHandler.command(docker, "stop", containerName); 079 } 080 081 public void removeContainers(String... containerNames) { 082 log.debug("remove {}", Arrays.toString(containerNames)); 083 try { 084 dockerCmd("rm", containerNames); 085 } catch (CommandException e) { 086 log.debug("removing containers that don't exist " + e.getMessage()); 087 } 088 } 089 090 public void stopContainers(String... containerNames) { 091 log.debug("stop {}", Arrays.toString(containerNames)); 092 try { 093 dockerCmd("stop", containerNames); 094 } catch (CommandException e) { 095 log.debug("stopping containers that don't exist " + e.getMessage()); 096 } 097 } 098 099 private void dockerCmd(String cmd, String[] containerNames) { 100 final List<String> cmds = new ArrayList<>(); 101 cmds.add(docker); 102 cmds.add(cmd); 103 for (String containerName : containerNames) { 104 cmds.add(containerName); 105 } 106 ProcessHandler.command(cmds); 107 } 108 109 /** 110 * Return true if the container is running. 111 */ 112 public boolean isRunning(String containerName) { 113 return running().contains(containerName); 114 } 115 116 /** 117 * Return true if the container is registered (exists and maybe running or not). 118 */ 119 public boolean isRegistered(String containerName) { 120 return registered().contains(containerName); 121 } 122 123 /** 124 * Return true if the logs of the container contain the match text. 125 */ 126 public boolean logsContain(String containerName, String match) { 127 return logsContain(containerName, match, null); 128 } 129 130 public boolean logsContain(String containerName, String match, String clearMatch) { 131 List<String> matchLines = logsWithMatch(containerName, match, clearMatch); 132 return !matchLines.isEmpty(); 133 } 134 135 /** 136 * Return true if the logs of the container contain the match text. 137 */ 138 public List<String> logsWithMatch(String containerName, String match, String clearMatch) { 139 ProcessResult result = ProcessHandler.matchCommand(match, clearMatch, docker, "logs", containerName); 140 return result.getOutLines(); 141 } 142 143 /** 144 * Return true if the logs of the container contain the match text. 145 */ 146 public List<String> logs(String containerName) { 147 ProcessResult result = ProcessHandler.command(docker, "logs", containerName); 148 return result.getOutLines(); 149 } 150 151 /** 152 * Return the list of containers currently running. 153 */ 154 private List<String> running() { 155 ProcessResult result = ProcessHandler.command(docker, "ps", "--format", "{{.Names}}"); 156 return result.getOutLines(); 157 } 158 159 /** 160 * Return the list of containers which maybe running or not. 161 */ 162 private List<String> registered() { 163 ProcessResult result = ProcessHandler.command(docker, "ps", "-a", "--format", "{{.Names}}"); 164 return result.getOutLines(); 165 } 166 167 /** 168 * Check if the port matches the existing port bindings and if not return the existing port bindings. 169 */ 170 public String registeredPortMatch(String containerName, int matchPort) { 171 ProcessResult result = ProcessHandler.command(docker, "container", "inspect", containerName, "--format={{.HostConfig.PortBindings}}"); 172 List<String> outLines = result.getOutLines(); 173 for (String outLine : outLines) { 174 if (outLine.startsWith("map")) { 175 if (outLine.contains("{ " + matchPort + "}")) { 176 // port matching all good 177 return null; 178 } else { 179 // mismatch - return all the PortBindings to include in exception message 180 return outLine; 181 } 182 } 183 } 184 // container doesn't exist 185 return null; 186 } 187 188 /** 189 * Return true if the container logs contains the logMessage. 190 * <p> 191 * Usually used to find a log entry to indicate the container is ready for use. 192 * </p> 193 * 194 * @param containerName The container logs to search 195 * @param logMessage The logMessage we are looking for (to usually indicate the container is ready). 196 * @param tail The number of logs to tail (such that we get recent and minimal logs) 197 * @return True if the logs searched contain the logMessage 198 */ 199 public boolean logsContain(String containerName, String logMessage, int tail) { 200 201 List<String> lines = logs(containerName, tail); 202 for (String line : lines) { 203 if (line.contains(logMessage)) { 204 return true; 205 } 206 } 207 return false; 208 } 209 210 /** 211 * Return the logs for the container with a tail. 212 * <p> 213 * If tail = 0 then all logs are returned (but we should be careful using that). 214 * </p> 215 */ 216 public List<String> logs(String containerName, int tail) { 217 218 ProcessResult result; 219 if (tail > 0) { 220 result = ProcessHandler.command(docker, "logs", "--tail", Integer.toString(tail), containerName); 221 } else { 222 result = ProcessHandler.command(docker, "logs", containerName); 223 } 224 return result.getOutLines(); 225 } 226 227}