feat: dockerutils lib to start container images

This commit is contained in:
Markus Pesch 2020-06-08 22:16:07 +02:00
parent 4931c63c10
commit 940e04371c
Signed by: volker.raschek
GPG Key ID: 852BCC170D81A982
3 changed files with 713 additions and 57 deletions

View File

@ -71,6 +71,12 @@ func (builder *Builder) Mounts(mounts map[string]string) *Builder {
return builder return builder
} }
// Network add the container with aliasses to a specific network
func (builder *Builder) Network(networkName string, aliasses ...string) *Builder {
builder.networks[networkName] = aliasses
return builder
}
// Port defines a port forwarding from the host machine to the container // Port defines a port forwarding from the host machine to the container
// Examples: // Examples:
// - 8080:8080 // - 8080:8080
@ -109,92 +115,118 @@ func (builder *Builder) Start(ctx context.Context) (string, error) {
} }
} }
// check if ports are available // Network: portbinding Host->Container
exposedPorts, portBindings, err := nat.ParsePortSpecs(builder.ports) exposedPorts, portBindings, err := nat.ParsePortSpecs(builder.ports)
if err != nil { if err != nil {
return "", fmt.Errorf("Failed to parse ports %v: %v", builder.ports, err) return "", fmt.Errorf("unabel to parse ports: %v", err)
} }
if len(portBindings) > 0 { if len(portBindings) > 0 {
time.Sleep(1 * time.Second)
builder.containerConfig.ExposedPorts = exposedPorts builder.containerConfig.ExposedPorts = exposedPorts
builder.hostConfig.PortBindings = portBindings builder.hostConfig.PortBindings = portBindings
} }
// add endpoint settings to existing networks // Network: Add container to container networks
networkExist := make(map[string]bool, 0) // Add the container to the first defined container network, if any one is
for networkName := range builder.networks { // defined. If no one is defined, the docker API will add the container to
networkExist[networkName] = false // their default bridge docker0. The other networks will be added to the
} // container after the container start.
var (
networks, err := builder.client.NetworkList(ctx, types.NetworkListOptions{}) networkNames = make([]string, 0)
if err != nil { networks = make([]types.NetworkResource, 0)
return "", fmt.Errorf("Failed to list networks: %v", err) )
} if len(builder.networks) > 0 {
for networkName := range builder.networks {
for _, nw := range networks { networkNames = append(networkNames, networkName)
if aliases, present := builder.networks[nw.Name]; present {
networkExist[nw.Name] = true
builder.networkConfig.EndpointsConfig[nw.Name] = &network.EndpointSettings{
Aliases: aliases,
NetworkID: nw.ID,
}
} }
} var err error
networks, err = builder.client.NetworkListByNames(ctx, networkNames...)
for nw, found := range networkExist { if err != nil {
if !found { return "", err
return "", fmt.Errorf("Failed to add endpoint settings for network %v. It does not exist", nw)
} }
endpointSetting := &network.EndpointSettings{
NetworkID: networks[0].ID,
Aliases: builder.networks[networkNames[0]],
}
builder.networkConfig.EndpointsConfig[networkNames[0]] = endpointSetting
networkNames = networkNames[1:]
networks = networks[1:]
} }
// create container // Container: Create
resp, err := builder.client.ContainerCreate(ctx, builder.containerConfig, builder.hostConfig, builder.networkConfig, builder.containerName) resp, err := builder.client.ContainerCreate(
ctx,
builder.containerConfig,
builder.hostConfig,
builder.networkConfig,
builder.containerName,
)
if err != nil { if err != nil {
return "", fmt.Errorf("Failed to create container %v: %v", builder.containerName, err) return "", fmt.Errorf("Unable to create container: %v", err)
} }
// start container
err = builder.client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}) err = builder.client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
if err != nil { if err != nil {
stopError := builder.client.ContainerStopByIDs(ctx, time.Second, resp.ID)
if stopError != nil { shutdownErr := builder.client.ContainerStopByIDs(ctx, 1*time.Second, resp.ID)
return "", fmt.Errorf("Failed to start container %v: %v\nUnable to remove container %v. Manual cleanup necessary", builder.containerName, err, builder.containerName) if shutdownErr != nil {
return "", fmt.Errorf("Unable to start container: %v\nUnable to remove container %s: %v\nManual cleanup necessary", err, resp.ID, shutdownErr)
} }
return "", fmt.Errorf("Failed to start container %v: %v", builder.containerName, err) return "", fmt.Errorf("Unable to start container: %v", err)
} }
// wait for healthy // Network: Add more container networks
if builder.waitForHealthy { for i, networkName := range networkNames {
endpointSetting := &network.EndpointSettings{
NetworkID: networks[i].ID,
Aliases: builder.networks[networkName],
}
err := builder.client.NetworkConnect(ctx, networks[i].ID, resp.ID, endpointSetting)
if err != nil {
return "", fmt.Errorf("Unable to append container endpoint to network %v", networkName)
}
}
if builder.waitForHealthy {
watcher := builder.client.GetWatcher() watcher := builder.client.GetWatcher()
errorChannel := make(chan error, 1) errors := make(chan error, 1)
doneChannel := make(chan struct{}) done := make(chan struct{})
err = watcher.AddListener(resp.ID, errorChannel, doneChannel) err = watcher.AddListener(resp.ID, errors, done)
if err != nil { if err != nil {
containerRemoveError := builder.client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true}) containerRemoveError := builder.client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
if containerRemoveError != nil { if containerRemoveError != nil {
return "", fmt.Errorf("Failed while watching status for container %v: %v\nUnable to remove container %v: %v", resp.ID, err, resp.ID, containerRemoveError) return "", fmt.Errorf("error while watching for container status: %v - unable to remove container: %v", err, containerRemoveError)
} }
return "", fmt.Errorf("Failed while watching status for container %v: %v", resp.ID, err) return "", fmt.Errorf("error while watching for container status: %v", err)
} }
select { select {
case err := <-errorChannel: case err := <-errors:
if err != nil { if err != nil {
containerRemoveError := builder.client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true}) containerRemoveError := builder.client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
if containerRemoveError != nil { if containerRemoveError != nil {
return "", fmt.Errorf("Unable to remove container %v: %v", resp.ID, containerRemoveError) return "", fmt.Errorf("%v - unable to remove container: %v", err, containerRemoveError)
} }
return "", err return "", err
} }
case <-doneChannel: case <-done:
} }
} }
return resp.ID, nil return resp.ID, err
} }
func (builder *Builder) WaitForHealthy() *Builder { func (builder *Builder) WaitForHealthy() *Builder {
builder.waitForHealthy = true builder.waitForHealthy = true
return builder return builder
} }
// WithName set the name of the container
func (builder *Builder) WithName(containerName string) *Builder {
builder.containerName = containerName
return builder
}

