From dfe15524a2cdf1984e488c7dfe61bcd27bdf3605 Mon Sep 17 00:00:00 2001 From: cuigh Date: Mon, 20 Dec 2021 14:28:43 +0800 Subject: [PATCH] Add agent support for image and volume --- api/image.go | 21 ++++++++++-------- api/node.go | 11 ++++++++++ api/volume.go | 22 ++++++++++++++----- biz/image.go | 20 ++++++++--------- biz/node.go | 15 ++++++++++++- biz/task.go | 25 ++++++++++++++++++--- biz/volume.go | 27 ++++++++++++----------- docker/docker.go | 18 ++------------- docker/image.go | 21 +++++++++--------- docker/node.go | 17 +++++++------- docker/service.go | 2 +- docker/volume.go | 39 ++++++++++++++++++--------------- ui/src/api/image.ts | 9 ++++---- ui/src/api/node.ts | 4 ++-- ui/src/api/task.ts | 1 + ui/src/api/volume.ts | 13 ++++++----- ui/src/pages/container/List.vue | 6 +++-- ui/src/pages/image/List.vue | 33 +++++++++++++++++++++++----- ui/src/pages/image/View.vue | 3 ++- ui/src/pages/service/View.vue | 6 ++--- ui/src/pages/task/List.vue | 13 +++++++---- ui/src/pages/task/View.vue | 20 +++++++++++------ ui/src/pages/volume/List.vue | 37 +++++++++++++++++++++++++------ ui/src/pages/volume/View.vue | 3 ++- ui/src/router/router.ts | 6 ++--- 25 files changed, 253 insertions(+), 139 deletions(-) diff --git a/api/image.go b/api/image.go index 5dc095a..10268df 100644 --- a/api/image.go +++ b/api/image.go @@ -8,22 +8,23 @@ import ( // ImageHandler encapsulates image related handlers. type ImageHandler struct { - Search web.HandlerFunc `path:"/search" auth:"image.view" desc:"search images"` - Find web.HandlerFunc `path:"/find" auth:"image.view" desc:"find image by id"` - Delete web.HandlerFunc `path:"/delete" method:"post" auth:"image.delete" desc:"delete image"` + Search web.HandlerFunc `path:"/search" auth:"image.view" desc:"search images"` + Find web.HandlerFunc `path:"/find" auth:"image.view" desc:"find image by id"` + Delete web.HandlerFunc `path:"/delete" method:"post" auth:"image.delete" desc:"delete image"` } // NewImage creates an instance of ImageHandler func NewImage(b biz.ImageBiz) *ImageHandler { return &ImageHandler{ - Search: imageSearch(b), - Find: imageFind(b), - Delete: imageDelete(b), + Search: imageSearch(b), + Find: imageFind(b), + Delete: imageDelete(b), } } func imageSearch(b biz.ImageBiz) web.HandlerFunc { type Args struct { + Node string `json:"node" bind:"node"` Name string `json:"name" bind:"name"` PageIndex int `json:"pageIndex" bind:"pageIndex"` PageSize int `json:"pageSize" bind:"pageSize"` @@ -37,7 +38,7 @@ func imageSearch(b biz.ImageBiz) web.HandlerFunc { ) if err = ctx.Bind(args); err == nil { - images, total, err = b.Search(args.Name, args.PageIndex, args.PageSize) + images, total, err = b.Search(args.Node, args.Name, args.PageIndex, args.PageSize) } if err != nil { @@ -53,8 +54,9 @@ func imageSearch(b biz.ImageBiz) web.HandlerFunc { func imageFind(b biz.ImageBiz) web.HandlerFunc { return func(ctx web.Context) error { + node := ctx.Query("node") id := ctx.Query("id") - image, raw, err := b.Find(id) + image, raw, err := b.Find(node, id) if err != nil { return err } @@ -64,12 +66,13 @@ func imageFind(b biz.ImageBiz) web.HandlerFunc { func imageDelete(b biz.ImageBiz) web.HandlerFunc { type Args struct { + Node string `json:"node"` ID string `json:"id"` } return func(ctx web.Context) (err error) { args := &Args{} if err = ctx.Bind(args); err == nil { - err = b.Delete(args.ID, ctx.User()) + err = b.Delete(args.Node, args.ID, ctx.User()) } return ajax(ctx, err) } diff --git a/api/node.go b/api/node.go index ed542e6..e03f29d 100644 --- a/api/node.go +++ b/api/node.go @@ -33,6 +33,17 @@ func nodeList(nb biz.NodeBiz) web.HandlerFunc { return err } + if ctx.Query("agent") == "true" { + i := 0 + for j := 0; j < len(nodes); j++ { + if nodes[j].Agent != "" { + nodes[i] = nodes[j] + i++ + } + } + nodes = nodes[:i] + } + return success(ctx, nodes) } } diff --git a/api/volume.go b/api/volume.go index f690a79..25ae601 100644 --- a/api/volume.go +++ b/api/volume.go @@ -28,6 +28,7 @@ func NewVolume(b biz.VolumeBiz) *VolumeHandler { func volumeSearch(b biz.VolumeBiz) web.HandlerFunc { type Args struct { + Node string `json:"node" bind:"node"` Name string `json:"name" bind:"name"` PageIndex int `json:"pageIndex" bind:"pageIndex"` PageSize int `json:"pageSize" bind:"pageSize"` @@ -41,7 +42,7 @@ func volumeSearch(b biz.VolumeBiz) web.HandlerFunc { ) if err = ctx.Bind(args); err == nil { - volumes, total, err = b.Search(args.Name, args.PageIndex, args.PageSize) + volumes, total, err = b.Search(args.Node, args.Name, args.PageIndex, args.PageSize) } if err != nil { @@ -57,8 +58,9 @@ func volumeSearch(b biz.VolumeBiz) web.HandlerFunc { func volumeFind(b biz.VolumeBiz) web.HandlerFunc { return func(ctx web.Context) error { + node := ctx.Query("node") name := ctx.Query("name") - volume, raw, err := b.Find(name) + volume, raw, err := b.Find(node, name) if err != nil { return err } @@ -68,12 +70,13 @@ func volumeFind(b biz.VolumeBiz) web.HandlerFunc { func volumeDelete(b biz.VolumeBiz) web.HandlerFunc { type Args struct { + Node string `json:"node"` Name string `json:"name"` } return func(ctx web.Context) (err error) { args := &Args{} if err = ctx.Bind(args); err == nil { - err = b.Delete(args.Name, ctx.User()) + err = b.Delete(args.Node, args.Name, ctx.User()) } return ajax(ctx, err) } @@ -91,11 +94,20 @@ func volumeSave(b biz.VolumeBiz) web.HandlerFunc { } func volumePrune(b biz.VolumeBiz) web.HandlerFunc { - return func(ctx web.Context) error { - deletedVolumes, reclaimedSpace, err := b.Prune(ctx.User()) + type Args struct { + Node string `json:"node"` + } + return func(ctx web.Context) (err error) { + args := &Args{} + if err = ctx.Bind(args); err != nil { + return err + } + + deletedVolumes, reclaimedSpace, err := b.Prune(args.Node, ctx.User()) if err != nil { return err } + return success(ctx, data.Map{ "deletedVolumes": deletedVolumes, "reclaimedSpace": reclaimedSpace, diff --git a/biz/image.go b/biz/image.go index 909fb6a..3c92fbf 100644 --- a/biz/image.go +++ b/biz/image.go @@ -12,9 +12,9 @@ import ( ) type ImageBiz interface { - Search(name string, pageIndex, pageSize int) ([]*Image, int, error) - Find(name string) (image *Image, raw string, err error) - Delete(id string, user web.User) (err error) + Search(node, name string, pageIndex, pageSize int) ([]*Image, int, error) + Find(node, name string) (image *Image, raw string, err error) + Delete(node, id string, user web.User) (err error) } func NewImage(d *docker.Docker) ImageBiz { @@ -25,7 +25,7 @@ type imageBiz struct { d *docker.Docker } -func (b *imageBiz) Find(id string) (img *Image, raw string, err error) { +func (b *imageBiz) Find(node, id string) (img *Image, raw string, err error) { var ( i types.ImageInspect r []byte @@ -33,12 +33,12 @@ func (b *imageBiz) Find(id string) (img *Image, raw string, err error) { ctx = context.TODO() ) - if i, r, err = b.d.ImageInspect(ctx, id); err == nil { + if i, r, err = b.d.ImageInspect(ctx, node, id); err == nil { raw, err = indentJSON(r) } if err == nil { - histories, err = b.d.ImageHistory(ctx, id) + histories, err = b.d.ImageHistory(ctx, node, id) } if err == nil { @@ -47,8 +47,8 @@ func (b *imageBiz) Find(id string) (img *Image, raw string, err error) { return } -func (b *imageBiz) Search(name string, pageIndex, pageSize int) (images []*Image, total int, err error) { - list, total, err := b.d.ImageList(context.TODO(), name, pageIndex, pageSize) +func (b *imageBiz) Search(node, name string, pageIndex, pageSize int) (images []*Image, total int, err error) { + list, total, err := b.d.ImageList(context.TODO(), node, name, pageIndex, pageSize) if err != nil { return nil, 0, err } @@ -60,8 +60,8 @@ func (b *imageBiz) Search(name string, pageIndex, pageSize int) (images []*Image return images, total, nil } -func (b *imageBiz) Delete(id string, user web.User) (err error) { - err = b.d.ImageRemove(context.TODO(), id) +func (b *imageBiz) Delete(node, id string, user web.User) (err error) { + err = b.d.ImageRemove(context.TODO(), node, id) //if err == nil { // Event.CreateImage(model.EventActionDelete, id, user) //} diff --git a/biz/node.go b/biz/node.go index fe94ca0..c21010e 100644 --- a/biz/node.go +++ b/biz/node.go @@ -2,6 +2,7 @@ package biz import ( "context" + "sort" "github.com/cuigh/auxo/data" "github.com/cuigh/auxo/net/web" @@ -42,7 +43,19 @@ func (b *nodeBiz) Find(id string) (node *Node, raw string, err error) { } func (b *nodeBiz) List() ([]*docker.Node, error) { - return b.d.NodeListCache() + m, err := b.d.NodeMap() + if err != nil { + return nil, err + } + + nodes := make([]*docker.Node, 0, len(m)) + for _, n := range m { + 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() ([]*Node, error) { diff --git a/biz/task.go b/biz/task.go index 4f1b451..56360f7 100644 --- a/biz/task.go +++ b/biz/task.go @@ -28,12 +28,17 @@ func (b *taskBiz) Find(id string) (task *Task, raw string, err error) { s swarm.Service r []byte ) + t, r, err = b.d.TaskInspect(context.TODO(), id) if err == nil { raw, err = indentJSON(r) } + if err == nil { - task = newTask(&t) + m, _ := b.d.NodeMap() + task = newTask(&t, m) + + // Fill service name if s, _, _ = b.d.ServiceInspect(context.TODO(), t.ServiceID, false); s.Spec.Name == "" { task.ServiceName = task.ServiceID } else { @@ -50,9 +55,15 @@ func (b *taskBiz) Search(node, service, state string, pageIndex, pageSize int) ( return } + m, _ := b.d.NodeMap() tasks = make([]*Task, len(list)) for i, t := range list { - tasks[i] = newTask(&t) + tasks[i] = newTask(&t, m) + if m != nil { + if n, ok := m[t.NodeID]; ok { + tasks[i].NodeName = n.Name + } + } } return } @@ -75,6 +86,7 @@ type Task struct { ServiceID string `json:"serviceId"` ServiceName string `json:"serviceName"` NodeID string `json:"nodeId"` + NodeName string `json:"nodeName"` ContainerID string `json:"containerId"` PID int `json:"pid"` ExitCode int `json:"exitCode"` @@ -93,7 +105,7 @@ type TaskNetwork struct { IPs []string `json:"ips"` } -func newTask(t *swarm.Task) *Task { +func newTask(t *swarm.Task, nodes map[string]*docker.Node) *Task { task := &Task{ ID: t.ID, Name: t.Name, @@ -103,6 +115,7 @@ func newTask(t *swarm.Task) *Task { State: t.Status.State, ServiceID: t.ServiceID, NodeID: t.NodeID, + NodeName: t.NodeID, Message: t.Status.Message, Error: t.Status.Err, Env: envToOptions(t.Spec.ContainerSpec.Env), @@ -122,5 +135,11 @@ func newTask(t *swarm.Task) *Task { IPs: n.Addresses, }) } + // Fill node name + if nodes != nil { + if n, ok := nodes[t.NodeID]; ok { + task.NodeName = n.Name + } + } return task } diff --git a/biz/volume.go b/biz/volume.go index 68c693c..dade6ae 100644 --- a/biz/volume.go +++ b/biz/volume.go @@ -12,11 +12,11 @@ import ( ) type VolumeBiz interface { - Search(name string, pageIndex, pageSize int) ([]*Volume, int, error) - Find(name string) (volume *Volume, raw string, err error) - Delete(name string, user web.User) (err error) + Search(node, name string, pageIndex, pageSize int) ([]*Volume, int, error) + Find(node, name string) (volume *Volume, raw string, err error) + Delete(node, name string, user web.User) (err error) Create(volume *Volume, user web.User) (err error) - Prune(user web.User) (deletedVolumes []string, reclaimedSpace uint64, err error) + Prune(node string, user web.User) (deletedVolumes []string, reclaimedSpace uint64, err error) } func NewVolume(d *docker.Docker, eb EventBiz) VolumeBiz { @@ -28,13 +28,13 @@ type volumeBiz struct { eb EventBiz } -func (b *volumeBiz) Find(name string) (volume *Volume, raw string, err error) { +func (b *volumeBiz) Find(node, name string) (volume *Volume, raw string, err error) { var ( v types.Volume r []byte ) - if v, r, err = b.d.VolumeInspect(context.TODO(), name); err == nil { + if v, r, err = b.d.VolumeInspect(context.TODO(), node, name); err == nil { raw, err = indentJSON(r) } @@ -44,8 +44,8 @@ func (b *volumeBiz) Find(name string) (volume *Volume, raw string, err error) { return } -func (b *volumeBiz) Search(name string, pageIndex, pageSize int) (volumes []*Volume, total int, err error) { - list, total, err := b.d.VolumeList(context.TODO(), name, pageIndex, pageSize) +func (b *volumeBiz) Search(node, name string, pageIndex, pageSize int) (volumes []*Volume, total int, err error) { + list, total, err := b.d.VolumeList(context.TODO(), node, name, pageIndex, pageSize) if err != nil { return nil, 0, err } @@ -57,8 +57,8 @@ func (b *volumeBiz) Search(name string, pageIndex, pageSize int) (volumes []*Vol return volumes, total, nil } -func (b *volumeBiz) Delete(name string, user web.User) (err error) { - err = b.d.VolumeRemove(context.TODO(), name) +func (b *volumeBiz) Delete(node, name string, user web.User) (err error) { + err = b.d.VolumeRemove(context.TODO(), node, name) if err == nil { b.eb.CreateVolume(EventActionDelete, name, user) } @@ -78,16 +78,16 @@ func (b *volumeBiz) Create(vol *Volume, user web.User) (err error) { options.Driver = vol.Driver } - err = b.d.VolumeCreate(context.TODO(), options) + err = b.d.VolumeCreate(context.TODO(), vol.Node, options) if err != nil { b.eb.CreateVolume(EventActionDelete, vol.Name, user) } return } -func (b *volumeBiz) Prune(user web.User) (deletedVolumes []string, reclaimedSpace uint64, err error) { +func (b *volumeBiz) Prune(node string, user web.User) (deletedVolumes []string, reclaimedSpace uint64, err error) { var report types.VolumesPruneReport - report, err = b.d.VolumePrune(context.TODO()) + report, err = b.d.VolumePrune(context.TODO(), node) if err == nil { deletedVolumes, reclaimedSpace = report.VolumesDeleted, report.SpaceReclaimed b.eb.CreateVolume(EventActionPrune, "", user) @@ -96,6 +96,7 @@ func (b *volumeBiz) Prune(user web.User) (deletedVolumes []string, reclaimedSpac } type Volume struct { + Node string `json:"node"` Name string `json:"name"` Driver string `json:"driver,omitempty"` CustomDriver string `json:"customDriver,omitempty"` diff --git a/docker/docker.go b/docker/docker.go index 4100143..54c6a32 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -4,10 +4,8 @@ import ( "context" "strings" "sync" - "time" "github.com/cuigh/auxo/app/container" - "github.com/cuigh/auxo/cache" "github.com/cuigh/auxo/errors" "github.com/cuigh/auxo/log" "github.com/cuigh/auxo/util/lazy" @@ -91,11 +89,11 @@ func (d *Docker) agent(node string) (*client.Client, error) { } func (d *Docker) getAgent(node string) (agent string, err error) { - if node == "" || node == "@" { + if node == "" || node == "-" { return "", nil } - nodes, err := d.getNodes() + nodes, err := d.NodeMap() if err != nil { return } @@ -106,18 +104,6 @@ func (d *Docker) getAgent(node string) (agent string, err error) { return } -func (d *Docker) getNodes() (map[string]*Node, error) { - v := cache.Value{ - TTL: 30 * time.Minute, - Load: func() (interface{}, error) { return d.loadCache() }, - } - value, err := v.Get(true) - if err != nil { - return nil, err - } - return value.(map[string]*Node), nil -} - func (d *Docker) loadCache() (interface{}, error) { c, err := d.client() if err != nil { diff --git a/docker/image.go b/docker/image.go index 7c39c2f..46e81dd 100644 --- a/docker/image.go +++ b/docker/image.go @@ -11,8 +11,8 @@ import ( ) // ImageList return images on the host. -func (d *Docker) ImageList(ctx context.Context, name string, pageIndex, pageSize int) (images []types.ImageSummary, total int, err error) { - c, err := d.client() +func (d *Docker) ImageList(ctx context.Context, node, name string, pageIndex, pageSize int) (images []types.ImageSummary, total int, err error) { + c, err := d.agent(node) if err != nil { return nil, 0, err } @@ -34,27 +34,28 @@ func (d *Docker) ImageList(ctx context.Context, name string, pageIndex, pageSize } // ImageInspect returns image information. -func (d *Docker) ImageInspect(ctx context.Context, id string) (image types.ImageInspect, raw []byte, err error) { +func (d *Docker) ImageInspect(ctx context.Context, node, id string) (image types.ImageInspect, raw []byte, err error) { var c *client.Client - if c, err = d.client(); err == nil { + if c, err = d.agent(node); err == nil { return c.ImageInspectWithRaw(ctx, id) } return } // ImageHistory returns the changes in an image in history format. -func (d *Docker) ImageHistory(ctx context.Context, id string) (histories []image.HistoryResponseItem, err error) { +func (d *Docker) ImageHistory(ctx context.Context, node, id string) (histories []image.HistoryResponseItem, err error) { var c *client.Client - if c, err = d.client(); err == nil { + if c, err = d.agent(node); err == nil { return c.ImageHistory(ctx, id) } return } // ImageRemove remove a image. -func (d *Docker) ImageRemove(ctx context.Context, id string) error { - return d.call(func(c *client.Client) (err error) { +func (d *Docker) ImageRemove(ctx context.Context, node, id string) error { + c, err := d.agent(node) + if err == nil { _, err = c.ImageRemove(ctx, id, types.ImageRemoveOptions{}) - return - }) + } + return err } diff --git a/docker/node.go b/docker/node.go index a020204..6b23911 100644 --- a/docker/node.go +++ b/docker/node.go @@ -3,7 +3,9 @@ package docker import ( "context" "sort" + "time" + "github.com/cuigh/auxo/cache" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" @@ -60,15 +62,14 @@ func (d *Docker) NodeInspect(ctx context.Context, id string) (node swarm.Node, r return } -func (d *Docker) NodeListCache() ([]*Node, error) { - m, err := d.getNodes() +func (d *Docker) NodeMap() (map[string]*Node, error) { + v := cache.Value{ + TTL: 30 * time.Minute, + Load: func() (interface{}, error) { return d.loadCache() }, + } + value, err := v.Get(true) if err != nil { return nil, err } - - nodes := make([]*Node, 0, len(m)) - for _, n := range m { - nodes = append(nodes, n) - } - return nodes, nil + return value.(map[string]*Node), nil } diff --git a/docker/service.go b/docker/service.go index 01606de..05ea18a 100644 --- a/docker/service.go +++ b/docker/service.go @@ -82,7 +82,7 @@ func (d *Docker) fillStatus(ctx context.Context, c *client.Client, services []sw opts = types.TaskListOptions{Filters: filters.NewArgs()} ) - nodes, err = d.getNodes() + nodes, err = d.NodeMap() if err != nil { return } diff --git a/docker/volume.go b/docker/volume.go index 682a25e..71c0773 100644 --- a/docker/volume.go +++ b/docker/volume.go @@ -12,13 +12,13 @@ import ( ) // VolumeList return volumes on the host. -func (d *Docker) VolumeList(ctx context.Context, name string, pageIndex, pageSize int) (volumes []*types.Volume, total int, err error) { +func (d *Docker) VolumeList(ctx context.Context, node, name string, pageIndex, pageSize int) (volumes []*types.Volume, total int, err error) { var ( c *client.Client resp volume.VolumeListOKBody ) - c, err = d.client() + c, err = d.agent(node) if err != nil { return } @@ -44,34 +44,37 @@ func (d *Docker) VolumeList(ctx context.Context, name string, pageIndex, pageSiz } // VolumeCreate create a volume. -func (d *Docker) VolumeCreate(ctx context.Context, options *volume.VolumeCreateBody) error { - return d.call(func(c *client.Client) (err error) { +func (d *Docker) VolumeCreate(ctx context.Context, node string, options *volume.VolumeCreateBody) (err error) { + var c *client.Client + if c, err = d.agent(node); err == nil { _, err = c.VolumeCreate(ctx, *options) - return - }) + } + return } // VolumeRemove remove a volume. -func (d *Docker) VolumeRemove(ctx context.Context, name string) error { - return d.call(func(c *client.Client) (err error) { - return c.VolumeRemove(ctx, name, false) - }) +func (d *Docker) VolumeRemove(ctx context.Context, node, name string) (err error) { + c, err := d.agent(node) + if err == nil { + err = c.VolumeRemove(ctx, name, false) + } + return err } // VolumePrune remove all unused volumes. -func (d *Docker) VolumePrune(ctx context.Context, ) (report types.VolumesPruneReport, err error) { - err = d.call(func(c *client.Client) (err error) { +func (d *Docker) VolumePrune(ctx context.Context, node string) (report types.VolumesPruneReport, err error) { + var c *client.Client + if c, err = d.agent(node); err == nil { report, err = c.VolumesPrune(ctx, filters.NewArgs()) - return - }) + } return } // VolumeInspect return volume raw information. -func (d *Docker) VolumeInspect(ctx context.Context, name string) (vol types.Volume, raw []byte, err error) { - err = d.call(func(c *client.Client) error { +func (d *Docker) VolumeInspect(ctx context.Context, node, name string) (vol types.Volume, raw []byte, err error) { + var c *client.Client + if c, err = d.agent(node); err == nil { vol, raw, err = c.VolumeInspectWithRaw(ctx, name) - return err - }) + } return } diff --git a/ui/src/api/image.ts b/ui/src/api/image.ts index 7eebe52..21a7be9 100644 --- a/ui/src/api/image.ts +++ b/ui/src/api/image.ts @@ -46,6 +46,7 @@ export interface Image { } export interface SearchArgs { + node?: string; name?: string; pageIndex: number; pageSize: number; @@ -62,16 +63,16 @@ export interface FindResult { } export class ImageApi { - find(id: string) { - return ajax.get('/image/find', { id }) + find(node: string, id: string) { + return ajax.get('/image/find', { node, id }) } search(args: SearchArgs) { return ajax.get('/image/search', args) } - delete(id: string, name: string) { - return ajax.post>('/image/delete', { id, name }) + delete(node: string, id: string, name: string) { + return ajax.post>('/image/delete', { node, id, name }) } } diff --git a/ui/src/api/node.ts b/ui/src/api/node.ts index 78b7015..d420330 100644 --- a/ui/src/api/node.ts +++ b/ui/src/api/node.ts @@ -37,8 +37,8 @@ export class NodeApi { return ajax.get('/node/find', { id }) } - list() { - return ajax.get('/node/list') + list(agent: boolean) { + return ajax.get('/node/list', { agent }) } search() { diff --git a/ui/src/api/task.ts b/ui/src/api/task.ts index 811c79b..857e6c8 100644 --- a/ui/src/api/task.ts +++ b/ui/src/api/task.ts @@ -10,6 +10,7 @@ export interface Task { serviceId: string; serviceName: string; nodeId: string; + nodeName: string; containerId?: string; pid?: number; exitCode?: number; diff --git a/ui/src/api/volume.ts b/ui/src/api/volume.ts index d11dfc0..742106b 100644 --- a/ui/src/api/volume.ts +++ b/ui/src/api/volume.ts @@ -20,6 +20,7 @@ export interface Volume { } export interface SearchArgs { + node?: string; name?: string; pageIndex: number; pageSize: number; @@ -41,24 +42,24 @@ export interface PruneResult { } export class VolumeApi { - find(name: string) { - return ajax.get('/volume/find', { name }) + find(node: string, name: string) { + return ajax.get('/volume/find', { node, name }) } search(args: SearchArgs) { return ajax.get('/volume/search', args) } - delete(name: string) { - return ajax.post>('/volume/delete', { name }) + delete(node: string, name: string) { + return ajax.post>('/volume/delete', { node, name }) } save(v: Volume) { return ajax.post>('/volume/save', v) } - prune() { - return ajax.post('/volume/prune') + prune(node: string) { + return ajax.post('/volume/prune', { node }) } } diff --git a/ui/src/pages/container/List.vue b/ui/src/pages/container/List.vue index f0b6080..50ce6f9 100644 --- a/ui/src/pages/container/List.vue +++ b/ui/src/pages/container/List.vue @@ -3,7 +3,9 @@ { const node = c.labels?.find(l => l.name === 'com.docker.swarm.node.id') - return renderLink({ name: 'container_detail', params: { id: c.id, node: node?.value || '@' } }, c.name) + return renderLink({ name: 'container_detail', params: { id: c.id, node: node?.value || '-' } }, c.name) }, }, { @@ -93,7 +95,7 @@ async function deleteContainer(c: Container, index: number) { } onMounted(async () => { - const r = await nodeApi.list() + const r = await nodeApi.list(true) nodes.value = r.data?.map(n => ({ label: n.name, value: n.id })) if (r.data?.length) { filter.node = r.data[0].id diff --git a/ui/src/pages/image/List.vue b/ui/src/pages/image/List.vue index 2f5635e..8ce97f1 100644 --- a/ui/src/pages/image/List.vue +++ b/ui/src/pages/image/List.vue @@ -2,6 +2,16 @@ + {{ t('buttons.search') }} @@ -21,30 +31,34 @@ \ No newline at end of file diff --git a/ui/src/pages/image/View.vue b/ui/src/pages/image/View.vue index e0590d6..b67a69e 100644 --- a/ui/src/pages/image/View.vue +++ b/ui/src/pages/image/View.vue @@ -92,6 +92,7 @@ const { t } = useI18n() const route = useRoute(); const model = ref({} as Image); const raw = ref(''); +const node = route.params.node as string || ''; const columns = [ { title: t('fields.sn'), @@ -137,7 +138,7 @@ const columns = [ async function fetchData() { const id = route.params.id as string; - let r = await imageApi.find(id); + let r = await imageApi.find(node, id); model.value = r.data?.image as Image; raw.value = r.data?.raw as string; } diff --git a/ui/src/pages/service/View.vue b/ui/src/pages/service/View.vue index 63c5cf9..aa5aefb 100644 --- a/ui/src/pages/service/View.vue +++ b/ui/src/pages/service/View.vue @@ -444,7 +444,7 @@ - {{ t.id }} + {{ t.id }} {{ t.state }} - {{ t.nodeId }} + {{ t.nodeName }} @@ -481,7 +481,7 @@ \ No newline at end of file diff --git a/ui/src/pages/volume/View.vue b/ui/src/pages/volume/View.vue index 42f79ad..93577ef 100644 --- a/ui/src/pages/volume/View.vue +++ b/ui/src/pages/volume/View.vue @@ -97,10 +97,11 @@ const { t } = useI18n() const route = useRoute(); const model = ref({} as Volume); const raw = ref(''); +const node = route.params.node as string || ''; async function fetchData() { const name = route.params.name as string; - let r = await volumeApi.find(name); + let r = await volumeApi.find(node, name); model.value = r.data?.volume as Volume; raw.value = r.data?.raw as string; } diff --git a/ui/src/router/router.ts b/ui/src/router/router.ts index 9bf181d..bfaacc4 100644 --- a/ui/src/router/router.ts +++ b/ui/src/router/router.ts @@ -203,7 +203,7 @@ const routes: RouteRecordRaw[] = [ }, { name: "image_detail", - path: "/local/images/:id", + path: "/local/images/:node/:id", component: () => import('../pages/image/View.vue'), }, { @@ -223,12 +223,12 @@ const routes: RouteRecordRaw[] = [ }, { name: "volume_detail", - path: "/local/volumes/:name", + path: "/local/volumes/:node/:name", component: () => import('../pages/volume/View.vue'), }, { name: "volume_new", - path: "/local/volumes/new", + path: "/local/volumes/:node/new", component: () => import('../pages/volume/New.vue'), }, {