mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2025-01-01 14:07:56 +01:00
Use unix domain socket for Docker commands
This commit is contained in:
parent
5555cdac89
commit
8e1553c0ed
@ -3,6 +3,9 @@ plugins {
|
|||||||
id 'java-library'
|
id 'java-library'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceCompatibility = 17
|
||||||
|
targetCompatibility = 17
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':api')
|
implementation project(':api')
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ import net.luckperms.api.LuckPerms;
|
|||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@ -80,7 +79,7 @@ public class LuckPermsApplication implements AutoCloseable {
|
|||||||
|
|
||||||
List<String> arguments = Arrays.asList(args);
|
List<String> arguments = Arrays.asList(args);
|
||||||
if (arguments.contains("--docker")) {
|
if (arguments.contains("--docker")) {
|
||||||
this.dockerCommandSocket = DockerCommandSocket.createAndStart(3000, terminal);
|
this.dockerCommandSocket = DockerCommandSocket.createAndStart("/opt/luckperms/luckperms.sock", terminal);
|
||||||
this.heartbeatHttpServer = HeartbeatHttpServer.createAndStart(3001, this.healthReporter);
|
this.heartbeatHttpServer = HeartbeatHttpServer.createAndStart(3001, this.healthReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +97,7 @@ public class LuckPermsApplication implements AutoCloseable {
|
|||||||
if (this.dockerCommandSocket != null) {
|
if (this.dockerCommandSocket != null) {
|
||||||
try {
|
try {
|
||||||
this.dockerCommandSocket.close();
|
this.dockerCommandSocket.close();
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
LOGGER.warn(e);
|
LOGGER.warn(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,33 +30,43 @@ import org.apache.logging.log4j.Logger;
|
|||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.net.StandardProtocolFamily;
|
||||||
import java.net.ServerSocket;
|
import java.net.UnixDomainSocketAddress;
|
||||||
import java.net.Socket;
|
import java.nio.channels.Channels;
|
||||||
import java.net.SocketException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple/dumb socket that listens for connections on a given port,
|
* Simple/dumb unix domain socket that listens for connections,
|
||||||
* reads the input to a string, then executes it as a command.
|
* reads the input to a string, then executes it as a command.
|
||||||
*
|
*
|
||||||
* Combined with a small sh/nc program, this makes it easy to execute
|
* <p>Combined with a small sh/nc program, this makes it easy to execute
|
||||||
* commands against a standalone instance of LP in a Docker container.
|
* commands against a standalone instance of LP in a Docker container.</p>
|
||||||
*/
|
*/
|
||||||
public class DockerCommandSocket extends ServerSocket implements Runnable {
|
public class DockerCommandSocket implements Runnable, AutoCloseable {
|
||||||
private static final Logger LOGGER = LogManager.getLogger(DockerCommandSocket.class);
|
private static final Logger LOGGER = LogManager.getLogger(DockerCommandSocket.class);
|
||||||
|
|
||||||
public static DockerCommandSocket createAndStart(int port, TerminalInterface terminal) {
|
public static DockerCommandSocket createAndStart(String socketPath, TerminalInterface terminal) {
|
||||||
DockerCommandSocket socket = null;
|
DockerCommandSocket socket = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
socket = new DockerCommandSocket(port, terminal::runCommand);
|
Path path = Paths.get(socketPath);
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
|
||||||
|
ServerSocketChannel channel = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
channel.bind(UnixDomainSocketAddress.of(path));
|
||||||
|
|
||||||
|
socket = new DockerCommandSocket(channel, terminal::runCommand);
|
||||||
|
|
||||||
Thread thread = new Thread(socket, "docker-command-socket");
|
Thread thread = new Thread(socket, "docker-command-socket");
|
||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
LOGGER.info("Created Docker command socket on port " + port);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("Error starting docker command socket", e);
|
LOGGER.error("Error starting docker command socket", e);
|
||||||
}
|
}
|
||||||
@ -64,30 +74,35 @@ public class DockerCommandSocket extends ServerSocket implements Runnable {
|
|||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final ServerSocketChannel channel;
|
||||||
private final Consumer<String> callback;
|
private final Consumer<String> callback;
|
||||||
|
|
||||||
public DockerCommandSocket(int port, Consumer<String> callback) throws IOException {
|
public DockerCommandSocket(ServerSocketChannel channel, Consumer<String> callback) throws IOException {
|
||||||
super(port);
|
this.channel = channel;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!isClosed()) {
|
while (this.channel.isOpen()) {
|
||||||
try (Socket socket = accept()) {
|
try (SocketChannel socket = this.channel.accept()) {
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
|
try (BufferedReader reader = new BufferedReader(Channels.newReader(socket, StandardCharsets.UTF_8))) {
|
||||||
String cmd;
|
String cmd;
|
||||||
while ((cmd = reader.readLine()) != null) {
|
while ((cmd = reader.readLine()) != null) {
|
||||||
LOGGER.info("Executing command from Docker: " + cmd);
|
LOGGER.info("Executing command from Docker: " + cmd);
|
||||||
this.callback.accept(cmd);
|
this.callback.accept(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (ClosedChannelException e) {
|
||||||
|
// ignore
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (e instanceof SocketException && e.getMessage().equals("Socket closed")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOGGER.error("Error processing input from the Docker socket", e);
|
LOGGER.error("Error processing input from the Docker socket", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
this.channel.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public class HeartbeatHttpServer implements HttpHandler, AutoCloseable {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
socket = new HeartbeatHttpServer(healthReporter, port);
|
socket = new HeartbeatHttpServer(healthReporter, port);
|
||||||
LOGGER.info("Created Heartbeat HTTP server on port " + port);
|
LOGGER.info("Started healthcheck HTTP server on :" + port);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("Error starting Heartbeat HTTP server", e);
|
LOGGER.error("Error starting Heartbeat HTTP server", e);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@ plugins {
|
|||||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceCompatibility = 17
|
||||||
|
targetCompatibility = 17
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':common')
|
implementation project(':common')
|
||||||
compileOnly project(':common:loader-utils')
|
compileOnly project(':common:loader-utils')
|
||||||
|
@ -4,7 +4,7 @@ RUN apk add --no-cache openjdk17 netcat-openbsd
|
|||||||
# create a simple 'send' command that will allow users
|
# create a simple 'send' command that will allow users
|
||||||
# to run, for example: docker exec <container> send lp info
|
# to run, for example: docker exec <container> send lp info
|
||||||
RUN printf '#!/bin/sh\n\
|
RUN printf '#!/bin/sh\n\
|
||||||
echo "$@" | nc -N localhost 3000\n' >> /usr/bin/send && chmod 777 /usr/bin/send
|
echo "$@" | nc -NU /opt/luckperms/luckperms.sock\n' >> /usr/bin/send && chmod 777 /usr/bin/send
|
||||||
|
|
||||||
# setup user
|
# setup user
|
||||||
RUN addgroup -S app && adduser -S -G app app
|
RUN addgroup -S app && adduser -S -G app app
|
||||||
|
@ -11,6 +11,9 @@ dependencies {
|
|||||||
implementation project(':standalone:app')
|
implementation project(':standalone:app')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceCompatibility = 17
|
||||||
|
targetCompatibility = 17
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass = 'me.lucko.luckperms.standalone.loader.StandaloneLoader'
|
mainClass = 'me.lucko.luckperms.standalone.loader.StandaloneLoader'
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user