thin-edge/thin-edge.io

c8y-remote-access-plugin connection fails if installed in non-default location

Closed this issue · 2 comments

Describe the bug

It seems that when c8y-remote-access-plugin is called from the operation handler, if a custom --config-dir is passed to the device, that this is not propagated when the child process is spawned via c8y-remote-access-plugin --child <connection_string>.

When trying to connect to a give passthrough connection, the following error occurs:

% /opt/homebrew/bin/c8y-remote-access-plugin "--config-dir" "/opt/homebrew/etc/tedge" "530,rmi-macos,127.0.0.1,2812,33f21ccf-2eaa-4a1d-9216-2a414da1322a"
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value:   × Failed to spawn child process
  ╰─▶ No such file or directory (os error 2)
', crates/core/tedge/src/main.rs:50:58
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

It is unclear which file or directory does not exist as the error message does not supply a path.

To Reproduce

It is a bit tricky to reproduce as you have to use a non-standard installation, e.g. install thin-edge.io in any other folder other than /etc/tedge, and /etc/tedge must exist!

The instructions below assume you've used c8ylp before.

  1. Install thin-edge.io in a custom setup (you'll have to use custom tedge --config-dir init for this)

  2. Manually create the c8y_RemoteAccessConnect operation handler

    file: /opt/homebrew/etc/tedge/operations/c8y/c8y_RemoteAccessConnect

    [exec]
    command = "/opt/homebrew/bin/c8y-remote-access-plugin --config-dir /opt/homebrew/etc/tedge"
    topic = "c8y/s/ds"
    on_message = "530"
  3. Create a Remote Access passthrough configuration for a local port on the device (e.g. port 22 if you have a ssh daemon running)

  4. Try to connect to the Passthrough configuration using c8ylp

Expected behavior

The c8y-remote-access-plugin should work if installed in custom locations (e.g. not /etc/tedge)

Screenshots

Environment (please complete the following information):

  • OS [incl. version]: MacOS
  • Hardware [incl. revision]: M1 (Apple Silicon)
  • System-Architecture [e.g. result of "uname -a"]: Darwin SAG-LJWQ4P62TY 23.5.0 Darwin Kernel Version 23.5.0: Wed May 1 20:12:58 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6000 arm64
  • thin-edge.io version [e.g. 0.1.0]: 1.0.2~317+g1002ed6

Additional context

The following logic seems to be flawed. The spawn child should not have to re-read the operations file to work out how to launch itself, as the processes could be very different (say if someone overrides this)...instead the existing process should have all of the information it already needs (as the process is already running after all) without accessing the operation handler file.

async fn spawn_child(command: String, config_dir: &Utf8Path) -> miette::Result<()> {

Personally I would expected to see a reference to this function (or similar): https://doc.rust-lang.org/std/env/fn.current_exe.html#

For example (forgive my naive/limited Rust knowledge):

    let exec_path = std::env::current_exe()
        .into_diagnostic()
        .with_context(|| {
            format!("Could get current process executable")
        })?;

    let mut command = tokio::process::Command::new(exec_path)
        .args(["--config-dir", config_dir.as_str()])
        .arg("--child")
        .arg(command)
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()
        .into_diagnostic()
        .context("Failed to spawn child process")?;

With this change then the c8y-remote-access-plugin connection works:
image

QA has thoroughly checked the bug and here are the results:

  • Test for ticket exists in the test suite.
  • QA has tested the bug and it's not reproducable anymore