| package testutils |
| |
| import ( |
| "context" |
| "crypto/rand" |
| "embed" |
| "encoding/base64" |
| "encoding/json" |
| "fmt" |
| "os" |
| "os/exec" |
| "path/filepath" |
| "testing" |
| |
| "github.com/docker/docker/api/types" |
| "github.com/pkg/errors" |
| "gotest.tools/v3/assert" |
| "gotest.tools/v3/fs" |
| "gotest.tools/v3/icmd" |
| ) |
| |
| //go:embed plugins/* |
| var plugins embed.FS |
| |
| // SetupPlugin builds a plugin and creates a temporary |
| // directory with the plugin's config.json and rootfs. |
| func SetupPlugin(t *testing.T, ctx context.Context) *fs.Dir { |
| t.Helper() |
| |
| p := &types.PluginConfig{ |
| Linux: types.PluginConfigLinux{ |
| Capabilities: []string{"CAP_SYS_ADMIN"}, |
| }, |
| Interface: types.PluginConfigInterface{ |
| Socket: "basic.sock", |
| Types: []types.PluginInterfaceType{{Capability: "docker.dummy/1.0"}}, |
| }, |
| Entrypoint: []string{"/basic"}, |
| } |
| configJSON, err := json.Marshal(p) |
| assert.NilError(t, err) |
| |
| binPath, err := buildPlugin(t, ctx) |
| assert.NilError(t, err) |
| |
| dir := fs.NewDir(t, "plugin_test", |
| fs.WithFile("config.json", string(configJSON), fs.WithMode(0o644)), |
| fs.WithDir("rootfs", fs.WithMode(0o755)), |
| ) |
| |
| icmd.RunCommand("/bin/cp", binPath, dir.Join("rootfs", p.Entrypoint[0])).Assert(t, icmd.Success) |
| return dir |
| } |
| |
| // buildPlugin uses Go to build a plugin from one of the source files in the plugins directory. |
| // It returns the path to the built plugin binary. |
| // To allow for multiple plugins to be built in parallel, the plugin is compiled with a unique |
| // identifier in the binary. This is done by setting a linker flag with the -ldflags option. |
| func buildPlugin(t *testing.T, ctx context.Context) (string, error) { |
| t.Helper() |
| |
| randomName, err := randomString() |
| if err != nil { |
| return "", err |
| } |
| |
| goBin, err := exec.LookPath("/usr/local/go/bin/go") |
| if err != nil { |
| return "", err |
| } |
| installPath := filepath.Join(os.Getenv("GOPATH"), "bin", randomName) |
| |
| pluginContent, err := plugins.ReadFile("plugins/basic.go") |
| if err != nil { |
| return "", err |
| } |
| dir := fs.NewDir(t, "plugin_build") |
| if err := os.WriteFile(dir.Join("main.go"), pluginContent, 0o644); err != nil { |
| return "", err |
| } |
| defer dir.Remove() |
| |
| cmd := exec.CommandContext(ctx, goBin, "build", "-ldflags", |
| fmt.Sprintf("-X 'main.UNIQUEME=%s'", randomName), |
| "-o", installPath, dir.Join("main.go")) |
| |
| cmd.Env = append(os.Environ(), "CGO_ENABLED=0") |
| |
| if out, err := cmd.CombinedOutput(); err != nil { |
| return "", errors.Wrapf(err, "error building basic plugin bin: %s", string(out)) |
| } |
| |
| return installPath, nil |
| } |
| |
| func randomString() (string, error) { |
| b := make([]byte, 8) |
| if _, err := rand.Read(b); err != nil { |
| return "", err |
| } |
| return base64.StdEncoding.EncodeToString(b), nil |
| } |