Search code examples
gostoragesystem-callsiscsi

Using exec.CommandContext with sg_inq sys comand and timeout never returns


I'm trying to call sg_inq on a multipath device (/dev/mapper/mpatha). sg_inq sends a iScsi inquiry to the specific device and extracts some data. I'm using go's own exec.commandContext for the timeout, like this:

ctx, cancel := context.WithTimeout(context.Background(), 
time.Duration(1000)*time.Millisecond)
defer cancel()

cmd := exec.CommandContext(ctx, "sg_inq", "/dev/mapper/mpatha")
err := cmd.Run()
cmd.Stdout = &stdout
cmd.Stderr = &stderr
stdErr := stderr.Bytes()
stdOut := stdout.Bytes()

code reference in the official guide - https://golang.org/pkg/os/exec/#CommandContext

This code never returns. When I run it as a standalone script, it works fine. But what I run it as a part of a whole interface, it just gets stuck. I can see all of the calls "out", but none of them return.

Is there any reason why the same code snippet works in a standalone script but not in a whole go class? Or maybe I'm way off here and the problem is something else entirely? I'm compiling it on go 1.9.2 (latest) but I've tried on 1.9.1 as well.

The build works fine, the tests pass, so everything should be working.


Solution

  • The solution was pretty simple actually. The main problem was that the systemcall didn't always function properly. I've researched this using these links:

    http://www.darrencoxall.com/golang/executing-commands-in-go/
    https://github.com/ryankurte/go-async-cmd/blob/master/cmd.go

    I found out that the only place to read the output of a command was before cmd.Wait() and after cmd.Start(). That's why I kept getting an empty byte array. The code did return, it was just empty.

    What I found out more - https://medium.com/@vCabbage/go-timeout-commands-with-os-exec-commandcontext-ba0c861ed738

    This last link has an amazing solution to the problem I've encountered. not using cmd.Wait() at all.