mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
fix(OriginExecution): apply execution policy to process launch
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
package work.slhaf.partner.core.action.runner.execution;
|
package work.slhaf.partner.core.action.runner.execution;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import work.slhaf.partner.core.action.runner.policy.WrappedLaunchSpec;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.File;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -37,15 +39,13 @@ public class CommandExecutionService {
|
|||||||
return exec(commands.toArray(new String[0]));
|
return exec(commands.toArray(new String[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result exec(String... commands) {
|
public Result exec(WrappedLaunchSpec launchSpec) {
|
||||||
Result result = new Result();
|
Result result = new Result();
|
||||||
List<String> output = new ArrayList<>();
|
List<String> output = new ArrayList<>();
|
||||||
List<String> error = new ArrayList<>();
|
List<String> error = new ArrayList<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Process process = new ProcessBuilder(commands)
|
Process process = startProcess(launchSpec);
|
||||||
.redirectErrorStream(false)
|
|
||||||
.start();
|
|
||||||
|
|
||||||
Thread stdoutThread = new Thread(() -> {
|
Thread stdoutThread = new Thread(() -> {
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
||||||
@@ -85,15 +85,17 @@ public class CommandExecutionService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result exec(String... commands) {
|
||||||
|
return exec(defaultLaunchSpec(commands));
|
||||||
|
}
|
||||||
|
|
||||||
public CommandSession createSessionTask(List<String> commands) {
|
public CommandSession createSessionTask(List<String> commands) {
|
||||||
return createSessionTask(commands.toArray(new String[0]));
|
return createSessionTask(commands.toArray(new String[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandSession createSessionTask(String... commands) {
|
public CommandSession createSessionTask(WrappedLaunchSpec launchSpec) {
|
||||||
try {
|
try {
|
||||||
Process process = new ProcessBuilder(commands)
|
Process process = startProcess(launchSpec);
|
||||||
.redirectErrorStream(false)
|
|
||||||
.start();
|
|
||||||
CommandSession session = new CommandSession();
|
CommandSession session = new CommandSession();
|
||||||
StringBuilder stdoutBuffer = new StringBuilder();
|
StringBuilder stdoutBuffer = new StringBuilder();
|
||||||
StringBuilder stderrBuffer = new StringBuilder();
|
StringBuilder stderrBuffer = new StringBuilder();
|
||||||
@@ -110,6 +112,10 @@ public class CommandExecutionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandSession createSessionTask(String... commands) {
|
||||||
|
return createSessionTask(defaultLaunchSpec(commands));
|
||||||
|
}
|
||||||
|
|
||||||
private void readToBuffer(java.io.InputStream inputStream, StringBuilder buffer) {
|
private void readToBuffer(java.io.InputStream inputStream, StringBuilder buffer) {
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
||||||
String line;
|
String line;
|
||||||
@@ -125,6 +131,31 @@ public class CommandExecutionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Process startProcess(WrappedLaunchSpec launchSpec) throws Exception {
|
||||||
|
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||||
|
List<String> command = new ArrayList<>();
|
||||||
|
command.add(launchSpec.getCommand());
|
||||||
|
command.addAll(launchSpec.getArgs());
|
||||||
|
processBuilder.command(command);
|
||||||
|
processBuilder.redirectErrorStream(false);
|
||||||
|
if (launchSpec.getWorkingDirectory() != null && !launchSpec.getWorkingDirectory().isBlank()) {
|
||||||
|
processBuilder.directory(new File(launchSpec.getWorkingDirectory()));
|
||||||
|
}
|
||||||
|
Map<String, String> environment = processBuilder.environment();
|
||||||
|
environment.clear();
|
||||||
|
environment.putAll(launchSpec.getEnvironment());
|
||||||
|
return processBuilder.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private WrappedLaunchSpec defaultLaunchSpec(String... commands) {
|
||||||
|
return new WrappedLaunchSpec(
|
||||||
|
commands[0],
|
||||||
|
List.of(commands).subList(1, commands.length),
|
||||||
|
null,
|
||||||
|
System.getenv()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class Result {
|
public static class Result {
|
||||||
private boolean ok;
|
private boolean ok;
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry;
|
|||||||
import work.slhaf.partner.core.action.runner.policy.WrappedLaunchSpec;
|
import work.slhaf.partner.core.action.runner.policy.WrappedLaunchSpec;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static work.slhaf.partner.core.action.ActionCore.ORIGIN_LOCATION;
|
import static work.slhaf.partner.core.action.ActionCore.ORIGIN_LOCATION;
|
||||||
|
|
||||||
@@ -22,10 +20,7 @@ public class OriginExecutionService {
|
|||||||
File file = new File(resolveOriginPath(metaAction));
|
File file = new File(resolveOriginPath(metaAction));
|
||||||
String[] commands = CommandExecutionService.INSTANCE.buildFileExecutionCommands(metaAction.getLauncher(), metaAction.getParams(), file.getAbsolutePath());
|
String[] commands = CommandExecutionService.INSTANCE.buildFileExecutionCommands(metaAction.getLauncher(), metaAction.getParams(), file.getAbsolutePath());
|
||||||
WrappedLaunchSpec wrapped = ExecutionPolicyRegistry.INSTANCE.prepare(Arrays.stream(commands).toList());
|
WrappedLaunchSpec wrapped = ExecutionPolicyRegistry.INSTANCE.prepare(Arrays.stream(commands).toList());
|
||||||
List<String> wrappedCommands = new ArrayList<>();
|
CommandExecutionService.Result execResult = CommandExecutionService.INSTANCE.exec(wrapped);
|
||||||
wrappedCommands.add(wrapped.getCommand());
|
|
||||||
wrappedCommands.addAll(wrapped.getArgs());
|
|
||||||
CommandExecutionService.Result execResult = CommandExecutionService.INSTANCE.exec(wrappedCommands);
|
|
||||||
response.setOk(execResult.isOk());
|
response.setOk(execResult.isOk());
|
||||||
response.setData(execResult.getTotal());
|
response.setData(execResult.getTotal());
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package work.slhaf.partner.core.action.runner.execution;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import work.slhaf.partner.core.action.runner.policy.WrappedLaunchSpec;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -105,6 +106,32 @@ class CommandExecutionServiceTest {
|
|||||||
Assertions.assertEquals("oops", session.getStderrBuffer().toString());
|
Assertions.assertEquals("oops", session.getStderrBuffer().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExecWrappedLaunchSpecAppliesWorkingDirectory(@org.junit.jupiter.api.io.TempDir Path tempDir) {
|
||||||
|
CommandExecutionService.Result result = service.exec(new WrappedLaunchSpec(
|
||||||
|
"sh",
|
||||||
|
List.of("-lc", "pwd"),
|
||||||
|
tempDir.toString(),
|
||||||
|
System.getenv()
|
||||||
|
));
|
||||||
|
|
||||||
|
Assertions.assertTrue(result.isOk());
|
||||||
|
Assertions.assertEquals(tempDir.toString(), result.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExecWrappedLaunchSpecAppliesEnvironmentOverride() {
|
||||||
|
CommandExecutionService.Result result = service.exec(new WrappedLaunchSpec(
|
||||||
|
"sh",
|
||||||
|
List.of("-lc", "printf '%s' \"$PARTNER_TEST_ENV\""),
|
||||||
|
null,
|
||||||
|
Map.of("PARTNER_TEST_ENV", "applied")
|
||||||
|
));
|
||||||
|
|
||||||
|
Assertions.assertTrue(result.isOk());
|
||||||
|
Assertions.assertEquals("applied", result.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
private void waitForBufferContains(StringBuilder buffer, String expected) throws InterruptedException {
|
private void waitForBufferContains(StringBuilder buffer, String expected) throws InterruptedException {
|
||||||
long deadline = System.currentTimeMillis() + 2000;
|
long deadline = System.currentTimeMillis() + 2000;
|
||||||
while (System.currentTimeMillis() < deadline) {
|
while (System.currentTimeMillis() < deadline) {
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package work.slhaf.partner.core.action.runner.execution;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import work.slhaf.partner.core.action.entity.MetaAction;
|
||||||
|
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicy;
|
||||||
|
import work.slhaf.partner.core.action.runner.policy.ExecutionPolicyRegistry;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
class OriginExecutionServiceTest {
|
||||||
|
|
||||||
|
private static String originalUserHome;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void prepareTestHome() throws IOException {
|
||||||
|
originalUserHome = System.getProperty("user.home");
|
||||||
|
Path tempHome = Files.createTempDirectory("partner-test-home");
|
||||||
|
System.setProperty("user.home", tempHome.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void restoreUserHome() {
|
||||||
|
if (originalUserHome != null) {
|
||||||
|
System.setProperty("user.home", originalUserHome);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testOriginExecutionServiceAppliesExecutionPolicyEnvironment(@TempDir Path tempDir) throws IOException {
|
||||||
|
Path script = tempDir.resolve("print_env.py");
|
||||||
|
Files.writeString(script, "import os\nprint(os.getenv('PARTNER_ORIGIN_TEST', ''), end='')\n");
|
||||||
|
|
||||||
|
ExecutionPolicy originalPolicy = new ExecutionPolicy(
|
||||||
|
ExecutionPolicy.Mode.DIRECT,
|
||||||
|
"direct",
|
||||||
|
ExecutionPolicy.Network.ENABLE,
|
||||||
|
true,
|
||||||
|
Map.of(),
|
||||||
|
null,
|
||||||
|
Set.of(),
|
||||||
|
Set.of()
|
||||||
|
);
|
||||||
|
ExecutionPolicyRegistry.INSTANCE.updatePolicy(new ExecutionPolicy(
|
||||||
|
ExecutionPolicy.Mode.DIRECT,
|
||||||
|
"direct",
|
||||||
|
ExecutionPolicy.Network.ENABLE,
|
||||||
|
false,
|
||||||
|
Map.of("PARTNER_ORIGIN_TEST", "origin-applied"),
|
||||||
|
null,
|
||||||
|
Set.of(),
|
||||||
|
Set.of()
|
||||||
|
));
|
||||||
|
|
||||||
|
try {
|
||||||
|
var prepared = ExecutionPolicyRegistry.INSTANCE.prepare(List.of("python3", script.toString()));
|
||||||
|
Assertions.assertEquals("origin-applied", prepared.getEnvironment().get("PARTNER_ORIGIN_TEST"));
|
||||||
|
var directExec = CommandExecutionService.INSTANCE.exec(prepared);
|
||||||
|
Assertions.assertTrue(directExec.isOk());
|
||||||
|
Assertions.assertEquals("origin-applied", directExec.getTotal());
|
||||||
|
OriginExecutionService service = new OriginExecutionService();
|
||||||
|
MetaAction metaAction = new MetaAction("run", false, "python3", MetaAction.Type.ORIGIN, script.toString());
|
||||||
|
var response = service.run(metaAction);
|
||||||
|
Assertions.assertTrue(response.isOk());
|
||||||
|
Assertions.assertEquals("origin-applied", response.getData());
|
||||||
|
} finally {
|
||||||
|
ExecutionPolicyRegistry.INSTANCE.updatePolicy(originalPolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user