github.com/thediveo/gons@v0.9.9/README.md (about) 1 # gons 2 3 [![Go Reference](https://pkg.go.dev/badge/godoc.org/github.com/TheDiveO/gons.svg)](https://pkg.go.dev/github.com/TheDiveO/gons) 4 [![GitHub](https://img.shields.io/github/license/thediveo/gons)](https://img.shields.io/github/license/thediveo/gons) 5 ![build and test](https://github.com/TheDiveO/gons/workflows/build%20and%20test/badge.svg?branch=master) 6 [![Go Report Card](https://goreportcard.com/badge/github.com/thediveo/gons)](https://goreportcard.com/report/github.com/thediveo/gons) 7 ![Coverage](https://img.shields.io/badge/Coverage-82.9%25-brightgreen) 8 9 ## gons 10 11 `gons` ("go [*into*] namespaces") is a small Go package that selectively 12 switches your Go application into other already existing Linux namespaces. 13 This must happen before the Go runtime spins up, blocking certain namespace 14 changes, such as changing into a different mount namespace. 15 16 - `gons` switches the Go application *itself* it is linked to into a set of 17 already existing namespaces, and only so at *startup*. 18 - `gons` does *neither fork nor re-execute* in order to switch namespaces. 19 - `gons` *does not* create new namespaces. 20 21 In consequence, `gons` is a package tackling a different usecase than 22 `runc/libcontainer`'s famous 23 [*nsenter*](https://github.com/opencontainers/runc/tree/master/libcontainer/nsenter) 24 package. 25 26 The existing namespaces to join/switch into are referenced by their paths in 27 the filesystem (such as `/proc/123456/ns/mnt`), and are specified using 28 environment variables. Set only the environment variables for those namespaces 29 that should be switched at startup. These variables need to be set before your 30 application is started. The names of the environment variables are as follows 31 and must be all lowercase: 32 33 - `gons_cgroup=...` 34 - `gons_ipc=...` 35 - `gons_mnt=...` 36 - `gons_net=...` 37 - `gons_pid=...` (*please note that this does not switch your application's 38 own PID namespace, but rather controls the PID namespace any child processes 39 of your application will be put into.*) 40 - `gons_user=...` 41 - `gons_uts=...` 42 43 Additionally, you can specify the order in which the namespaces should be 44 switched, as well as when the namespace paths are to be opened: 45 46 - if not overridden by the optional environment variable `gons_order=...`, 47 then the default order is `!user,!mnt,!cgroup,!ipc,!net,!pid,!uts` (see 48 below for the meaning of "`!`"). It's not necessary to specify all 7 49 namespace types when you don't intend to switch them all. For instance, if 50 you just switch the net and IPC namespaces, then `gons_order=net,ipc` is 51 sufficient. 52 - when a namespace type name is preceded by a bang "`!`", such as `!user`, 53 then the its path will be opened before the first namespace switch takes 54 place. Without a bang, the namespace path is opened just right before 55 switching into this namespace. This is mostly of importance when switching 56 the mount namespace, as this can also change the filesystem and thus how the 57 namespace paths are resolved. 58 59 > **Note:** if a given namespace path is invalid, or if there are insufficient 60 > rights to access the path or switch to the specified namespace, then an 61 > error message is stored which you need to pick up later in your application 62 > using `gons.Status()`. Please see the package documentation for details. 63 64 The `gons` package requires [cgo](https://golang.org/cmd/cgo/): the required 65 namespace switches can only safely be done while your application is still 66 single-threaded and that's only the case before the Go runtime is spinning up. 67 68 ## gons/reexec 69 70 `gons/reexec` helps with forking and re-executing an application in order to 71 switch namespaces, run some action, sending back intelligence to the parent 72 application process, and then terminating the re-executed child. The parent 73 process (or rather: go routine) then continues, working on the intelligence 74 gathered. 75 76 A very simplistic example: 77 78 ```go 79 package main 80 81 import ( 82 "fmt" 83 "github.com/thediveo/gons/reexec" 84 ) 85 86 func init() { 87 reexec.Register("answertoeverything", func() { 88 fmt.Fprintln(os.Stdout, `42`) 89 }) 90 } 91 92 func main() { 93 var answer int 94 reexec.RunReexecAction("answertoeverything", reexec.Result(&s)) 95 fmt.Printf("answer: %d\n", answer) 96 } 97 ``` 98 99 - `reexec.Register` registers an action with its name and the code to execute. 100 - `reexec.RunReexecAction` forks and re-executes itself as a child process, 101 triggering the named action. It then picks up the result, which the action 102 has to print to `os.Stdout` in JSON format, and prints the result. 103 104 ## gons/reexec/testing 105 106 So you want to get code coverage data even across one or several 107 re-executions? Then you'll need to add a `TestMain` as follows: 108 109 ```go 110 package foobar 111 112 import ( 113 "testing" 114 115 rxtst "github.com/thediveo/gons/reexec/testing" 116 ) 117 118 func TestMain(m *testing.M) { 119 mm := &rxtst.M{M: m} 120 os.Exit(mm.Run()) 121 } 122 ``` 123 124 As you can see from this code above, `TestMain` takes the usual `m *testing.M` 125 parameter. But instead of directly calling `m.Run()` we have to wrap it into a 126 `txtst.M` instead, and call `Run()` only on the wrapper. This wrapper contains 127 the magic to cause re-executed actions to write coverage profile data and to 128 merge it with the main process' coverage profile data. 129 130 ## Copyright and License 131 132 `gons` is Copyright 2019-23 Harald Albrecht, and licensed under the Apache 133 License, Version 2.0.