public static DockerContainer fromContainerInfo(ContainerInfo container) { Map<String, String> labels = container.config().labels(); return new DockerContainer( container.name().substring(1), container.created(), GSON.fromJson(labels.get(Constants.CONFIGURATION_LABEL_KEY), HashMap.class), labels.get(Constants.ENVIRONMENT_LABEL_KEY)); }
public static DockerContainer create( CreateAgentRequest request, PluginSettings settings, DockerClient docker) throws InterruptedException, DockerException, IOException { String containerName = UUID.randomUUID().toString(); HashMap<String, String> labels = labelsFrom(request); String imageName = image(request.properties()); List<String> env = environmentFrom(request, settings, containerName); try { docker.inspectImage(imageName); } catch (ImageNotFoundException ex) { LOG.info("Image " + imageName + " not found, attempting to download."); docker.pull(imageName); } ContainerConfig.Builder containerConfigBuilder = ContainerConfig.builder(); if (request.properties().containsKey("Command")) { containerConfigBuilder.cmd( splitIntoLinesAndTrimSpaces(request.properties().get("Command")) .toArray(new String[] {})); } ContainerConfig containerConfig = containerConfigBuilder.image(imageName).labels(labels).env(env).build(); ContainerCreation container = docker.createContainer(containerConfig, containerName); String id = container.id(); ContainerInfo containerInfo = docker.inspectContainer(id); LOG.debug("Created container " + containerName); docker.startContainer(containerName); return new DockerContainer( containerName, containerInfo.created(), request.properties(), request.environment()); }
@Override public int execute( final List<String> commandLine, final File executionDirectory, final Map<String, String> environmentVariables, final File temporaryDirectory, final File stdoutFile, final File stderrFile, final boolean redirectErrorStream) throws EoulsanException { checkNotNull(commandLine, "commandLine argument cannot be null"); checkNotNull(executionDirectory, "executionDirectory argument cannot be null"); checkNotNull(stdoutFile, "stdoutFile argument cannot be null"); checkNotNull(stderrFile, "stderrFile argument cannot be null"); checkArgument( executionDirectory.isDirectory(), "execution directory does not exists or is not a directory: " + executionDirectory.getAbsolutePath()); try { final List<String> env = new ArrayList<>(); if (environmentVariables != null) { for (Map.Entry<String, String> e : environmentVariables.entrySet()) { env.add(e.getKey() + '=' + e.getValue()); } } // Pull image if needed pullImageIfNotExists(this.dockerClient, this.dockerImage); // Create container configuration getLogger().fine("Configure container, command to execute: " + commandLine); final ContainerConfig.Builder builder = ContainerConfig.builder().image(dockerImage).cmd(commandLine); // Set the working directory builder.workingDir(executionDirectory.getAbsolutePath()); // Set the UID and GID of the docker process if (this.userUid >= 0 && this.userGid >= 0) { builder.user(this.userUid + ":" + this.userGid); } // Define temporary directory final List<File> toBind; if (temporaryDirectory.isDirectory()) { toBind = singletonList(temporaryDirectory); env.add(TMP_DIR_ENV_VARIABLE + "=" + temporaryDirectory.getAbsolutePath()); } else { toBind = Collections.emptyList(); } builder.hostConfig(createBinds(executionDirectory, toBind)); // Set environment variables builder.env(env); // Create container final ContainerCreation creation = this.dockerClient.createContainer(builder.build()); // Get container id final String containerId = creation.id(); // Start container getLogger().fine("Start of the Docker container: " + containerId); this.dockerClient.startContainer(containerId); // Redirect stdout and stderr final LogStream logStream = this.dockerClient.logs( containerId, LogsParameter.FOLLOW, LogsParameter.STDERR, LogsParameter.STDOUT); redirect(logStream, stdoutFile, stderrFile, redirectErrorStream); // Wait the end of the container getLogger().fine("Wait the end of the Docker container: " + containerId); this.dockerClient.waitContainer(containerId); // Get process exit code final ContainerInfo info = this.dockerClient.inspectContainer(containerId); final int exitValue = info.state().exitCode(); getLogger().fine("Exit value: " + exitValue); // Stop container before removing it this.dockerClient.stopContainer(containerId, SECOND_TO_WAIT_BEFORE_KILLING_CONTAINER); // Remove container getLogger().fine("Remove Docker container: " + containerId); try { this.dockerClient.removeContainer(containerId); } catch (DockerException | InterruptedException e) { EoulsanLogger.getLogger().severe("Unable to remove Docker container: " + containerId); } return exitValue; } catch (DockerException | InterruptedException e) { throw new EoulsanException(e); } }
private MineCloudDaemon(Properties properties) { redis = MineCloud.instance().redis(); mongo = MineCloud.instance().mongo(); dockerClient = new DefaultDockerClient("unix:///var/run/docker.sock"); node = (String) properties.get("node-name"); instance = this; redis.addChannel( SimpleRedisChannel.create("server-create", redis) .addCallback( (message) -> { if (message.type() != MessageType.BINARY) { return; } MessageInputStream stream = message.contents(); if (!stream.readString().equalsIgnoreCase(node)) { return; } Network network = mongo.repositoryBy(Network.class).findFirst(stream.readString()); ServerType type = mongo.repositoryBy(ServerType.class).findFirst(stream.readString()); List<ServerMetadata> metadata = new ArrayList<>(); int size = stream.readVarInt32(); for (int i = 0; i < size; i++) { metadata.add(new ServerMetadata(stream.readString(), stream.readString())); } Deployer.deployServer(network, type, metadata); })); redis.addChannel( SimpleRedisChannel.create("server-kill", redis) .addCallback( (message) -> { if (message.type() != MessageType.BINARY) { return; } MessageInputStream stream = message.contents(); if (!stream.readString().equalsIgnoreCase(node)) return; Server server = mongo.repositoryBy(Server.class).findFirst(stream.readString()); if (!server.node().name().equals(node)) { MineCloud.logger() .log( Level.SEVERE, "Invalid request was sent to kill a server " + "not on the current node"); return; } try { dockerClient.killContainer(server.containerId()); MineCloud.logger() .info( "Killed server " + server.name() + " with container id " + server.containerId()); mongo.repositoryBy(Server.class).delete(server); } catch (DockerException | InterruptedException e) { MineCloud.logger().log(Level.SEVERE, "Was unable to kill a server", e); } })); redis.addChannel( SimpleRedisChannel.create("bungee-create", redis) .addCallback( (message) -> { if (message.type() != MessageType.BINARY) { return; } MessageInputStream stream = message.contents(); if (!stream.readString().equalsIgnoreCase(node)) return; Network network = mongo.repositoryBy(Network.class).findFirst(stream.readString()); BungeeType type = mongo.repositoryBy(BungeeType.class).findFirst(stream.readString()); Deployer.deployBungee(network, type); })); redis.addChannel( SimpleRedisChannel.create("bungee-kill", redis) .addCallback( (message) -> { if (message.type() != MessageType.BINARY) { return; } MessageInputStream stream = message.contents(); if (!stream.readString().equalsIgnoreCase(node)) return; Bungee bungee = mongo.repositoryBy(Bungee.class).findFirst(stream.readString()); if (!bungee.node().name().equals(node)) { MineCloud.logger() .log( Level.SEVERE, "Invalid request was sent to kill a bungee " + "not on the current node"); return; } try { dockerClient.killContainer(bungee.containerId()); MineCloud.logger() .info( "Killed bungee " + bungee.name() + " with container id " + bungee.containerId()); mongo.repositoryBy(Bungee.class).delete(bungee); } catch (DockerException | InterruptedException e) { MineCloud.logger().log(Level.SEVERE, "Was unable to kill a server", e); } })); redis.addChannel( SimpleRedisChannel.create("server-start-notif", redis) .addCallback( (message) -> { if (message.type() != MessageType.BINARY) return; MessageInputStream stream = message.contents(); Server server = mongo.repositoryBy(Server.class).findFirst(stream.readString()); if (!server.node().name().equals(node)) return; if (server.port() != -1) return; // don't even know how this would happen try { ContainerInfo info = dockerClient.inspectContainer(server.containerId()); info.networkSettings() .ports() .forEach( (s, l) -> { if (!s.contains("25565")) return; server.setPort(Integer.parseInt(l.get(0).hostPort())); MineCloud.logger() .log( Level.INFO, "Set " + server.name() + "'s port to " + server.port()); }); mongo.repositoryBy(Server.class).save(server); } catch (Exception e) { MineCloud.logger() .log(Level.SEVERE, "Was unable to set the port of a started server", e); } })); redis.addChannel(SimpleRedisChannel.create("server-shutdown-notif", redis)); new StatisticsWatcher().start(); while (!Thread.currentThread().isInterrupted()) { try { dockerClient .listContainers(DockerClient.ListContainersParam.allContainers()) .stream() .filter( (container) -> !container.status().toLowerCase().contains("up") && ((System.currentTimeMillis() / 1000L) - container.created()) > 5L) .forEach( (container) -> { try { String name = container.names() == null || container.names().isEmpty() ? "null" : container.names().get(0); dockerClient.removeContainer(container.id()); if (container.image().contains("minecloud")) { String type = container.image().substring(9); switch (type.toLowerCase()) { case "bungee": AbstractMongoRepository<Bungee> repository = mongo.repositoryBy(Bungee.class); Query<Bungee> query = repository.createQuery().field("_id").equal(node().publicIp()); repository.deleteByQuery(query); break; case "server": Server server = mongo .repositoryBy(Server.class) .findOne("containerId", container.names().get(0)); if (server != null) { mongo.repositoryBy(Server.class).delete(server); } break; } } MineCloud.logger() .info("Killed dead container " + container.id() + " (" + name + ")"); } catch (DockerException | InterruptedException e) { MineCloud.logger() .log( Level.SEVERE, "Was unable to kill exited container " + container.id(), e); } }); ServerRepository repository = mongo.repositoryBy(Server.class); Query<Server> query = repository .createQuery() .field("node") .equal(node()) .field("port") .notEqual(-1) .field("tps") .notEqual(-1); repository .find(query) .asList() .forEach( (server) -> { boolean exists; try { dockerClient.inspectContainer(server.containerId()); exists = true; } catch (DockerException | InterruptedException ex) { exists = false; } if (exists) { return; } repository.delete(server); MineCloud.logger() .info( "Removed " + server.containerId() + " from DB due to not existing as a container"); }); } catch (DockerException | InterruptedException e) { MineCloud.logger().log(Level.SEVERE, "Was unable to list containers for update", e); } try { Thread.sleep(2000L); } catch (InterruptedException ignored) { // I don't care } } }