github.1git.de/docker/cli@v26.1.3+incompatible/e2e/testutils/plugins.go (about) 1 package testutils 2 3 import ( 4 "context" 5 "crypto/rand" 6 "embed" 7 "encoding/base64" 8 "encoding/json" 9 "fmt" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "testing" 14 15 "github.com/docker/docker/api/types" 16 "github.com/pkg/errors" 17 "gotest.tools/v3/assert" 18 "gotest.tools/v3/fs" 19 "gotest.tools/v3/icmd" 20 ) 21 22 //go:embed plugins/* 23 var plugins embed.FS 24 25 // SetupPlugin builds a plugin and creates a temporary 26 // directory with the plugin's config.json and rootfs. 27 func SetupPlugin(t *testing.T, ctx context.Context) *fs.Dir { 28 t.Helper() 29 30 p := &types.PluginConfig{ 31 Linux: types.PluginConfigLinux{ 32 Capabilities: []string{"CAP_SYS_ADMIN"}, 33 }, 34 Interface: types.PluginConfigInterface{ 35 Socket: "basic.sock", 36 Types: []types.PluginInterfaceType{{Capability: "docker.dummy/1.0"}}, 37 }, 38 Entrypoint: []string{"/basic"}, 39 } 40 configJSON, err := json.Marshal(p) 41 assert.NilError(t, err) 42 43 binPath, err := buildPlugin(t, ctx) 44 assert.NilError(t, err) 45 46 dir := fs.NewDir(t, "plugin_test", 47 fs.WithFile("config.json", string(configJSON), fs.WithMode(0o644)), 48 fs.WithDir("rootfs", fs.WithMode(0o755)), 49 ) 50 51 icmd.RunCommand("/bin/cp", binPath, dir.Join("rootfs", p.Entrypoint[0])).Assert(t, icmd.Success) 52 return dir 53 } 54 55 // buildPlugin uses Go to build a plugin from one of the source files in the plugins directory. 56 // It returns the path to the built plugin binary. 57 // To allow for multiple plugins to be built in parallel, the plugin is compiled with a unique 58 // identifier in the binary. This is done by setting a linker flag with the -ldflags option. 59 func buildPlugin(t *testing.T, ctx context.Context) (string, error) { 60 t.Helper() 61 62 randomName, err := randomString() 63 if err != nil { 64 return "", err 65 } 66 67 goBin, err := exec.LookPath("/usr/local/go/bin/go") 68 if err != nil { 69 return "", err 70 } 71 installPath := filepath.Join(os.Getenv("GOPATH"), "bin", randomName) 72 73 pluginContent, err := plugins.ReadFile("plugins/basic.go") 74 if err != nil { 75 return "", err 76 } 77 dir := fs.NewDir(t, "plugin_build") 78 if err := os.WriteFile(dir.Join("main.go"), pluginContent, 0o644); err != nil { 79 return "", err 80 } 81 defer dir.Remove() 82 83 cmd := exec.CommandContext(ctx, goBin, "build", "-ldflags", 84 fmt.Sprintf("-X 'main.UNIQUEME=%s'", randomName), 85 "-o", installPath, dir.Join("main.go")) 86 87 cmd.Env = append(os.Environ(), "CGO_ENABLED=0") 88 89 if out, err := cmd.CombinedOutput(); err != nil { 90 return "", errors.Wrapf(err, "error building basic plugin bin: %s", string(out)) 91 } 92 93 return installPath, nil 94 } 95 96 func randomString() (string, error) { 97 b := make([]byte, 8) 98 if _, err := rand.Read(b); err != nil { 99 return "", err 100 } 101 return base64.StdEncoding.EncodeToString(b), nil 102 }