Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better xtask run as sudo command #316

Merged
merged 2 commits into from
Sep 26, 2024
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
1 change: 1 addition & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[alias]
xtask = "run --package xtask --"
surun = "run --package xtask -- surun"

[target.x86_64-unknown-linux-gnu]
rustflags = [
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- name: Integration tests
if: endsWith(matrix.platform.target, 'musl')
run: |
cargo xtask test \
cargo xtask test-suite \
--force-architest \
--target=${{ matrix.platform.target }} \
--kernel-versions=${{ matrix.platform.kernel-versions }} \
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion xtask/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ clap = { workspace = true, features = ["derive"] }
flate2 = { workspace = true }
indicatif = { workspace = true }
num_cpus = { workspace = true }
reqwest = { workspace = true, default-features = false, features = ["blocking", "json", "rustls-tls"] }
reqwest = { workspace = true, default-features = false, features = [
"blocking",
"json",
"rustls-tls",
] }
serde = { workspace = true, features = ["derive"] }
signal-hook = { workspace = true }
tar = { workspace = true }
uuid = { workspace = true, features = ["v4"] }
xshell = { workspace = true }
log = { workspace = true }
env_logger = { workspace = true }
8 changes: 4 additions & 4 deletions xtask/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@ with `sudo`.

To run the eBPF test suite you can use:
```sh
cargo xtask test
cargo xtask test-suite
```

## Run pulsar daemon

To run the agent daemon you can use:
```sh
cargo xtask pulsard
cargo surun pulsard
```

## Run pulsar client

To run the agent client you can use:
```sh
cargo xtask pulsar
cargo surun pulsar
```

## Run single probe

To run a single module you can use:
```sh
cargo xtask probe file-system-monitor
cargo surun --example standalone-probes file-system-monitor
```
1 change: 1 addition & 0 deletions xtask/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod surun;
24 changes: 10 additions & 14 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use clap::Parser;
use run::run_with_sudo;
use signal_hook::{consts::TERM_SIGNALS, iterator::Signals};
use xtask::surun::SuRunCommand;

mod run;
mod tempdir;
mod test;
mod test_suite;
mod vmlinux;

#[derive(Debug, Parser)]
Expand All @@ -16,29 +15,26 @@ pub struct Options {

#[derive(Debug, Parser)]
enum Command {
/// Run pulsar daemon with admin privileges
Pulsard(run::Options),
/// Run pulsar cli with admin privileges
Pulsar(run::Options),
/// Run a single module with admin privileges
Probe(run::Options),
/// Same as `cargo run` but with admin privileges (using `sudo -E` as runner)
#[clap(name = "surun")]
SuRun(SuRunCommand),
/// Run eBPF test suite with admin privileges
Test(test::Options),
TestSuite(test_suite::Options),
/// Build headers with BTF type definitions.
Vmlinux(vmlinux::Options),
}

fn main() {
let opts = Options::parse();

env_logger::init();

// Drop term signals: register a handler, but never check it
let _ = Signals::new(TERM_SIGNALS).expect("error setting signal handler");

let ret = match opts.command {
Command::Pulsard(opts) => run_with_sudo("pulsar-exec", &["pulsard"], opts),
Command::Pulsar(opts) => run_with_sudo("pulsar-exec", &["pulsar"], opts),
Command::Probe(opts) => run_with_sudo("probe", &[], opts),
Command::Test(opts) => test::run(opts),
Command::SuRun(cmd) => cmd.run(),
Command::TestSuite(opts) => test_suite::run(opts),
Command::Vmlinux(opts) => vmlinux::run(opts),
};

Expand Down
41 changes: 0 additions & 41 deletions xtask/src/run.rs

This file was deleted.

91 changes: 91 additions & 0 deletions xtask/src/surun.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use anyhow::{bail, Context, Result};
use clap::Parser;
use xshell::{cmd, Shell};

#[derive(Debug, Parser)]
pub struct SuRunCommand {
/// Arguments normally passed to `cargo run`
#[clap(name = "ARGS", allow_hyphen_values = true)]
pub run_args: Vec<String>,
}

impl SuRunCommand {
pub fn run(&self) -> Result<()> {
let cargo = std::env::var("CARGO").unwrap();

// To determine the target triple it checks in order:
// - `--target` command line option
// - `CARGO_BUILD_TARGET` environment variable
// - default host target
//
// TODO: it should check also hierarchical `config.toml` files as described
// in the following page:
// https://doc.rust-lang.org/cargo/reference/config.html#hierarchical-structure
let target_triple = match self
.run_args
.iter()
.skip_while(|arg| *arg != "--target")
banditopazzo marked this conversation as resolved.
Show resolved Hide resolved
.nth(1) // skip the `--target` identifier
{
Some(target_triple) => target_triple.to_owned(),
None => {
const TARGET_TRIPLE_ENV: &str = "CARGO_BUILD_TARGET";

match std::env::var(TARGET_TRIPLE_ENV) {
Ok(target_triple) => target_triple,
Err(std::env::VarError::NotPresent) => {
get_default_target(&cargo)
.context(format!("failed to get target triple with {cargo}"))?
}
Err(std::env::VarError::NotUnicode(var)) => {
bail!("env variable `{TARGET_TRIPLE_ENV}` doesn't contain a valid unicode: {var:?}")
}
}
}
};

log::debug!("Detected host triple: {target_triple}");

let target_triple_env_runner = {
let tt_env_format = target_triple.to_uppercase().replace("-", "_");
format!("CARGO_TARGET_{tt_env_format}_RUNNER")
};

log::debug!("Overriding env variable: {target_triple_env_runner}");

let sh = Shell::new()?;

sh.set_var(target_triple_env_runner, "sudo -E");

let args = &self.run_args;

cmd!(sh, "{cargo} run {args...}").run()?;

Ok(())
}
}

/// Calls `cargo -vV`` in a subprocess and returns the default Clang target triple.
fn get_default_target(cargo_path: &str) -> Result<String> {
/// The [`rustc`][1] output field name that shows the target.
///
/// [1]: https://doc.rust-lang.org/rustc/what-is-rustc.html
const TARGET_FIELD: &str = "host: ";

// Query rustc for defaults.
let output = std::process::Command::new(cargo_path)
.arg("-vV")
.output()
.context(format!("failed to execute `{cargo_path} -vV`"))?;

// Decode stdout.
let stdout = std::str::from_utf8(&output.stdout).context("failed to read stdout into uft8")?;

// Parse the default target from stdout.
stdout
.lines()
.find(|l| l.starts_with(TARGET_FIELD))
.map(|l| &l[TARGET_FIELD.len()..])
.context(format!("failed to parse target from {cargo_path} output"))
.map(str::to_owned)
}
File renamed without changes.