mirror of https://github.com/docker/cli.git
103 lines
2.6 KiB
Go
103 lines
2.6 KiB
Go
|
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
|
||
|
}
|