Unverified Commit acf3bafa authored by catsby's avatar catsby
Browse files

starting up docker

parent 228d899a
Branches unavailable
No related merge requests found
Showing with 227 additions and 178 deletions
+227 -178
......@@ -7,6 +7,7 @@ import (
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/testing/stepwise"
dockerDriver "github.com/hashicorp/vault/sdk/testing/stepwise/drivers/docker"
"github.com/mitchellh/mapstructure"
)
......@@ -14,6 +15,7 @@ import (
func TestBackend_basic_derived_docker(t *testing.T) {
// decryptData := make(map[string]interface{})
stepwise.Run(t, stepwise.Case{
Driver: dockerDriver.NewDockerDriver("transit"),
Steps: []stepwise.Step{
testAccStepwiseListPolicy(t, "test", true),
testAccStepwiseWritePolicy(t, "test", true),
......
......@@ -12,8 +12,10 @@ import (
"encoding/hex"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"log"
"math/big"
mathrand "math/rand"
"net"
......@@ -27,18 +29,30 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/pkg/archive"
"github.com/docker/go-connections/nat"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/internalshared/reloadutil"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/testing/stepwise"
"github.com/hashicorp/vault/vault"
"github.com/y0ssar1an/q"
"golang.org/x/net/http2"
docker "github.com/docker/docker/client"
)
var _ stepwise.StepDriver = &DockerCluster{}
// DockerCluster is used to managing the lifecycle of the test Vault cluster
type DockerCluster struct {
// PluginName is the input from the test case
PluginName string
// ClusterName is a UUID name of the cluster. Docker ID?
CluterName string
RaftStorage bool
ClientAuthRequired bool
BarrierKeys [][]byte
......@@ -59,12 +73,34 @@ type DockerCluster struct {
ClusterNodes []*DockerClusterNode
}
// Cleanup stops all the containers.
// Teardown stops all the containers.
// TODO: error/logging
func (rc *DockerCluster) Cleanup() {
func (rc *DockerCluster) Teardown() error {
q.Q("//-> driver teardown")
for _, node := range rc.ClusterNodes {
node.Cleanup()
}
// TODO should return something
return nil
}
func (dc *DockerCluster) Name() string {
// TODO return UUID cluster name
return dc.PluginName
}
func (dc *DockerCluster) Client() (*api.Client, error) {
if len(dc.ClusterNodes) > 0 {
if dc.ClusterNodes[0].Client != nil {
c, err := dc.ClusterNodes[0].Client.Clone()
if err != nil {
return nil, err
}
return c, nil
}
}
return nil, errors.New("no configured client found")
}
func (rc *DockerCluster) GetBarrierOrRecoveryKeys() [][]byte {
......@@ -514,7 +550,9 @@ func (n *DockerClusterNode) CreateAPIClient() (*api.Client, error) {
}
func (n *DockerClusterNode) Cleanup() {
q.Q("==> calling cleanup")
if err := n.dockerAPI.ContainerKill(context.Background(), n.container.ID, "KILL"); err != nil {
q.Q("====> should panic")
panic(err)
}
}
......@@ -822,3 +860,157 @@ func createNetwork(cli *docker.Client, netName, cidr string) (string, error) {
return resp.ID, nil
}
func NewDockerDriver(name string) *DockerCluster {
return &DockerCluster{
PluginName: name,
RaftStorage: true,
}
}
// Setup creates any temp dir and compiles the binary for copying to Docker
func (dc *DockerCluster) Setup() error {
// TODO many not use name here
name := dc.PluginName
// get the working directory of the plugin being tested.
srcDir, err := os.Getwd()
if err != nil {
panic(err)
}
// tmpDir gets cleaned up when the cluster is cleaned up
tmpDir, err := ioutil.TempDir("", "bin")
if err != nil {
log.Fatal(err)
}
binPath, sha256value, err := stepwise.CompilePlugin(name, srcDir, tmpDir)
if err != nil {
panic(err)
}
coreConfig := &vault.CoreConfig{
DisableMlock: true,
}
dOpts := &DockerClusterOptions{PluginTestBin: binPath}
cluster, err := NewDockerCluster(fmt.Sprintf("test-%s", name), coreConfig, dOpts)
if err != nil {
panic(err)
}
cores := cluster.ClusterNodes
client := cores[0].Client
// TODO maybe not use / need global here
// TODO: likely not a safe way of setting this either
stepwise.TestHelper = &stepwise.Helper{
Client: client,
// Cluster: cluster,
// TODO: maybe not needed
BuildDir: tmpDir,
}
// use client to mount plugin
err = client.Sys().RegisterPlugin(&api.RegisterPluginInput{
Name: name,
Type: consts.PluginTypeSecrets,
Command: name,
SHA256: sha256value,
})
if err != nil {
panic(err)
}
return nil
}
// Runner manages the lifecycle of the Docker container
type Runner struct {
dockerAPI *docker.Client
ContainerConfig *container.Config
ContainerName string
NetName string
IP string
CopyFromTo map[string]string
}
func (d *Runner) Start(ctx context.Context) (*types.ContainerJSON, error) {
hostConfig := &container.HostConfig{
PublishAllPorts: true,
// AutoRemove: false,
// TODO: configure auto remove
AutoRemove: true,
}
networkingConfig := &network.NetworkingConfig{}
switch d.NetName {
case "":
case "host":
hostConfig.NetworkMode = "host"
default:
es := &network.EndpointSettings{
//Links: nil,
Aliases: []string{d.ContainerName},
}
if len(d.IP) != 0 {
es.IPAMConfig = &network.EndpointIPAMConfig{
IPv4Address: d.IP,
}
}
networkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
d.NetName: es,
}
}
// best-effort pull
resp, _ := d.dockerAPI.ImageCreate(ctx, d.ContainerConfig.Image, types.ImageCreateOptions{})
if resp != nil {
_, _ = ioutil.ReadAll(resp)
}
cfg := *d.ContainerConfig
hostConfig.CapAdd = strslice.StrSlice{"IPC_LOCK"}
cfg.Hostname = d.ContainerName
//fullName := d.NetName + "." + d.ContainerName
fullName := d.ContainerName
container, err := d.dockerAPI.ContainerCreate(ctx, &cfg, hostConfig, networkingConfig, fullName)
if err != nil {
return nil, fmt.Errorf("container create failed: %v", err)
}
for from, to := range d.CopyFromTo {
srcInfo, err := archive.CopyInfoSourcePath(from, false)
if err != nil {
return nil, fmt.Errorf("error copying from source %q: %v", from, err)
}
srcArchive, err := archive.TarResource(srcInfo)
if err != nil {
return nil, fmt.Errorf("error creating tar from source %q: %v", from, err)
}
defer srcArchive.Close()
dstInfo := archive.CopyInfo{Path: to}
dstDir, content, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, dstInfo)
if err != nil {
return nil, fmt.Errorf("error preparing copy from %q -> %q: %v", from, to, err)
}
defer content.Close()
err = d.dockerAPI.CopyToContainer(ctx, container.ID, dstDir, content, types.CopyToContainerOptions{})
if err != nil {
return nil, fmt.Errorf("error copying from %q -> %q: %v", from, to, err)
}
}
err = d.dockerAPI.ContainerStart(ctx, container.ID, types.ContainerStartOptions{})
if err != nil {
return nil, fmt.Errorf("container start failed: %v", err)
}
inspect, err := d.dockerAPI.ContainerInspect(ctx, container.ID)
if err != nil {
return nil, err
}
return &inspect, nil
}
package docker
import (
"context"
"fmt"
"io/ioutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/strslice"
docker "github.com/docker/docker/client"
"github.com/docker/docker/pkg/archive"
)
// Runner manages the lifecycle of the Docker container
type Runner struct {
dockerAPI *docker.Client
ContainerConfig *container.Config
ContainerName string
NetName string
IP string
CopyFromTo map[string]string
}
func (d *Runner) Start(ctx context.Context) (*types.ContainerJSON, error) {
hostConfig := &container.HostConfig{
PublishAllPorts: true,
// AutoRemove: false,
// TODO: configure auto remove
AutoRemove: true,
}
networkingConfig := &network.NetworkingConfig{}
switch d.NetName {
case "":
case "host":
hostConfig.NetworkMode = "host"
default:
es := &network.EndpointSettings{
//Links: nil,
Aliases: []string{d.ContainerName},
}
if len(d.IP) != 0 {
es.IPAMConfig = &network.EndpointIPAMConfig{
IPv4Address: d.IP,
}
}
networkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{
d.NetName: es,
}
}
// best-effort pull
resp, _ := d.dockerAPI.ImageCreate(ctx, d.ContainerConfig.Image, types.ImageCreateOptions{})
if resp != nil {
_, _ = ioutil.ReadAll(resp)
}
cfg := *d.ContainerConfig
hostConfig.CapAdd = strslice.StrSlice{"IPC_LOCK"}
cfg.Hostname = d.ContainerName
//fullName := d.NetName + "." + d.ContainerName
fullName := d.ContainerName
container, err := d.dockerAPI.ContainerCreate(ctx, &cfg, hostConfig, networkingConfig, fullName)
if err != nil {
return nil, fmt.Errorf("container create failed: %v", err)
}
for from, to := range d.CopyFromTo {
srcInfo, err := archive.CopyInfoSourcePath(from, false)
if err != nil {
return nil, fmt.Errorf("error copying from source %q: %v", from, err)
}
srcArchive, err := archive.TarResource(srcInfo)
if err != nil {
return nil, fmt.Errorf("error creating tar from source %q: %v", from, err)
}
defer srcArchive.Close()
dstInfo := archive.CopyInfo{Path: to}
dstDir, content, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, dstInfo)
if err != nil {
return nil, fmt.Errorf("error preparing copy from %q -> %q: %v", from, to, err)
}
defer content.Close()
err = d.dockerAPI.CopyToContainer(ctx, container.ID, dstDir, content, types.CopyToContainerOptions{})
if err != nil {
return nil, fmt.Errorf("error copying from %q -> %q: %v", from, to, err)
}
}
err = d.dockerAPI.ContainerStart(ctx, container.ID, types.ContainerStartOptions{})
if err != nil {
return nil, fmt.Errorf("container start failed: %v", err)
}
inspect, err := d.dockerAPI.ContainerInspect(ctx, container.ID)
if err != nil {
return nil, err
}
return &inspect, nil
}
......@@ -5,16 +5,11 @@ import (
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/helper/consts"
dockerDriver "github.com/hashicorp/vault/sdk/testing/stepwise/drivers/docker"
"github.com/hashicorp/vault/vault"
)
// TestHelper is a package global that plugins will use to extract Vault
......@@ -25,23 +20,23 @@ var TestHelper *Helper
// other tests in a package can use to create Terraform execution contexts
type Helper struct {
// api client for use
Client *api.Client
Cluster *dockerDriver.DockerCluster
Client *api.Client
// Cluster *dockerDriver.DockerCluster
// name for plugin in test
Name string
// sourceDir is the dir containing the plugin test binary
SourceDir string
// temp dir where plugin is compiled
buildDir string
BuildDir string
}
// Cleanup cals the Cluster Cleanup method, if Cluster is not nil
func (h *Helper) Cleanup() {
if h.Cluster != nil {
h.Cluster.Cleanup()
}
if h.buildDir != "" {
_ = os.RemoveAll(h.buildDir) // clean up
// if h.Cluster != nil {
// h.Cluster.Cleanup()
// }
if h.BuildDir != "" {
_ = os.RemoveAll(h.BuildDir) // clean up
}
}
......@@ -64,7 +59,8 @@ func UseDocker(name, src string) *Helper {
// os.Exit(stat)
// }
func compilePlugin(name, srcDir, tmpDir string) (string, string, error) {
// CompilePlugin is a helper method to compile a sourc plugin
func CompilePlugin(name, srcDir, tmpDir string) (string, string, error) {
binPath := path.Join(tmpDir, name)
cmd := exec.Command("go", "build", "-o", path.Join(tmpDir, name), path.Join(srcDir, fmt.Sprintf("cmd/%s/main.go", name)))
......@@ -96,56 +92,3 @@ func compilePlugin(name, srcDir, tmpDir string) (string, string, error) {
return binPath, sha256value, err
}
// Setup creates any temp dir and compiles the binary for copying to Docker
func Setup(name string) error {
if os.Getenv("VAULT_ACC") == "1" {
// get the working directory of the plugin being tested.
srcDir, err := os.Getwd()
if err != nil {
panic(err)
}
// tmpDir gets cleaned up when the cluster is cleaned up
tmpDir, err := ioutil.TempDir("", "bin")
if err != nil {
log.Fatal(err)
}
binPath, sha256value, err := compilePlugin(name, srcDir, tmpDir)
if err != nil {
panic(err)
}
coreConfig := &vault.CoreConfig{
DisableMlock: true,
}
dOpts := &dockerDriver.DockerClusterOptions{PluginTestBin: binPath}
cluster, err := dockerDriver.NewDockerCluster(fmt.Sprintf("test-%s", name), coreConfig, dOpts)
if err != nil {
panic(err)
}
cores := cluster.ClusterNodes
client := cores[0].Client
TestHelper = &Helper{
Client: client,
Cluster: cluster,
buildDir: tmpDir,
}
// use client to mount plugin
err = client.Sys().RegisterPlugin(&api.RegisterPluginInput{
Name: name,
Type: consts.PluginTypeSecrets,
Command: name,
SHA256: sha256value,
})
if err != nil {
panic(err)
}
}
return nil
}
......@@ -73,10 +73,10 @@ type StepCheckFunc func(*api.Secret) error
// StepDriver is the interface Drivers need to implement to be used in
// Case to execute each Step
type StepDriver interface {
Setup()
Client()
Teardown()
Name() // maybe?
Setup() error
Client() (*api.Client, error)
Teardown() error
Name() string // maybe?
}
// Case is a single set of tests to run for a backend. A test Case
......@@ -149,6 +149,23 @@ func Run(tt TestT, c Case) {
}
// TODO setup on driver here
if c.Driver != nil {
q.Q("Found driver:", c.Driver)
err := c.Driver.Setup()
defer func() {
q.Q("==> calling driver teardown()")
err := c.Driver.Teardown()
if err != nil {
tt.Fatal(err)
}
}()
if err != nil {
tt.Fatal(err)
}
} else {
q.Q("nil driver")
tt.Fatal("nil driver")
}
// Create an in-memory Vault core
logger := logging.NewVaultLogger(log.Trace)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment