Support patterns in config
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details

pull/5/head
Clément FRÉVILLE 1 year ago
parent ed1972a0a7
commit eeccee7763

@ -6,15 +6,19 @@ threads = 1
[runner]
timeout = 2
[[runners]]
[javascript]
[runners.javascript]
type = "bubblewrap"
binary = ["node", "-e", "{}"]
args = ["node", "-e", "{}"]
[bash]
[runners.bun]
type = "bubblewrap"
binary = ["bash", "-c", "{}"]
args = ["bun", "run", "/dev/stdin"]
[moshell]
[runners.bash]
type = "bubblewrap"
args = ["bash", "-c", "{}"]
[runners.moshell]
type = "docker"
image = "ghcr.io/moshell-lang/moshell:master"
args = ["moshell", "-c", "{}"]

@ -32,7 +32,18 @@ static sk::config read(const toml::table &config) {
}
args_vector.emplace_back(*arg_string);
}
strategies.emplace(name, sk::bubblewrap_config{std::move(args_vector)});
if (*backend_type == "docker") {
auto *image = backend_table->get_as<std::string>("image");
if (image == nullptr) {
std::cerr << "Invalid runner config for " << name << ": missing image field\n";
continue;
}
strategies.emplace(name, sk::docker_config{{std::move(args_vector)}, std::string{*image}});
} else if (*backend_type == "bubblewrap") {
strategies.emplace(name, sk::bubblewrap_config{std::move(args_vector)});
} else {
std::cerr << "Invalid runner config for " << name << ": unknown type " << *backend_type << "\n";
}
}
}
return sk::config{

@ -83,7 +83,12 @@ int main(int argc, char **argv) {
buffer << t.rdbuf();
std::string code = buffer.str();
sk::program program{"sample-code", code, "moshell"};
sk::run_result result = runners.run_blocking(program);
sk::runner *runner = runners.find_runner_for(program);
if (runner == nullptr) {
std::cerr << "No runner found for " << program.image << std::endl;
return 1;
}
sk::run_result result = runner->run_blocking(program);
std::cout << "exited with: " << result.exit_code << "\n";
std::cout << "out: " << result.out << "\n";
std::cout << "err: " << result.err << "\n";
@ -132,7 +137,16 @@ int main(int argc, char **argv) {
std::cout << "Executing " << codeLen << " bytes code.\n";
#endif
sk::program program{std::move(jobId), std::move(requestString), std::move(imageString)};
sk::run_result result = runners.run_blocking(program);
sk::runner *runner = runners.find_runner_for(program);
if (runner == nullptr) {
send(STDERR_CLIENT_BOUND, program.name, "No runner found for " + program.image);
sk::prepare_headers(sizeof(uint32_t), EXIT_CLIENT_BOUND, program.name);
auto [reply, reply_bytes] = sk::prepare_headers(sizeof(uint32_t), EXIT_CLIENT_BOUND, program.name);
sk::write_uint32(reply_bytes, -1);
sender.send(reply, zmq::send_flags::none);
continue;
}
sk::run_result result = runner->run_blocking(program);
if (!result.out.empty()) {
send(STDOUT_CLIENT_BOUND, program.name, result.out);

@ -21,17 +21,26 @@ static auto ensure = [](int res) -> void {
template <class> inline constexpr bool always_false_v = false;
namespace sk {
execution_strategy::execution_strategy(const std::vector<std::string> &patterns) {
for (const auto &pattern : patterns) {
if (pattern == "{}") {
this->patterns.emplace_back(nullptr);
} else {
this->patterns.emplace_back(pattern);
}
}
}
execution_strategy::execution_strategy(std::vector<pattern> patterns) : patterns(std::move(patterns)) {}
std::unique_ptr<execution_strategy> execution_strategy::create(const runner_strategy_config &config) {
return std::visit(
[](auto &&strategy) -> std::unique_ptr<execution_strategy> {
using T = std::decay_t<decltype(strategy)>;
std::vector<pattern> patterns;
if constexpr (std::is_same_v<T, sk::bubblewrap_config>) {
return std::make_unique<bubblewrap_execution_strategy>(std::move(patterns));
return std::make_unique<bubblewrap_execution_strategy>(strategy.args);
} else if constexpr (std::is_same_v<T, sk::docker_config>) {
return std::make_unique<docker_execution_strategy>(std::move(patterns), strategy.image);
return std::make_unique<docker_execution_strategy>(strategy.args, strategy.image);
} else {
static_assert(always_false_v<T>, "non-exhaustive visitor!");
}
@ -39,15 +48,41 @@ std::unique_ptr<execution_strategy> execution_strategy::create(const runner_stra
config);
}
void execution_strategy::concat_patterns(std::vector<const char *> &args, const program &program) const {
for (const auto &pattern : patterns) {
std::visit(
[&args, &program](const auto &arg) {
if constexpr (std::is_same_v<std::string, std::decay_t<decltype(arg)>>) {
args.push_back(arg.c_str());
} else {
args.push_back(program.code.c_str());
}
},
pattern);
}
}
bubblewrap_execution_strategy::bubblewrap_execution_strategy(const std::vector<std::string> &patterns) : execution_strategy{patterns} {}
bubblewrap_execution_strategy::bubblewrap_execution_strategy(std::vector<pattern> patterns) : execution_strategy{std::move(patterns)} {}
std::vector<const char *> bubblewrap_execution_strategy::start(const program &program) { return {"bwrap", "--ro-bind", "/usr", "/usr", "--dir", "/tmp", "--dir", "/var", "--proc", "/proc", "--dev", "/dev", "--symlink", "usr/lib", "/lib", "--symlink", "usr/lib64", "/lib64", "--symlink", "usr/bin", "/bin", "--symlink", "usr/sbin", "/sbin", "--unshare-all", "--die-with-parent", "/bin/sh", nullptr}; }
std::vector<const char *> bubblewrap_execution_strategy::start(const program &program) {
std::vector<const char *> args{"bwrap", "--ro-bind", "/usr", "/usr", "--dir", "/tmp", "--dir", "/var", "--proc", "/proc", "--dev", "/dev", "--symlink", "usr/lib", "/lib", "--symlink", "usr/lib64", "/lib64", "--symlink", "usr/bin", "/bin", "--symlink", "usr/sbin", "/sbin", "--unshare-all", "--die-with-parent"};
concat_patterns(args, program);
return args;
}
void bubblewrap_execution_strategy::stop(const active_job &job) { ensure(kill(job.pid, SIGINT)); }
docker_execution_strategy::docker_execution_strategy(const std::vector<std::string> &patterns, std::string image) : execution_strategy{patterns}, image{std::move(image)} {}
docker_execution_strategy::docker_execution_strategy(std::vector<pattern> patterns, std::string image) : execution_strategy{std::move(patterns)}, image{std::move(image)} {}
std::vector<const char *> docker_execution_strategy::start(const program &program) { return {"docker", "run", "--rm", "-i", "--name", program.name.c_str(), "--pull=never", "--cap-drop=ALL", "--network=none", "--memory=64m", "--memory-swap=64m", "--pids-limit=128", image.c_str(), nullptr}; }
std::vector<const char *> docker_execution_strategy::start(const program &program) {
std::vector<const char *> args{"docker", "run", "--rm", "-i", "--name", program.name.c_str(), "--pull=never", "--cap-drop=ALL", "--network=none", "--memory=64m", "--memory-swap=64m", "--pids-limit=128", image.c_str()};
concat_patterns(args, program);
return args;
}
void docker_execution_strategy::stop(const active_job &job) {
const char *const kill_args[] = {"docker", "kill", job.job_id.c_str(), nullptr};
@ -111,6 +146,7 @@ run_result runner::run_blocking(const program &program) {
posix_spawn_file_actions_adddup2(&actions, out_pipe[1], STDOUT_FILENO);
posix_spawn_file_actions_adddup2(&actions, err_pipe[1], STDERR_FILENO);
std::vector<const char *> args = backend->start(program);
args.push_back(nullptr);
pid_t pid;
bool killed = false;
int exit_code;
@ -246,7 +282,13 @@ runner_list::runner_list(sk::runner_backend preferred_backend, const runner_conf
}
}
run_result runner_list::run_blocking(const program &program) { return runners.at(program.name).run_blocking(program); }
runner *runner_list::find_runner_for(const program &program) {
auto it = runners.find(program.image);
if (it != runners.end()) {
return &it->second;
}
return nullptr;
}
bool runner_list::kill_active(const std::string &jobId) {
return std::any_of(runners.begin(), runners.end(), [&jobId](auto &runner) { return runner.second.kill_active(jobId); });

@ -27,16 +27,21 @@ class execution_strategy {
std::vector<pattern> patterns;
public:
explicit execution_strategy(const std::vector<std::string> &patterns);
explicit execution_strategy(std::vector<pattern> patterns);
virtual std::vector<const char *> start(const program &program) = 0;
virtual void stop(const active_job &job) = 0;
virtual ~execution_strategy() = default;
static std::unique_ptr<execution_strategy> create(const runner_strategy_config &config);
protected:
void concat_patterns(std::vector<const char *> &args, const program &program) const;
};
class bubblewrap_execution_strategy : public execution_strategy {
public:
bubblewrap_execution_strategy(std::vector<pattern> patterns);
explicit bubblewrap_execution_strategy(const std::vector<std::string> &patterns);
explicit bubblewrap_execution_strategy(std::vector<pattern> patterns);
std::vector<const char *> start(const program &program) override;
void stop(const active_job &job) override;
};
@ -46,6 +51,7 @@ class docker_execution_strategy : public execution_strategy {
std::string image;
public:
docker_execution_strategy(const std::vector<std::string> &patterns, std::string image);
docker_execution_strategy(std::vector<pattern> patterns, std::string image);
std::vector<const char *> start(const program &program) override;
void stop(const active_job &job) override;
@ -74,7 +80,7 @@ class runner_list {
public:
runner_list(sk::runner_backend preferred_backend, const runner_config &config);
run_result run_blocking(const program &program);
runner *find_runner_for(const program &program);
bool kill_active(const std::string &jobId);
void exit_active_jobs();
};

Loading…
Cancel
Save