dotcloud/docker

View on GitHub
integration-cli/daemon/daemon_swarm.go

Summary

Maintainability
C
1 day
Test Coverage
package daemon // import "github.com/docker/docker/integration-cli/daemon"

import (
    "context"
    "fmt"
    "strings"
    "testing"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/filters"
    "github.com/docker/docker/api/types/swarm"
    "github.com/docker/docker/errdefs"
    "gotest.tools/v3/assert"
)

// CheckServiceTasksInState returns the number of tasks with a matching state,
// and optional message substring.
func (d *Daemon) CheckServiceTasksInState(ctx context.Context, service string, state swarm.TaskState, message string) func(*testing.T) (interface{}, string) {
    return func(c *testing.T) (interface{}, string) {
        tasks := d.GetServiceTasks(ctx, c, service)
        var count int
        for _, task := range tasks {
            if task.Status.State == state {
                if message == "" || strings.Contains(task.Status.Message, message) {
                    count++
                }
            }
        }
        return count, ""
    }
}

// CheckServiceTasksInStateWithError returns the number of tasks with a matching state,
// and optional message substring.
func (d *Daemon) CheckServiceTasksInStateWithError(ctx context.Context, service string, state swarm.TaskState, errorMessage string) func(*testing.T) (interface{}, string) {
    return func(c *testing.T) (interface{}, string) {
        tasks := d.GetServiceTasks(ctx, c, service)
        var count int
        for _, task := range tasks {
            if task.Status.State == state {
                if errorMessage == "" || strings.Contains(task.Status.Err, errorMessage) {
                    count++
                }
            }
        }
        return count, ""
    }
}

// CheckServiceRunningTasks returns the number of running tasks for the specified service
func (d *Daemon) CheckServiceRunningTasks(ctx context.Context, service string) func(*testing.T) (interface{}, string) {
    return d.CheckServiceTasksInState(ctx, service, swarm.TaskStateRunning, "")
}

// CheckServiceUpdateState returns the current update state for the specified service
func (d *Daemon) CheckServiceUpdateState(ctx context.Context, service string) func(*testing.T) (interface{}, string) {
    return func(c *testing.T) (interface{}, string) {
        service := d.GetService(ctx, c, service)
        if service.UpdateStatus == nil {
            return "", ""
        }
        return service.UpdateStatus.State, ""
    }
}

// CheckPluginRunning returns the runtime state of the plugin
func (d *Daemon) CheckPluginRunning(ctx context.Context, plugin string) func(c *testing.T) (interface{}, string) {
    return func(c *testing.T) (interface{}, string) {
        apiclient := d.NewClientT(c)
        resp, _, err := apiclient.PluginInspectWithRaw(ctx, plugin)
        if errdefs.IsNotFound(err) {
            return false, fmt.Sprintf("%v", err)
        }
        assert.NilError(c, err)
        return resp.Enabled, fmt.Sprintf("%+v", resp)
    }
}

// CheckPluginImage returns the runtime state of the plugin
func (d *Daemon) CheckPluginImage(ctx context.Context, plugin string) func(c *testing.T) (interface{}, string) {
    return func(c *testing.T) (interface{}, string) {
        apiclient := d.NewClientT(c)
        resp, _, err := apiclient.PluginInspectWithRaw(ctx, plugin)
        if errdefs.IsNotFound(err) {
            return false, fmt.Sprintf("%v", err)
        }
        assert.NilError(c, err)
        return resp.PluginReference, fmt.Sprintf("%+v", resp)
    }
}

// CheckServiceTasks returns the number of tasks for the specified service
func (d *Daemon) CheckServiceTasks(ctx context.Context, service string) func(*testing.T) (interface{}, string) {
    return func(c *testing.T) (interface{}, string) {
        tasks := d.GetServiceTasks(ctx, c, service)
        return len(tasks), ""
    }
}

