package biz import ( "context" "sort" "github.com/cuigh/auxo/data" "github.com/cuigh/auxo/net/web" "github.com/cuigh/swirl/docker" "github.com/docker/docker/api/types/swarm" ) type NodeBiz interface { List(agent bool) ([]*docker.Node, error) Search(ctx context.Context) ([]*Node, error) Find(ctx context.Context, id string) (node *Node, raw string, err error) Delete(ctx context.Context, id, name string, user web.User) (err error) Update(ctx context.Context, n *Node, user web.User) (err error) } func NewNode(d *docker.Docker, eb EventBiz) NodeBiz { return &nodeBiz{d: d, eb: eb} } type nodeBiz struct { d *docker.Docker eb EventBiz } func (b *nodeBiz) Find(ctx context.Context, id string) (node *Node, raw string, err error) { var ( sn swarm.Node r []byte ) sn, r, err = b.d.NodeInspect(ctx, id) if err == nil { raw, err = indentJSON(r) } if err == nil { node = newNode(&sn) } return } func (b *nodeBiz) List(agent bool) ([]*docker.Node, error) { m, err := b.d.NodeMap() if err != nil { return nil, err } var nodes []*docker.Node for _, n := range m { if !agent || n.Agent != "" { nodes = append(nodes, n) } } sort.Slice(nodes, func(i, j int) bool { return nodes[i].Name < nodes[j].Name }) return nodes, nil } func (b *nodeBiz) Search(ctx context.Context) ([]*Node, error) { list, err := b.d.NodeList(ctx) if err != nil { return nil, err } networks := make([]*Node, len(list)) for i, n := range list { networks[i] = newNode(&n) } return networks, nil } func (b *nodeBiz) Delete(ctx context.Context, id, name string, user web.User) (err error) { err = b.d.NodeRemove(ctx, id) if err == nil { b.eb.CreateNode(EventActionDelete, id, name, user) } return } func (b *nodeBiz) Update(ctx context.Context, n *Node, user web.User) (err error) { spec := &swarm.NodeSpec{ Role: n.Role, Availability: n.Availability, } spec.Name = n.Name spec.Labels = toMap(n.Labels) err = b.d.NodeUpdate(ctx, n.ID, n.Version, spec) if err == nil { b.eb.CreateNode(EventActionUpdate, n.ID, n.Hostname, user) } return } type Node struct { ID string `json:"id"` Name string `json:"name,omitempty"` Hostname string `json:"hostname"` Version uint64 `json:"version"` Role swarm.NodeRole `json:"role"` Availability swarm.NodeAvailability `json:"availability"` EngineVersion string `json:"engineVersion"` Architecture string `json:"arch"` OS string `json:"os"` CPU int64 `json:"cpu"` Memory float32 `json:"memory"` Address string `json:"address"` State swarm.NodeState `json:"state"` Manager *NodeManager `json:"manager,omitempty"` Labels data.Options `json:"labels,omitempty"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } type NodeManager struct { Leader bool `json:"leader,omitempty"` Reachability swarm.Reachability `json:"reachability,omitempty"` Addr string `json:"addr,omitempty"` } func newNode(sn *swarm.Node) *Node { n := &Node{ ID: sn.ID, Name: sn.Spec.Name, Hostname: sn.Description.Hostname, Version: sn.Version.Index, Role: sn.Spec.Role, Availability: sn.Spec.Availability, EngineVersion: sn.Description.Engine.EngineVersion, Architecture: sn.Description.Platform.Architecture, OS: sn.Description.Platform.OS, CPU: sn.Description.Resources.NanoCPUs / 1e9, Memory: float32(sn.Description.Resources.MemoryBytes>>20) / 1024, Address: sn.Status.Addr, State: sn.Status.State, Labels: mapToOptions(sn.Spec.Labels), CreatedAt: formatTime(sn.CreatedAt), UpdatedAt: formatTime(sn.UpdatedAt), } if n.Role == swarm.NodeRoleManager { n.Manager = &NodeManager{ Leader: sn.ManagerStatus.Leader, Reachability: sn.ManagerStatus.Reachability, Addr: sn.ManagerStatus.Addr, } } return n }