void clean(final Id id) { if (id == null) { throw new IllegalArgumentException("id is null"); } stop(id); logger.info("Cleaning " + id); for (Container container : findAllContainers(id)) { logger.info("Removing container " + container.getId()); try { removeContainer(container); } catch (DockerException e) { throw new OrchestrationException(e); } } String imageId = null; try { imageId = findImageId(id); } catch (NotFoundException e) { logger.warn("Image " + id + " not found"); } catch (DockerException e) { throw new OrchestrationException(e); } if (imageId != null) { logger.info("Removing image " + imageId); try { docker.removeImageCmd(imageId).withForce().exec(); } catch (DockerException e) { logger.warn(e.getMessage()); } } }
private void start(final Id id) { if (id == null) { throw new IllegalArgumentException("id is null"); } final Pattern waitForPattern = compileWaitForPattern(id); logger.info("Starting " + id); try { if (!imageExists(id)) { logger.info("Image does not exist, so building it"); build(id); } } catch (DockerException e) { throw new OrchestrationException(e); } try { Container existingContainer = findContainer(id); if (existingContainer == null) { logger.info("No existing container so creating and starting new one"); startContainer(createNewContainer(id)); } else if (!isImageIdFromContainerMatchingProvidedImageId(existingContainer.getId(), id)) { logger.info("Image IDs do not match, removing container and creating new one from image"); removeContainer(existingContainer); startContainer(createNewContainer(id)); } else if (isRunning(id)) { logger.info("Container already running"); } else { logger.info("Starting existing container " + existingContainer.getId()); startContainer(existingContainer.getId()); } try (Tail tail = tailFactory.newTail(docker, findContainer(id), logger)) { tail.start(); for (Plugin plugin : plugins) { plugin.started(id, conf(id)); } healthCheck(id); sleep(id); tail.setMaxLines(conf(id).getMaxLogLines()); } waitFor(id, waitForPattern); } catch (DockerException e) { throw new OrchestrationException(e); } }
private boolean isRunning(Id id) { if (id == null) { throw new IllegalArgumentException("id is null"); } boolean running = false; final Container candidate = findContainer(id); for (Container container : docker.listContainersCmd().withShowAll(false).exec()) { running |= candidate != null && candidate.getId().equals(container.getId()); } return running; }
private void waitFor(Id id, Pattern pattern) { if (pattern == null) { return; } final StopWatch watch = new StopWatch(); watch.start(); logger.info(String.format("Waiting for '%s' to appear in output", pattern.toString())); final Container container; try { container = findContainer(id); } catch (DockerException e) { throw new OrchestrationException(e); } if (container == null) { logger.warn(String.format("Can not find container %s, not waiting", id)); return; } try { final LogContainerCmd logContainerCmd = docker .logContainerCmd(container.getId()) .withStdErr() .withStdOut() .withFollowStream() .withTimestamps(); final InputStream stream = logContainerCmd.exec(); try (final BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { String line; while ((line = reader.readLine()) != null) { if (pattern.matcher(line).find()) { watch.stop(); logger.info(String.format("Waited for %s", watch.toString())); return; } } throw new OrchestrationException("Container log ended before line appeared in output"); } } catch (Exception e) { logger.warn( "Unable to obtain logs from container " + container.getId() + ", will continue without waiting: ", e); } }
private List<Container> findContainers(Id id, boolean allContainers) { final List<Container> matchingContainers = new ArrayList<>(); for (Container container : docker.listContainersCmd().withShowAll(allContainers).exec()) { boolean imageNameMatches = container.getImage().equals(repo.imageName(id)); String[] containerNames = container.getNames(); if (containerNames == null) { // Every container should have a name, but this is not the case // on Circle CI. Containers with no name are broken residues of // building the image and therefore will be ignored. continue; } boolean containerNameMatches = asList(containerNames).contains(containerName(id)); if (imageNameMatches || containerNameMatches) { matchingContainers.add(container); } } return matchingContainers; }
private void stop(final Id id) { if (id == null) { throw new IllegalArgumentException("id is null"); } logger.info("Stopping " + id); for (Container container : findRunningContainers(id)) { logger.info("Stopping container " + Arrays.toString(container.getNames())); try { docker.stopContainerCmd(container.getId()).withTimeout(1).exec(); } catch (DockerException e) { throw new OrchestrationException(e); } } for (Plugin plugin : plugins) { plugin.stopped(id, conf(id)); } }
private void removeContainer(Container existingContainer) { try { docker.removeContainerCmd(existingContainer.getId()).withForce().exec(); } catch (InternalServerErrorException e) { if (permissionErrorTolerant && isPermissionError(e)) { logger.warn( String.format( "ignoring %s when removing container as we are configured to be permission error tolerant", e)); } else { throw e; } } }