Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions commons-lib/src/main/java/org/opencb/commons/exec/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,29 @@ public class Command extends RunnableProcess {
private final String[] cmdArray;
private boolean printOutput = true;

private String stdinInput;

// Add a constructor that takes stdin input
public Command(String commandLine, String stdinInput) {
this(commandLine);
this.stdinInput = stdinInput;
}

public Command(String commandLine, List<String> environment, String stdinInput) {
this(commandLine, environment);
this.stdinInput = stdinInput;
}

public Command(String[] cmdArray, List<String> environment, String stdinInput) {
this(cmdArray, environment);
this.stdinInput = stdinInput;
}

public Command(String[] cmdArray, Map<String, String> environment, String stdinInput) {
this(cmdArray, environment);
this.stdinInput = stdinInput;
}

public Command(String commandLine) {
this.commandLine = commandLine;
cmdArray = Commandline.translateCommandline(getCommandLine());
Expand Down Expand Up @@ -109,6 +132,14 @@ public Future<Status> run(boolean background) {
}
setStatus(Status.RUNNING);

// Write to stdin if input is provided
if (stdinInput != null) {
try (OutputStream stdin = proc.getOutputStream()) {
stdin.write(stdinInput.getBytes());
stdin.flush();
}
}

InputStream stdout = proc.getInputStream();
Future<?> readOutputStreamThread = readOutputStream(stdout);
InputStream stderr = proc.getErrorStream();
Expand Down Expand Up @@ -310,6 +341,15 @@ public Command setPrintOutput(boolean printOutput) {
return this;
}

public String getStdinInput() {
return stdinInput;
}

public Command setStdinInput(String stdinInput) {
this.stdinInput = stdinInput;
return this;
}

public Process getProc() {
return proc;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,58 @@ private static List<String> getPaths(String entryPoint) {
return new ArrayList<>(res);
}

/**
* Login into dockerhub with the given credentials.
*
* @param registry Docker registry URL
* @param username Docker registry username
* @param password Docker registry password
* @return True if login was successful, false otherwise
* @throws IOException IO exception
*/
public static boolean login(String registry, String username, String password) throws IOException {
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
throw new IllegalArgumentException("Username and password are required");
}
if (registry == null) {
// Leave it empty (defaults to dockerhub)
registry = "";
}

String commandLine = "docker login " + registry + " --username " + username + " --password-stdin";

LOGGER.info("Running docker login command");
Command cmd = new Command(commandLine, password);
cmd.run();

if (cmd.getExitValue() != 0) {
LOGGER.error("Docker login failed: {}", cmd.getError());
return false;
}

return true;
}

/**
* Create and run the command line to execute the docker image with optional registry authentication.
*
* @param image Docker image name
* @param inputBindings Array of bind mounts for docker input volumes (source-target)
* @param outputBinding Bind mount for docker output volume (source-target)
* @param cmdParams Image command parameters
* @param dockerParams Docker parameters
* @param registry Docker registry URL
* @param username Optional Docker registry username
* @param password Optional Docker registry password
* @return The command line
* @throws IOException IO exception
*/
public static String run(String image, List<AbstractMap.SimpleEntry<String, String>> inputBindings,
AbstractMap.SimpleEntry<String, String> outputBinding, String cmdParams,
Map<String, String> dockerParams, String registry, String username, String password) throws IOException {
return run(image, inputBindings, outputBinding != null ? Collections.singletonList(outputBinding) : null,
cmdParams, dockerParams, registry, username, password);
}

/**
* Create and run the command line to execute the docker image.
Expand Down Expand Up @@ -191,8 +243,37 @@ public static String run(String image, List<AbstractMap.SimpleEntry<String, Stri
public static String run(String image, List<AbstractMap.SimpleEntry<String, String>> inputBindings,
List<AbstractMap.SimpleEntry<String, String>> outputBindings, String cmdParams,
Map<String, String> dockerParams) throws IOException {
return run(image, inputBindings, outputBindings, cmdParams, dockerParams, null, null, null);
}

/**
* Create and run the command line to execute the docker image with optional registry authentication.
*
* @param image Docker image name
* @param inputBindings Array of bind mounts for docker input volumes (source-target)
* @param outputBindings Array of bind mount for docker output volume (source-target)
* @param cmdParams Image command parameters
* @param dockerParams Docker parameters
* @param registry Optional Docker registry URL (null if not using private registry)
* @param username Optional Docker registry username
* @param password Optional Docker registry password
* @return The command line
* @throws IOException IO exception
*/
public static String run(String image, List<AbstractMap.SimpleEntry<String, String>> inputBindings,
List<AbstractMap.SimpleEntry<String, String>> outputBindings, String cmdParams,
Map<String, String> dockerParams, String registry, String username, String password) throws IOException {

checkDockerDaemonAlive();

// Login to registry if credentials provided
if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
boolean loginSuccess = login(registry, username, password);
if (!loginSuccess) {
throw new IOException("Failed to authenticate to Dockerhub");
}
}

String commandLine = buildCommandLine(image, inputBindings, outputBindings, cmdParams, dockerParams);

LOGGER.info("Run docker command line");
Expand Down Expand Up @@ -222,7 +303,6 @@ public static String run(String image, List<AbstractMap.SimpleEntry<String, Stri
return commandLine;
}


public static void checkDockerDaemonAlive() throws IOException {
int maxAttempts = 12;
for (int i = 0; i < maxAttempts; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import org.junit.Test;

import java.io.IOException;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.junit.Assert.assertTrue;

public class DockerUtilsTest {

@Test
Expand All @@ -24,4 +27,31 @@ public void buildMountPathsCommandLine() throws IOException {

}

@Test
public void testDockerLogin() throws IOException {
// Skip test if environment variables are not set
String registry = System.getenv("DOCKER_REGISTRY_URL");
String username = System.getenv("DOCKER_USERNAME");
String password = System.getenv("DOCKER_PASSWORD");

// Skip test if credentials are not provided
org.junit.Assume.assumeTrue("Skipping test: Docker credentials not provided in environment variables",
org.apache.commons.lang3.StringUtils.isNotEmpty(username) && org.apache.commons.lang3.StringUtils.isNotEmpty(password));

try {
// First, check if docker is available
DockerUtils.checkDockerDaemonAlive();

// Execute private docker image with authentication
assertTrue(DockerUtils.login(registry, username, password));

System.out.println("Successfully logged in");

} catch (IOException e) {
System.err.println("Test failed: " + e.getMessage());
throw e;
}
}


}
Loading