public synchronized static ResourceReaper instance() { if (instance == null) { instance = new ResourceReaper(); } return instance; }
private void registerContainersForShutdown() { ResourceReaper.instance().registerFilterForCleanup(Arrays.asList( new SimpleEntry<>("label", "com.docker.compose.project=" + project) )); }
/** * Removes a network by ID. * @param id */ public void removeNetworkById(String id) { removeNetwork(id); }
@Override public void close() { if (initialized.getAndSet(false)) { ResourceReaper.instance().removeNetworkById(id); } } }
/** * Stops the container. */ @Override public void stop() { if (containerId == null) { return; } try { String imageName; try { imageName = image.get(); } catch (Exception e) { imageName = "<unknown>"; } ResourceReaper.instance().stopAndRemoveContainer(containerId, imageName); } finally { containerId = null; containerInfo = null; } }
@Deprecated public static String start(String hostIpAddress, DockerClient client, boolean withDummyMount) { return start(hostIpAddress, client); }
/** * Removes a network by ID. * @param identifier * @deprecated see {@link ResourceReaper#removeNetworkById(String)} */ @Deprecated public void removeNetworks(String identifier) { removeNetworkById(identifier); }
/** * @param networkName the name of the network * @deprecated see {@link ResourceReaper#registerNetworkIdForCleanup(String)} */ @Deprecated public void registerNetworkForCleanup(String networkName) { try { // Try to find the network by name, so that we can register its ID for later deletion dockerClient.listNetworksCmd() .withNameFilter(networkName) .exec() .forEach(network -> registerNetworkIdForCleanup(network.getId())); } catch (Exception e) { LOGGER.trace("Error encountered when looking up network (name: {})", networkName); } }
/** * Stops the container. */ @Override public void stop() { if (containerId == null) { return; } try { String imageName; try { imageName = image.get(); } catch (Exception e) { imageName = "<unknown>"; } ResourceReaper.instance().stopAndRemoveContainer(containerId, imageName); } finally { containerId = null; containerInfo = null; } }
private void registerContainersForShutdown() { ResourceReaper.instance().registerFilterForCleanup(Arrays.asList(new SimpleEntry<>("label", "com.docker.compose.project=" + project))); }
/** * Stop a potentially running container and remove it, including associated volumes. * * @param containerId the ID of the container * @param imageName the image name of the container (used for logging) */ public void stopAndRemoveContainer(String containerId, String imageName) { stopContainer(containerId, imageName); registeredContainers.remove(containerId); }
/** * Register a container to be cleaned up, either on explicit call to stopAndRemoveContainer, or at JVM shutdown. * * @param containerId the ID of the container * @param imageName the image name of the container (used for logging) */ public void registerContainerForCleanup(String containerId, String imageName) { setHook(); registeredContainers.put(containerId, imageName); }
@Override public void stop() { synchronized (MUTEX) { try { // shut down the ambassador container ambassadorContainer.stop(); // Kill the services using docker-compose try { runWithCompose("down -v"); // If we reach here then docker-compose down has cleared networks and containers; // we can unregister from ResourceReaper spawnedContainerIds.forEach(ResourceReaper.instance()::unregisterContainer); spawnedNetworkIds.forEach(ResourceReaper.instance()::unregisterNetwork); } catch (Exception e) { // docker-compose down failed; use ResourceReaper to ensure cleanup // kill the spawned service containers spawnedContainerIds.forEach(ResourceReaper.instance()::stopAndRemoveContainer); // remove the networks after removing the containers spawnedNetworkIds.forEach(ResourceReaper.instance()::removeNetworkById); } spawnedContainerIds.clear(); spawnedNetworkIds.clear(); } finally { project = randomProjectId(); } } }
boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED")); if (useRyuk) { ryukContainerId = ResourceReaper.start(hostIpAddress, client); log.info("Ryuk started - will monitor and terminate Testcontainers containers on JVM exit");
/** * Removes a network by ID. * @param identifier * @deprecated see {@link ResourceReaper#removeNetworkById(String)} */ @Deprecated public void removeNetworks(String identifier) { removeNetworkById(identifier); }
/** * @param networkName the name of the network * @deprecated see {@link ResourceReaper#registerNetworkIdForCleanup(String)} */ @Deprecated public void registerNetworkForCleanup(String networkName) { try { // Try to find the network by name, so that we can register its ID for later deletion dockerClient.listNetworksCmd().withNameFilter(networkName).exec().forEach(network -> registerNetworkIdForCleanup(network.getId())); } catch (Exception e) { LOGGER.trace("Error encountered when looking up network (name: {})", networkName); } }
/** * Stop a potentially running container and remove it, including associated volumes. * * @param containerId the ID of the container */ public void stopAndRemoveContainer(String containerId) { stopContainer(containerId, registeredContainers.get(containerId)); registeredContainers.remove(containerId); }
/** * Register a network to be cleaned up at JVM shutdown. * * @param id the ID of the network */ public void registerNetworkIdForCleanup(String id) { setHook(); registeredNetworks.add(id); }
public static String start(String hostIpAddress, DockerClient client) { try { String ryukImage = TestcontainersConfiguration.getInstance().getRyukImage(); DockerClientFactory.instance().checkAndPullImage(client, ryukImage); List<Bind> binds = new ArrayList<>(); binds.add(new Bind("//var/run/docker.sock", new Volume("/var/run/docker.sock"))); String ryukContainerId = client.createContainerCmd(ryukImage).withHostConfig(new HostConfig().withAutoRemove(true)).withExposedPorts(new ExposedPort(8080)).withPublishAllPorts(true).withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID).withLabels(Collections.singletonMap(DockerClientFactory.TESTCONTAINERS_LABEL, "true")).withBinds(binds).withPrivileged(TestcontainersConfiguration.getInstance().isRyukPrivileged()).exec().getId(); client.startContainerCmd(ryukContainerId).exec(); InspectContainerResponse inspectedContainer = client.inspectContainerCmd(ryukContainerId).exec(); Integer ryukPort = inspectedContainer.getNetworkSettings().getPorts().getBindings().values().stream().flatMap(Stream::of).findFirst().map(Ports.Binding::getHostPortSpec).map(Integer::parseInt).get(); CountDownLatch ryukScheduledLatch = new CountDownLatch(1); synchronized (DEATH_NOTE) { DEATH_NOTE.add(DockerClientFactory.DEFAULT_LABELS.entrySet().stream().<Map.Entry<String, String>>map(it -> new SimpleEntry<>("label", it.getKey() + "=" + it.getValue())).collect(Collectors.toList())); } Thread kiraThread = new Thread(DockerClientFactory.TESTCONTAINERS_THREAD_GROUP, () -> { while (true) { int index = 0; try (Socket clientSocket = new Socket(hostIpAddress, ryukPort)) { FilterRegistry registry = new FilterRegistry(clientSocket.getInputStream(), clientSocket.getOutputStream()); synchronized (DEATH_NOTE) { while (true) { if (DEATH_NOTE.size() <= index) { try { DEATH_NOTE.wait(1000); continue; } catch (InterruptedException e) { throw new RuntimeException(e); } } List<Map.Entry<String, String>> filters = DEATH_NOTE.get(index);
@Override public void close() { if (initialized.getAndSet(false)) { ResourceReaper.instance().removeNetworkById(id); } }