In order to discover Linux namespaces under certain conditions my open source Golang package lxkns needs to re-execute the application it is used in as a new child process in order to be able to switch mount namespaces before the Golang runtime spins up. The way Linux mount namespaces work makes it impossible to switch them from Golang applications after the runtime has spun up OS threads.
This means that the original process "P" re-runs a copy of itself as a child "C" (reexec package), passing a special indication via the child's environment which signals to the child to only run a specific "action" function belonging to the included "lxkns" package (see below for details), instead of running the whole application normally (avoiding endless recursively spawning children).
forkchild := exec.Command("/proc/self/exe")
forkchild.Start()
...
forkchild.Wait()
At the moment, I invoke the coverage tests from VisualStudio Code, which runs:
go test -timeout 30s -coverprofile=/tmp/vscode-goXXXXX/go-code-cover github.com/thediveo/lxkns
So, "P" re-executes a copy "C" of itself, and tells it to run some action "A", print some result to stdout, and then to immediately terminate. "P" waits for "C"'s output, parses it, and then continues in its program flow.
The module test uses Ginkgo/Gomega and a dedicated TestMain in order to catch when the test gets re-executed as a child in order to run only the requested "action" function.
package lxkns
import (
"os"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/thediveo/gons/reexec"
)
func TestMain(m *testing.M) {
// Ensure that the registered handler is run in the re-executed child. This
// won't trigger the handler while we're in the parent, because the
// parent's Arg[0] won't match the name of our handler.
reexec.CheckAction()
os.Exit(m.Run())
}
func TestLinuxKernelNamespaces(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "lxkns package")
}
I would like to also create code coverage data from the re-executed child process.
- Is it possible to enable code coverage from within the program under test itself, and how so?
- Is it possible to then append the code coverage data written by the child to the coverage data of the parent process "P"?
- Does the Golang runtime only write the coverage data at exit and does it overwrite the file specified, or does it append? (I would already be glad for a pointer to the corresponding runtime sources.)
Note: switching mount namespaces won't conflict with creating coverage files in the new mount namespaces in my test cases. The reason is that these test mount namespaces are copies of the initial mount namespaces, so creating a new file will show up also in the filesystem normally.

os.Create().