// CheckRunningTaskNetworks returns the number of times each network is referenced from a task.
func (d *Daemon) CheckRunningTaskNetworks(ctx context.Context) func(t *testing.T) (interface{}, string) {
    return func(t *testing.T) (interface{}, string) {
        cli := d.NewClientT(t)
        defer cli.Close()

        tasks, err := cli.TaskList(ctx, types.TaskListOptions{
            Filters: filters.NewArgs(filters.Arg("desired-state", "running")),
        })
        assert.NilError(t, err)

        result := make(map[string]int)
        for _, task := range tasks {
            for _, network := range task.Spec.Networks {
                result[network.Target]++
            }
        }
        return result, ""
    }
}

// CheckRunningTaskImages returns the times each image is running as a task.
func (d *Daemon) CheckRunningTaskImages(ctx context.Context) func(t *testing.T) (interface{}, string) {
    return func(t *testing.T) (interface{}, string) {
        cli := d.NewClientT(t)
        defer cli.Close()

        tasks, err := cli.TaskList(ctx, types.TaskListOptions{
            Filters: filters.NewArgs(filters.Arg("desired-state", "running")),
        })
        assert.NilError(t, err)

        result := make(map[string]int)
        for _, task := range tasks {
            if task.Status.State == swarm.TaskStateRunning && task.Spec.ContainerSpec != nil {
                result[task.Spec.ContainerSpec.Image]++
            }
        }
        return result, ""
    }
}

// CheckNodeReadyCount returns the number of ready node on the swarm
func (d *Daemon) CheckNodeReadyCount(ctx context.Context) func(t *testing.T) (interface{}, string) {
    return func(t *testing.T) (interface{}, string) {
        nodes := d.ListNodes(ctx, t)
        var readyCount int
        for _, node := range nodes {
            if node.Status.State == swarm.NodeStateReady {
                readyCount++
            }
        }
        return readyCount, ""
    }
}

// CheckLocalNodeState returns the current swarm node state
func (d *Daemon) CheckLocalNodeState(ctx context.Context) func(t *testing.T) (interface{}, string) {
    return func(t *testing.T) (interface{}, string) {
        info := d.SwarmInfo(ctx, t)
        return info.LocalNodeState, ""
    }
}

// CheckControlAvailable returns the current swarm control available
func (d *Daemon) CheckControlAvailable(ctx context.Context) func(t *testing.T) (interface{}, string) {
    return func(t *testing.T) (interface{}, string) {
        info := d.SwarmInfo(ctx, t)
        assert.Equal(t, info.LocalNodeState, swarm.LocalNodeStateActive)
        return info.ControlAvailable, ""
    }
}

// CheckLeader returns whether there is a leader on the swarm or not
func (d *Daemon) CheckLeader(ctx context.Context) func(t *testing.T) (interface{}, string) {
    return func(t *testing.T) (interface{}, string) {
        cli := d.NewClientT(t)
        defer cli.Close()

        errList := "could not get node list"

        ls, err := cli.NodeList(ctx, types.NodeListOptions{})
        if err != nil {
            return err, errList
        }

        for _, node := range ls {
            if node.ManagerStatus != nil && node.ManagerStatus.Leader {
                return nil, ""
            }
        }
        return fmt.Errorf("no leader"), "could not find leader"
    }
}

// CmdRetryOutOfSequence tries the specified command against the current daemon
// up to 10 times, retrying if it encounters an "update out of sequence" error.
func (d *Daemon) CmdRetryOutOfSequence(args ...string) (string, error) {
    var (
        output string
        err    error
    )

    for i := 0; i < 10; i++ {
        output, err = d.Cmd(args...)
        // error, no error, whatever. if we don't have "update out of
        // sequence", we don't retry, we just return.
        if !strings.Contains(output, "update out of sequence") {
            return output, err
        }
    }

    // otherwise, once all of our attempts have been exhausted, just return
    // whatever the last values were.
    return output, err
}