feat: dockerutils lib to start container images
This commit is contained in:
parent
4931c63c10
commit
940e04371c
@ -71,6 +71,12 @@ func (builder *Builder) Mounts(mounts map[string]string) *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
|
||||
// Examples:
|
||||
// - 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)
|
||||
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 {
|
||||
time.Sleep(1 * time.Second)
|
||||
builder.containerConfig.ExposedPorts = exposedPorts
|
||||
builder.hostConfig.PortBindings = portBindings
|
||||
}
|
||||
|
||||
// add endpoint settings to existing networks
|
||||
networkExist := make(map[string]bool, 0)
|
||||
// Network: Add container to container networks
|
||||
// Add the container to the first defined container network, if any one is
|
||||
// defined. If no one is defined, the docker API will add the container to
|
||||
// their default bridge docker0. The other networks will be added to the
|
||||
// container after the container start.
|
||||
var (
|
||||
networkNames = make([]string, 0)
|
||||
networks = make([]types.NetworkResource, 0)
|
||||
)
|
||||
if len(builder.networks) > 0 {
|
||||
for networkName := range builder.networks {
|
||||
networkExist[networkName] = false
|
||||
networkNames = append(networkNames, networkName)
|
||||
}
|
||||
|
||||
networks, err := builder.client.NetworkList(ctx, types.NetworkListOptions{})
|
||||
var err error
|
||||
networks, err = builder.client.NetworkListByNames(ctx, networkNames...)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to list networks: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, nw := range networks {
|
||||
if aliases, present := builder.networks[nw.Name]; present {
|
||||
networkExist[nw.Name] = true
|
||||
builder.networkConfig.EndpointsConfig[nw.Name] = &network.EndpointSettings{
|
||||
Aliases: aliases,
|
||||
NetworkID: nw.ID,
|
||||
}
|
||||
}
|
||||
endpointSetting := &network.EndpointSettings{
|
||||
NetworkID: networks[0].ID,
|
||||
Aliases: builder.networks[networkNames[0]],
|
||||
}
|
||||
|
||||
for nw, found := range networkExist {
|
||||
if !found {
|
||||
return "", fmt.Errorf("Failed to add endpoint settings for network %v. It does not exist", nw)
|
||||
}
|
||||
builder.networkConfig.EndpointsConfig[networkNames[0]] = endpointSetting
|
||||
|
||||
networkNames = networkNames[1:]
|
||||
networks = networks[1:]
|
||||
}
|
||||
|
||||
// create container
|
||||
resp, err := builder.client.ContainerCreate(ctx, builder.containerConfig, builder.hostConfig, builder.networkConfig, builder.containerName)
|
||||
// Container: Create
|
||||
resp, err := builder.client.ContainerCreate(
|
||||
ctx,
|
||||
builder.containerConfig,
|
||||
builder.hostConfig,
|
||||
builder.networkConfig,
|
||||
builder.containerName,
|
||||
)
|
||||
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{})
|
||||
if err != nil {
|
||||
stopError := builder.client.ContainerStopByIDs(ctx, time.Second, resp.ID)
|
||||
if stopError != nil {
|
||||
return "", fmt.Errorf("Failed to start container %v: %v\nUnable to remove container %v. Manual cleanup necessary", builder.containerName, err, builder.containerName)
|
||||
|
||||
shutdownErr := builder.client.ContainerStopByIDs(ctx, 1*time.Second, resp.ID)
|
||||
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("Unable to start container: %v", err)
|
||||
}
|
||||
|
||||
// Network: Add more container networks
|
||||
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)
|
||||
}
|
||||
return "", fmt.Errorf("Failed to start container %v: %v", builder.containerName, err)
|
||||
}
|
||||
|
||||
// wait for healthy
|
||||
if builder.waitForHealthy {
|
||||
|
||||
watcher := builder.client.GetWatcher()
|
||||
errorChannel := make(chan error, 1)
|
||||
doneChannel := make(chan struct{})
|
||||
err = watcher.AddListener(resp.ID, errorChannel, doneChannel)
|
||||
errors := make(chan error, 1)
|
||||
done := make(chan struct{})
|
||||
err = watcher.AddListener(resp.ID, errors, done)
|
||||
if err != nil {
|
||||
containerRemoveError := builder.client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
|
||||
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 {
|
||||
case err := <-errorChannel:
|
||||
case err := <-errors:
|
||||
if err != nil {
|
||||
containerRemoveError := builder.client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
|
||||
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
|
||||
}
|
||||
case <-doneChannel:
|
||||
case <-done:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return resp.ID, nil
|
||||
return resp.ID, err
|
||||
}
|
||||
|
||||
func (builder *Builder) WaitForHealthy() *Builder {
|
||||
builder.waitForHealthy = true
|
||||
return builder
|
||||
}
|
||||
|
||||
// WithName set the name of the container
|
||||
func (builder *Builder) WithName(containerName string) *Builder {
|
||||
builder.containerName = containerName
|
||||
return builder
|
||||
}
|
||||
|
@ -13,9 +13,11 @@ import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/client"
|
||||
)
|
||||
|
||||
// Client from the docker API with additional functions
|
||||
type Client struct {
|
||||
*client.Client
|
||||
watcher *Watcher
|
||||
@ -33,9 +35,9 @@ func (client *Client) Close() error {
|
||||
}
|
||||
|
||||
// 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()
|
||||
for key, value := range labels {
|
||||
for key, value := range containerLabels {
|
||||
filterArgs.Add("label", fmt.Sprintf("%v=%v", key, value))
|
||||
}
|
||||
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
|
||||
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()
|
||||
for _, name := range names {
|
||||
for _, name := range containerNames {
|
||||
filterArgs.Add("name", name)
|
||||
}
|
||||
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
|
||||
func (client *Client) ContainerRemoveByLabels(ctx context.Context, labels map[string]string) error {
|
||||
containers, err := client.ContainerListByLabels(ctx, true, labels)
|
||||
func (client *Client) ContainerRemoveByLabels(ctx context.Context, containerLabels map[string]string) error {
|
||||
containers, err := client.ContainerListByLabels(ctx, true, containerLabels)
|
||||
if err != nil {
|
||||
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
|
||||
func (client *Client) ContainerRemoveByNames(ctx context.Context, names ...string) error {
|
||||
containers, err := client.ContainerListByNames(ctx, true, names...)
|
||||
func (client *Client) ContainerRemoveByNames(ctx context.Context, containerNames ...string) error {
|
||||
containers, err := client.ContainerListByNames(ctx, true, containerNames...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -123,8 +125,23 @@ func (client *Client) ContainerStopByIDs(ctx context.Context, timeout time.Durat
|
||||
}
|
||||
|
||||
// ContainerStopByLabels shutdown containters which match by given labels
|
||||
func (client *Client) ContainerStopByLabels(ctx context.Context, timeout time.Duration, labels map[string]string) error {
|
||||
containers, err := client.ContainerListByLabels(ctx, true, labels)
|
||||
func (client *Client) ContainerStopByLabels(ctx context.Context, timeout time.Duration, containerLabels map[string]string) error {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -158,6 +175,96 @@ func (client *Client) GetWatcher() *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
|
||||
func (client *Client) NewBuilder(image string) *Builder {
|
||||
return &Builder{
|
||||
@ -166,7 +273,9 @@ func (client *Client) NewBuilder(image string) *Builder {
|
||||
Image: image,
|
||||
},
|
||||
hostConfig: new(container.HostConfig),
|
||||
networkConfig: new(network.NetworkingConfig),
|
||||
networkConfig: &network.NetworkingConfig{
|
||||
EndpointsConfig: make(map[string]*network.EndpointSettings, 0),
|
||||
},
|
||||
networks: make(map[string][]string, 0),
|
||||
ports: make([]string, 0),
|
||||
pull: false,
|
||||
@ -206,6 +315,78 @@ func (client *Client) PullQuiet(ctx context.Context, image string) error {
|
||||
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
|
||||
func New() (*Client, error) {
|
||||
dockerClient, err := client.NewEnvClient()
|
||||
|
443
pkg/testutils/dockerutils/client_test.go
Normal file
443
pkg/testutils/dockerutils/client_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user