View File

@ -13,9 +13,11 @@ import (
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client" "github.com/docker/docker/client"
) )
// Client from the docker API with additional functions
type Client struct { type Client struct {
*client.Client *client.Client
watcher *Watcher watcher *Watcher
@ -33,9 +35,9 @@ func (client *Client) Close() error {
} }
// ContainerListByLabels returns only containers which match by given labels // ContainerListByLabels returns only containers which match by given labels
func (client *Client) ContainerListByLabels(ctx context.Context, all bool, labels map[string]string) ([]types.Container, error) { func (client *Client) ContainerListByLabels(ctx context.Context, all bool, containerLabels map[string]string) ([]types.Container, error) {
filterArgs := filters.NewArgs() filterArgs := filters.NewArgs()
for key, value := range labels { for key, value := range containerLabels {
filterArgs.Add("label", fmt.Sprintf("%v=%v", key, value)) filterArgs.Add("label", fmt.Sprintf("%v=%v", key, value))
} }
containers, err := client.ContainerList(ctx, types.ContainerListOptions{ containers, err := client.ContainerList(ctx, types.ContainerListOptions{
@ -52,9 +54,9 @@ func (client *Client) ContainerListByLabels(ctx context.Context, all bool, label
} }
// ContainerListByNames returns only containers which match by given labels // ContainerListByNames returns only containers which match by given labels
func (client *Client) ContainerListByNames(ctx context.Context, all bool, names ...string) ([]types.Container, error) { func (client *Client) ContainerListByNames(ctx context.Context, all bool, containerNames ...string) ([]types.Container, error) {
filterArgs := filters.NewArgs() filterArgs := filters.NewArgs()
for _, name := range names { for _, name := range containerNames {
filterArgs.Add("name", name) filterArgs.Add("name", name)
} }
containers, err := client.ContainerList(ctx, types.ContainerListOptions{ containers, err := client.ContainerList(ctx, types.ContainerListOptions{
@ -82,8 +84,8 @@ func (client *Client) ContainerRemoveByIDs(ctx context.Context, containerIDs ...
} }
// ContainerRemoveByLabels deletes all containers which match by given labels // ContainerRemoveByLabels deletes all containers which match by given labels
func (client *Client) ContainerRemoveByLabels(ctx context.Context, labels map[string]string) error { func (client *Client) ContainerRemoveByLabels(ctx context.Context, containerLabels map[string]string) error {
containers, err := client.ContainerListByLabels(ctx, true, labels) containers, err := client.ContainerListByLabels(ctx, true, containerLabels)
if err != nil { if err != nil {
return err return err
} }
@ -97,8 +99,8 @@ func (client *Client) ContainerRemoveByLabels(ctx context.Context, labels map[st
} }
// ContainerRemoveByNames deletes all containers which match by their names // ContainerRemoveByNames deletes all containers which match by their names
func (client *Client) ContainerRemoveByNames(ctx context.Context, names ...string) error { func (client *Client) ContainerRemoveByNames(ctx context.Context, containerNames ...string) error {
containers, err := client.ContainerListByNames(ctx, true, names...) containers, err := client.ContainerListByNames(ctx, true, containerNames...)
if err != nil { if err != nil {
return err return err
} }
@ -123,8 +125,23 @@ func (client *Client) ContainerStopByIDs(ctx context.Context, timeout time.Durat
} }
// ContainerStopByLabels shutdown containters which match by given labels // ContainerStopByLabels shutdown containters which match by given labels
func (client *Client) ContainerStopByLabels(ctx context.Context, timeout time.Duration, labels map[string]string) error { func (client *Client) ContainerStopByLabels(ctx context.Context, timeout time.Duration, containerLabels map[string]string) error {
containers, err := client.ContainerListByLabels(ctx, true, labels) containers, err := client.ContainerListByLabels(ctx, true, containerLabels)
if err != nil {
return err
}
for _, container := range containers {
err := client.ContainerStop(ctx, container.ID, &timeout)
if err != nil {
return err
}
}
return nil
}
// ContainerStopByNames shutdown containters matching by their names
func (client *Client) ContainerStopByNames(ctx context.Context, timeout time.Duration, containerNames ...string) error {
containers, err := client.ContainerListByNames(ctx, true, containerNames...)
if err != nil { if err != nil {
return err return err
} }
@ -158,6 +175,96 @@ func (client *Client) GetWatcher() *Watcher {
return client.watcher return client.watcher
} }
// NetworkListByLabels returns networks which match by given labels
func (client *Client) NetworkListByLabels(ctx context.Context, networkLabels map[string]string) ([]types.NetworkResource, error) {
args := filters.NewArgs()
for key, value := range networkLabels {
args.Add("label", fmt.Sprintf("%v=%v", key, value))
}
return client.NetworkList(ctx, types.NetworkListOptions{
Filters: args,
})
}
// NetworkListByNames returns networks which match by their names. If a
// network can not be found, the function returns an error
func (client *Client) NetworkListByNames(ctx context.Context, networkNames ...string) ([]types.NetworkResource, error) {
networks, err := client.NetworkList(ctx, types.NetworkListOptions{})
if err != nil {
return nil, err
}
foundNetwork := make(map[string]bool, 0)
for _, networkName := range networkNames {
foundNetwork[networkName] = false
}
filteredNetworks := make([]types.NetworkResource, 0)
for _, networkName := range networkNames {
for _, network := range networks {
if network.Name == networkName {
filteredNetworks = append(filteredNetworks, network)
foundNetwork[networkName] = true
}
}
}
for _, networkName := range networkNames {
if !foundNetwork[networkName] {
return nil, fmt.Errorf("Network %v not found", networkName)
}
}
return filteredNetworks, nil
}
// NetworkRemoveByLabels remove all networks which match by given labels
func (client *Client) NetworkRemoveByLabels(ctx context.Context, containerLabels map[string]string) error {
networks, err := client.NetworkListByLabels(ctx, containerLabels)
if err != nil {
return err
}
for _, network := range networks {
err := client.NetworkRemove(ctx, network.ID)
if err != nil {
return err
}
}
return nil
}
// NetworkRemoveByNames remove all networks match by their names. If a
// network can not be found, the function returns an error
func (client *Client) NetworkRemoveByNames(ctx context.Context, networkNames ...string) error {
networks, err := client.NetworkListByNames(ctx, networkNames...)
if err != nil {
return err
}
for _, network := range networks {
err := client.NetworkRemove(ctx, network.ID)
if err != nil {
return err
}
}
return nil
}
// NetworkRemoveByIDs remove all networks match by their id
func (client *Client) NetworkRemoveByIDs(ctx context.Context, containerIDs ...string) error {
for _, containerID := range containerIDs {
err := client.NetworkRemove(ctx, containerID)
if err != nil {
return err
}
}
return nil
}
// NewBuilder returns a new builder for containers // NewBuilder returns a new builder for containers
func (client *Client) NewBuilder(image string) *Builder { func (client *Client) NewBuilder(image string) *Builder {
return &Builder{ return &Builder{
@ -165,8 +272,10 @@ func (client *Client) NewBuilder(image string) *Builder {
containerConfig: &container.Config{ containerConfig: &container.Config{
Image: image, Image: image,
}, },
hostConfig: new(container.HostConfig), hostConfig: new(container.HostConfig),
networkConfig: new(network.NetworkingConfig), networkConfig: &network.NetworkingConfig{
EndpointsConfig: make(map[string]*network.EndpointSettings, 0),
},
networks: make(map[string][]string, 0), networks: make(map[string][]string, 0),
ports: make([]string, 0), ports: make([]string, 0),
pull: false, pull: false,
@ -206,6 +315,78 @@ func (client *Client) PullQuiet(ctx context.Context, image string) error {
return client.Pull(ctx, image, ioutil.Discard) return client.Pull(ctx, image, ioutil.Discard)
} }
// VolumeListByLabels returns volumes which match by given labels
func (client *Client) VolumeListByLabels(ctx context.Context, volumeLabels map[string]string) (volume.VolumesListOKBody, error) {
args := filters.NewArgs()
for key, value := range volumeLabels {
args.Add("label", fmt.Sprintf("%v=%v", key, value))
}
return client.VolumeList(ctx, args)
}
// VolumeListByNames returns volumes which match by their names. If a
// volume can not be found, the function returns an error
func (client *Client) VolumeListByNames(ctx context.Context, volumeNames ...string) (volume.VolumesListOKBody, error) {
args := filters.NewArgs()
foundVolumes := make(map[string]bool, 0)
for _, volumeName := range volumeNames {
foundVolumes[volumeName] = false
args.Add("name", volumeName)
}
volumes, err := client.VolumeList(ctx, args)
if err != nil {
return volume.VolumesListOKBody{}, err
}
for _, volume := range volumes.Volumes {
foundVolumes[volume.Name] = true
}
for _, volumeName := range volumeNames {
if foundVolumes[volumeName] != true {
return volume.VolumesListOKBody{}, fmt.Errorf("Volume %v not found", volumeName)
}
}
return volumes, err
}
// VolumeRemoveByLabels remove all volumes match by their labels
func (client *Client) VolumeRemoveByLabels(ctx context.Context, volumeLabels map[string]string) error {
volumes, err := client.VolumeListByLabels(ctx, volumeLabels)
if err != nil {
return err
}
for _, volume := range volumes.Volumes {
err := client.VolumeRemove(ctx, volume.Name, true)
if err != nil {
return err
}
}
return nil
}
// VolumeRemoveByNames remove all volumes match by their names. If a
// volume can not be found, the function returns an error
func (client *Client) VolumeRemoveByNames(ctx context.Context, volumeNames ...string) error {
volumes, err := client.VolumeListByNames(ctx, volumeNames...)
if err != nil {
return err
}
for _, volume := range volumes.Volumes {
err := client.VolumeRemove(ctx, volume.Name, true)
if err != nil {
return err
}
}
return nil
}
// New returns a new dockerutil client // New returns a new dockerutil client
func New() (*Client, error) { func New() (*Client, error) {
dockerClient, err := client.NewEnvClient() dockerClient, err := client.NewEnvClient()

View File

@ -0,0 +1,443 @@
package dockerutils
import (
"context"
"fmt"
"net/http"
"strings"
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/volume"
uuid "github.com/satori/go.uuid"
"github.com/stretchr/testify/require"
)
// TestContainerCRUD
// Test the following API functions:
// - ContainerListByLabels
// - ContainerListByNames
// - ContainerRemoveByNames
// - ContainerRemoveByLabels
// - ContainerRemoveByIDs
func TestContainerCRUD(t *testing.T) {
var (
ctx = context.Background()
require = require.New(t)
iterations = 5
cleanupLabels = map[string]string{
uuid.NewV4().String(): uuid.NewV4().String(),
}
)
dockerClient, err := New()
require.NoError(err)
t.Cleanup(func() {
dockerClient.ContainerRemoveByLabels(ctx, cleanupLabels)
})
// Create Containers
containerIDs := make([]string, 0)
containerNames := make([]string, 0)
for i := 0; i < iterations; i++ {
containerName := uuid.NewV4().String()
containerID, err := dockerClient.NewBuilder("nginx:alpine").
Labels(cleanupLabels).
Port("80").
Pull().
WithName(containerName).
Start(ctx)
require.NoError(err)
containerNames = append(containerNames, containerName)
containerIDs = append(containerIDs, containerID)
}
// ListByLabels
containers, err := dockerClient.ContainerListByLabels(ctx, true, cleanupLabels)
require.NoError(err)
require.Len(containers, iterations)
for _, container := range containers {
require.Contains(containerIDs, container.ID)
require.Contains(containerNames, strings.Split(container.Names[0], "/")[1])
}
// ListByNames
containers, err = dockerClient.ContainerListByNames(ctx, true, containerNames...)
require.NoError(err)
require.Len(containers, iterations)
for _, container := range containers {
require.Contains(containerIDs, container.ID)
require.Contains(containerNames, strings.Split(container.Names[0], "/")[1])
}
// RemoveByLabels
err = dockerClient.ContainerRemoveByLabels(ctx, cleanupLabels)
require.NoError(err)
containers, err = dockerClient.ContainerListByLabels(ctx, true, cleanupLabels)
require.NoError(err)
require.Len(containers, 0)
// Create
containerIDs = make([]string, 0)
containerNames = make([]string, 0)
for i := 0; i < iterations; i++ {
containerName := uuid.NewV4().String()
containerID, err := dockerClient.NewBuilder("nginx:alpine").
Labels(cleanupLabels).
Port("80").
Pull().
WithName(containerName).
Start(ctx)
require.NoError(err)
containerNames = append(containerNames, containerName)
containerIDs = append(containerIDs, containerID)
}
// RemoveByNames
err = dockerClient.ContainerRemoveByNames(ctx, containerNames...)
require.NoError(err)
containers, err = dockerClient.ContainerListByNames(ctx, true, containerNames...)
require.NoError(err)
require.Len(containers, 0)
// Create
containerIDs = make([]string, 0)
containerNames = make([]string, 0)
for i := 0; i < iterations; i++ {
containerName := uuid.NewV4().String()
containerID, err := dockerClient.NewBuilder("nginx:alpine").
Labels(cleanupLabels).
Port("80").
Pull().
WithName(containerName).
Start(ctx)
require.NoError(err)
containerNames = append(containerNames, containerName)
containerIDs = append(containerIDs, containerID)
}
// RemoveByID
err = dockerClient.ContainerRemoveByIDs(ctx, containerIDs...)
require.NoError(err)
containers, err = dockerClient.ContainerListByLabels(ctx, true, cleanupLabels)
require.NoError(err)
require.Len(containers, 0)
}
// TestNetworkCRUD
// Test the following API functions:
// - NetworkListByLabels
// - NetworkListByNames
// - NetworkRemoveByLabels
// - NetworkRemoveByNames
// - NetworkRemoveByIDs
func TestNetworkCRUD(t *testing.T) {
var (
ctx = context.Background()
require = require.New(t)
iterations = 5
cleanupLabels = map[string]string{
uuid.NewV4().String(): uuid.NewV4().String(),
}
)
dockerClient, err := New()
require.NoError(err)
t.Cleanup(func() {
dockerClient.NetworkRemoveByLabels(ctx, cleanupLabels)
})
// Create Networks
networkIDs := make([]string, 0)
networkNames := make([]string, 0)
for i := 0; i < iterations; i++ {
networkName := uuid.NewV4().String()
resp, err := dockerClient.NetworkCreate(ctx, networkName, types.NetworkCreate{
Labels: cleanupLabels,
})
require.NoError(err)
networkNames = append(networkNames, networkName)
networkIDs = append(networkIDs, resp.ID)
}
// ListByLabels
networks, err := dockerClient.NetworkListByLabels(ctx, cleanupLabels)
require.NoError(err)
require.Len(networks, iterations)
for _, network := range networks {
require.Contains(networkIDs, network.ID)
require.Contains(networkNames, network.Name)
}
// ListByLabels, network with label does not exist
networks, err = dockerClient.NetworkListByLabels(ctx, map[string]string{uuid.NewV4().String(): uuid.NewV4().String()})
require.NoError(err)
require.Len(networks, 0)
// ListByNames
networks, err = dockerClient.NetworkListByNames(ctx, networkNames...)
require.NoError(err)
require.Len(networks, iterations)
for _, network := range networks {
require.Contains(networkIDs, network.ID)
require.Contains(networkNames, network.Name)
}
// ListByNames, network with names does not exist
networks, err = dockerClient.NetworkListByNames(ctx, uuid.NewV4().String(), uuid.NewV4().String())
require.Error(err)
require.Nil(networks)
// RemoveByLabels
err = dockerClient.NetworkRemoveByLabels(ctx, cleanupLabels)
require.NoError(err)
networks, err = dockerClient.NetworkListByLabels(ctx, cleanupLabels)
require.NoError(err)
require.Len(networks, 0)
// RemoveByLabels, label does not exists
err = dockerClient.NetworkRemoveByLabels(ctx, map[string]string{uuid.NewV4().String(): uuid.NewV4().String()})
require.NoError(err)
// Create Networks
networkIDs = make([]string, 0)
networkNames = make([]string, 0)
for i := 0; i < iterations; i++ {
networkName := uuid.NewV4().String()
resp, err := dockerClient.NetworkCreate(ctx, networkName, types.NetworkCreate{
Labels: cleanupLabels,
})
require.NoError(err)
networkNames = append(networkNames, networkName)
networkIDs = append(networkIDs, resp.ID)
}
// RemoveByNames
err = dockerClient.NetworkRemoveByNames(ctx, networkNames...)
require.NoError(err)
networks, err = dockerClient.NetworkListByNames(ctx, networkNames...)
require.Error(err)
require.Nil(networks)
// RemoveByNames, name does not exists
err = dockerClient.NetworkRemoveByNames(ctx, uuid.NewV4().String())
require.Error(err)
// Create Networks
networkIDs = make([]string, 0)
networkNames = make([]string, 0)
for i := 0; i < iterations; i++ {
networkName := uuid.NewV4().String()
resp, err := dockerClient.NetworkCreate(ctx, networkName, types.NetworkCreate{
Labels: cleanupLabels,
})
require.NoError(err)
networkNames = append(networkNames, networkName)
networkIDs = append(networkIDs, resp.ID)
}
// RemoveByIDs
err = dockerClient.NetworkRemoveByIDs(ctx, networkIDs...)
require.NoError(err)
networks, err = dockerClient.NetworkListByNames(ctx, networkNames...)
require.Error(err)
require.Nil(networks)
// RemoveByID, id does not exists
err = dockerClient.NetworkRemoveByIDs(ctx, uuid.NewV4().String())
require.Error(err)
}
func TestVolumeCRUD(t *testing.T) {
var (
ctx = context.Background()
require = require.New(t)
iterations = 5
cleanupLabels = map[string]string{
uuid.NewV4().String(): uuid.NewV4().String(),
}
)
dockerClient, err := New()
require.NoError(err)
t.Cleanup(func() {
dockerClient.VolumeRemoveByLabels(ctx, cleanupLabels)
})
// Create Volumes
volumeNames := make([]string, 0)
for i := 0; i < iterations; i++ {
volumeName := uuid.NewV4().String()
volume, err := dockerClient.VolumeCreate(ctx, volume.VolumesCreateBody{
Name: volumeName,
Labels: cleanupLabels,
})
require.NoError(err)
volumeNames = append(volumeNames, volume.Name)
}
// ListByLabels
volumes, err := dockerClient.VolumeListByLabels(ctx, cleanupLabels)
require.NoError(err)
require.Len(volumes.Volumes, iterations)
for _, volume := range volumes.Volumes {
require.Contains(volumeNames, volume.Name)
}
// ListByLabels, network with label does not exist
volumes, err = dockerClient.VolumeListByLabels(ctx, map[string]string{uuid.NewV4().String(): uuid.NewV4().String()})
require.NoError(err)
require.Len(volumes.Volumes, 0)
// ListByNames
volumes, err = dockerClient.VolumeListByNames(ctx, volumeNames...)
require.NoError(err)
require.Len(volumes.Volumes, iterations)
for _, volume := range volumes.Volumes {
require.Contains(volumeNames, volume.Name)
}
// ListByNames, network with names does not exist
volumes, err = dockerClient.VolumeListByNames(ctx, uuid.NewV4().String(), uuid.NewV4().String())
require.Error(err)
require.Nil(volumes.Volumes)
// RemoveByLabels
err = dockerClient.VolumeRemoveByLabels(ctx, cleanupLabels)
require.NoError(err)
volumes, err = dockerClient.VolumeListByLabels(ctx, cleanupLabels)
require.NoError(err)
require.Len(volumes.Volumes, 0)
// RemoveByLabels, labels does not exists
err = dockerClient.NetworkRemoveByLabels(ctx, map[string]string{uuid.NewV4().String(): uuid.NewV4().String()})
require.NoError(err)
// Create Volumes
volumeNames = make([]string, 0)
for i := 0; i < iterations; i++ {
volumeName := uuid.NewV4().String()
volume, err := dockerClient.VolumeCreate(ctx, volume.VolumesCreateBody{
Name: volumeName,
Labels: cleanupLabels,
})
require.NoError(err)
volumeNames = append(volumeNames, volume.Name)
}
// RemoveByNames
err = dockerClient.VolumeRemoveByNames(ctx, volumeNames...)
require.NoError(err)
volumes, err = dockerClient.VolumeListByNames(ctx, volumeNames...)
require.Error(err)
require.Nil(volumes.Volumes)
// RemoveByNames, name does not exists
err = dockerClient.NetworkRemoveByNames(ctx, uuid.NewV4().String())
require.Error(err)
}
// TestContainerMultipleNetworks
// Test if a container can be accessed ofer multiple networks/ips.
func TestContainerMultipleNetworks(t *testing.T) {
var (
ctx = context.Background()
require = require.New(t)
iterations = 5
cleanupLabels = map[string]string{
uuid.NewV4().String(): uuid.NewV4().String(),
}
)
dockerClient, err := New()
require.NoError(err)
t.Cleanup(func() {
dockerClient.ContainerRemoveByLabels(ctx, cleanupLabels)
dockerClient.NetworkRemoveByLabels(ctx, cleanupLabels)
})
// Create Containers
containerIDs := make([]string, 0)
containerNames := make([]string, 0)
containersNetworks := make(map[string]map[string][]string, 0)
for i := 0; i < iterations; i++ {
containerName := uuid.NewV4().String()
containerNetworks := map[string][]string{
uuid.NewV4().String(): {
uuid.NewV4().String(),
uuid.NewV4().String(),
},
uuid.NewV4().String(): {
uuid.NewV4().String(),
uuid.NewV4().String(),
},
}
builder := dockerClient.NewBuilder("nginx:alpine").
Labels(cleanupLabels).
Port("80").
Pull().
WithName(containerName)
for networkName, aliasses := range containerNetworks {
_, err := dockerClient.NetworkCreate(ctx, networkName, types.NetworkCreate{
Labels: cleanupLabels,
})
require.NoError(err)
builder.Network(networkName, aliasses...)
}
containerID, err := builder.Start(ctx)
require.NoError(err)
containerNames = append(containerNames, containerName)
containerIDs = append(containerIDs, containerID)
containersNetworks[containerID] = containerNetworks
}
for containerID, containerNetworks := range containersNetworks {
for networkName := range containerNetworks {
networks, err := dockerClient.NetworkListByNames(ctx, networkName)
require.NoError(err)
for _, network := range networks {
if _, present := network.Containers[containerID]; !present {
require.Fail("Container %v not found in network %v", containerID, network.ID)
}
networkIPParts := strings.Split(network.Containers[containerID].IPv4Address, "/")
url := fmt.Sprintf("http://%v", networkIPParts[0])
resp, err := http.Get(url)
require.NoError(err)
defer resp.Body.Close()
require.Equal(http.StatusOK, resp.StatusCode)
}
}
}
}