| 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/client" |
| "gotest.tools/assert" |
| ) |
| |
| // CheckServiceTasksInState returns the number of tasks with a matching state, |
| // and optional message substring. |
| func (d *Daemon) CheckServiceTasksInState(service string, state swarm.TaskState, message string) func(*testing.T) (interface{}, string) { |
| return func(c *testing.T) (interface{}, string) { |
| tasks := d.GetServiceTasks(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(service string, state swarm.TaskState, errorMessage string) func(*testing.T) (interface{}, string) { |
| return func(c *testing.T) (interface{}, string) { |
| tasks := d.GetServiceTasks(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(service string) func(*testing.T) (interface{}, string) { |
| return d.CheckServiceTasksInState(service, swarm.TaskStateRunning, "") |
| } |
| |
| // CheckServiceUpdateState returns the current update state for the specified service |
| func (d *Daemon) CheckServiceUpdateState(service string) func(*testing.T) (interface{}, string) { |
| return func(c *testing.T) (interface{}, string) { |
| service := d.GetService(c, service) |
| if service.UpdateStatus == nil { |
| return "", "" |
| } |
| return service.UpdateStatus.State, "" |
| } |
| } |
| |
| // CheckPluginRunning returns the runtime state of the plugin |
| func (d *Daemon) CheckPluginRunning(plugin string) func(c *testing.T) (interface{}, string) { |
| return func(c *testing.T) (interface{}, string) { |
| apiclient := d.NewClientT(c) |
| resp, _, err := apiclient.PluginInspectWithRaw(context.Background(), plugin) |
| if client.IsErrNotFound(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(plugin string) func(c *testing.T) (interface{}, string) { |
| return func(c *testing.T) (interface{}, string) { |
| apiclient := d.NewClientT(c) |
| resp, _, err := apiclient.PluginInspectWithRaw(context.Background(), plugin) |
| if client.IsErrNotFound(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(service string) func(*testing.T) (interface{}, string) { |
| return func(c *testing.T) (interface{}, string) { |
| tasks := d.GetServiceTasks(c, service) |
| return len(tasks), "" |
| } |
| } |
| |
| // CheckRunningTaskNetworks returns the number of times each network is referenced from a task. |
| func (d *Daemon) CheckRunningTaskNetworks(c *testing.T) (interface{}, string) { |
| cli := d.NewClientT(c) |
| defer cli.Close() |
| |
| filterArgs := filters.NewArgs() |
| filterArgs.Add("desired-state", "running") |
| |
| options := types.TaskListOptions{ |
| Filters: filterArgs, |
| } |
| |
| tasks, err := cli.TaskList(context.Background(), options) |
| assert.NilError(c, 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(c *testing.T) (interface{}, string) { |
| cli := d.NewClientT(c) |
| defer cli.Close() |
| |
| filterArgs := filters.NewArgs() |
| filterArgs.Add("desired-state", "running") |
| |
| options := types.TaskListOptions{ |
| Filters: filterArgs, |
| } |
| |
| tasks, err := cli.TaskList(context.Background(), options) |
| assert.NilError(c, 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(c *testing.T) (interface{}, string) { |
| nodes := d.ListNodes(c) |
| 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(c *testing.T) (interface{}, string) { |
| info := d.SwarmInfo(c) |
| return info.LocalNodeState, "" |
| } |
| |
| // CheckControlAvailable returns the current swarm control available |
| func (d *Daemon) CheckControlAvailable(c *testing.T) (interface{}, string) { |
| info := d.SwarmInfo(c) |
| assert.Equal(c, info.LocalNodeState, swarm.LocalNodeStateActive) |
| return info.ControlAvailable, "" |
| } |
| |
| // CheckLeader returns whether there is a leader on the swarm or not |
| func (d *Daemon) CheckLeader(c *testing.T) (interface{}, string) { |
| cli := d.NewClientT(c) |
| defer cli.Close() |
| |
| errList := "could not get node list" |
| |
| ls, err := cli.NodeList(context.Background(), 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 |
| } |