package docker import ( "bytes" "context" "io" "math" "sort" "strconv" "github.com/cuigh/swirl/misc" "github.com/cuigh/swirl/model" "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" "github.com/docker/docker/pkg/stdcopy" ) // TaskList return all running tasks of a service or a node. func TaskList(args *model.TaskListArgs) (infos []*model.TaskInfo, totalCount int, err error) { err = mgr.Do(func(ctx context.Context, cli *client.Client) (err error) { var ( tasks []swarm.Task opts = types.TaskListOptions{ Filters: filters.NewArgs(), } ) if args.PageIndex < 1 { args.PageIndex = 1 } if args.PageSize < 1 { args.PageSize = math.MaxInt32 } if args.Service != "" { opts.Filters.Add("service", args.Service) } if args.Node != "" { opts.Filters.Add("node", args.Node) } if args.Name != "" { opts.Filters.Add("name", args.Name) } if args.State != "" { opts.Filters.Add("desired-state", args.State) } tasks, err = cli.TaskList(ctx, opts) totalCount = len(tasks) if err == nil && totalCount > 0 { sort.Slice(tasks, func(i, j int) bool { return tasks[i].UpdatedAt.After(tasks[j].UpdatedAt) }) start, end := misc.Page(totalCount, args.PageIndex, args.PageSize) tasks = tasks[start:end] nodes := make(map[string]string) for _, t := range tasks { if _, ok := nodes[t.NodeID]; !ok { if n, _, e := cli.NodeInspectWithRaw(ctx, t.NodeID); e == nil { if n.Spec.Name == "" { nodes[t.NodeID] = n.Description.Hostname } else { nodes[t.NodeID] = n.Spec.Name } } else { nodes[t.NodeID] = "" } } } infos = make([]*model.TaskInfo, len(tasks)) for i, t := range tasks { infos[i] = model.NewTaskInfo(t, nodes[t.NodeID]) } } return }) return } // TaskInspect return detail information of a task. func TaskInspect(id string) (task swarm.Task, raw []byte, err error) { err = mgr.Do(func(ctx context.Context, cli *client.Client) (err error) { task, raw, err = cli.TaskInspectWithRaw(ctx, id) return }) return } // TaskLogs returns the logs generated by a task in an io.ReadCloser. // It's up to the caller to close the stream. func TaskLogs(id string, line int, timestamps bool) (stdout, stderr *bytes.Buffer, err error) { var ( ctx context.Context cli *client.Client rc io.ReadCloser ) ctx, cli, err = mgr.Client() if err != nil { return } opts := types.ContainerLogsOptions{ ShowStdout: true, ShowStderr: true, Tail: strconv.Itoa(line), Timestamps: timestamps, //Since: (time.Hour * 24).String() } if rc, err = cli.TaskLogs(ctx, id, opts); err == nil { defer rc.Close() stdout = &bytes.Buffer{} stderr = &bytes.Buffer{} _, err = stdcopy.StdCopy(stdout, stderr, rc) } return }