diff --git a/biz/container.go b/biz/container.go index 6bc523f..8b9c8d2 100644 --- a/biz/container.go +++ b/biz/container.go @@ -63,7 +63,7 @@ func (b *containerBiz) Search(node, name, status string, pageIndex, pageSize int func (b *containerBiz) Delete(node, id, name string, user web.User) (err error) { err = b.d.ContainerRemove(context.TODO(), node, id) if err == nil { - b.eb.CreateContainer(EventActionDelete, id, name, user) + b.eb.CreateContainer(EventActionDelete, node, id, name, user) } return } @@ -92,7 +92,7 @@ func (b *containerBiz) Prune(node string, user web.User) (count int, size uint64 var report types.ContainersPruneReport if report, err = b.d.ContainerPrune(context.TODO(), node); err == nil { count, size = len(report.ContainersDeleted), report.SpaceReclaimed - b.eb.CreateContainer(EventActionPrune, "", "", user) + b.eb.CreateContainer(EventActionPrune, node, "", "", user) } return } diff --git a/biz/event.go b/biz/event.go index 61cdaef..c844e8f 100644 --- a/biz/event.go +++ b/biz/event.go @@ -3,6 +3,7 @@ package biz import ( "context" + "github.com/cuigh/auxo/data" "github.com/cuigh/auxo/log" "github.com/cuigh/auxo/net/web" "github.com/cuigh/swirl/dao" @@ -12,21 +13,20 @@ import ( type EventType string const ( - EventTypeRegistry EventType = "Registry" - EventTypeNode EventType = "Node" - EventTypeNetwork EventType = "Network" - EventTypeService EventType = "Service" - EventTypeServiceTemplate EventType = "Template" - EventTypeStack EventType = "Stack" - EventTypeConfig EventType = "Config" - EventTypeSecret EventType = "Secret" - EventTypeImage EventType = "Image" - EventTypeContainer EventType = "Container" - EventTypeVolume EventType = "Volume" - EventTypeUser EventType = "User" - EventTypeRole EventType = "Role" - EventTypeChart EventType = "Chart" - EventTypeSetting EventType = "Setting" + EventTypeRegistry EventType = "Registry" + EventTypeNode EventType = "Node" + EventTypeNetwork EventType = "Network" + EventTypeService EventType = "Service" + EventTypeStack EventType = "Stack" + EventTypeConfig EventType = "Config" + EventTypeSecret EventType = "Secret" + EventTypeImage EventType = "Image" + EventTypeContainer EventType = "Container" + EventTypeVolume EventType = "Volume" + EventTypeUser EventType = "User" + EventTypeRole EventType = "Role" + EventTypeChart EventType = "Chart" + EventTypeSetting EventType = "Setting" ) type EventAction string @@ -51,13 +51,12 @@ type EventBiz interface { CreateNode(action EventAction, id, name string, user web.User) CreateNetwork(action EventAction, id, name string, user web.User) CreateService(action EventAction, name string, user web.User) - CreateTemplate(action EventAction, id, name string, user web.User) CreateConfig(action EventAction, id, name string, user web.User) CreateSecret(action EventAction, id, name string, user web.User) CreateStack(action EventAction, name string, user web.User) - CreateImage(action EventAction, id string, user web.User) - CreateContainer(action EventAction, id, name string, user web.User) - CreateVolume(action EventAction, name string, user web.User) + CreateImage(action EventAction, node, id string, user web.User) + CreateContainer(action EventAction, node, id, name string, user web.User) + CreateVolume(action EventAction, node, name string, user web.User) CreateUser(action EventAction, id, name string, user web.User) CreateRole(action EventAction, id, name string, user web.User) CreateChart(action EventAction, id, title string, user web.User) @@ -76,79 +75,99 @@ func (b *eventBiz) Search(args *dao.EventSearchArgs) (events []*dao.Event, total return b.d.EventSearch(context.TODO(), args) } -func (b *eventBiz) create(et EventType, ea EventAction, code, name string, user web.User) { +func (b *eventBiz) create(et EventType, ea EventAction, args data.Map, user web.User) { event := &dao.Event{ ID: primitive.NewObjectID(), Type: string(et), Action: string(ea), - Code: code, - Name: name, + Args: args, UserID: user.ID(), Username: user.Name(), Time: now(), } err := b.d.EventCreate(context.TODO(), event) if err != nil { - log.Get("event").Errorf("failed to create event `%+v`: %v", event, err) + log.Get("event").Errorf("failed to create event `%+v`: %s", event, err) } } func (b *eventBiz) CreateRegistry(action EventAction, id, name string, user web.User) { - b.create(EventTypeRegistry, action, id, name, user) + args := data.Map{"id": id, "name": name} + b.create(EventTypeRegistry, action, args, user) } func (b *eventBiz) CreateService(action EventAction, name string, user web.User) { - b.create(EventTypeService, action, name, name, user) -} - -func (b *eventBiz) CreateTemplate(action EventAction, id, name string, user web.User) { - b.create(EventTypeServiceTemplate, action, id, name, user) + args := data.Map{"name": name} + b.create(EventTypeService, action, args, user) } func (b *eventBiz) CreateNetwork(action EventAction, id, name string, user web.User) { - b.create(EventTypeNetwork, action, id, name, user) + args := data.Map{"id": id, "name": name} + b.create(EventTypeNetwork, action, args, user) } func (b *eventBiz) CreateNode(action EventAction, id, name string, user web.User) { - b.create(EventTypeNode, action, id, name, user) + args := data.Map{"id": id, "name": name} + b.create(EventTypeNode, action, args, user) } -func (b *eventBiz) CreateImage(action EventAction, id string, user web.User) { - b.create(EventTypeImage, action, id, "", user) +func (b *eventBiz) CreateImage(action EventAction, node, id string, user web.User) { + args := data.Map{"node": node} + if id != "" { + args["id"] = id + } + b.create(EventTypeImage, action, args, user) } -func (b *eventBiz) CreateContainer(action EventAction, id, name string, user web.User) { - b.create(EventTypeContainer, action, id, name, user) +func (b *eventBiz) CreateContainer(action EventAction, node, id, name string, user web.User) { + args := data.Map{"node": node} + if id != "" { + args["id"] = id + } + if name != "" { + args["name"] = name + } + b.create(EventTypeContainer, action, args, user) } -func (b *eventBiz) CreateVolume(action EventAction, name string, user web.User) { - b.create(EventTypeVolume, action, name, name, user) +func (b *eventBiz) CreateVolume(action EventAction, node, name string, user web.User) { + args := data.Map{"node": node} + if name != "" { + args["name"] = name + } + b.create(EventTypeVolume, action, args, user) } func (b *eventBiz) CreateStack(action EventAction, name string, user web.User) { - b.create(EventTypeStack, action, name, name, user) + args := data.Map{"name": name} + b.create(EventTypeStack, action, args, user) } func (b *eventBiz) CreateSecret(action EventAction, id, name string, user web.User) { - b.create(EventTypeSecret, action, id, name, user) + args := data.Map{"id": id, "name": name} + b.create(EventTypeSecret, action, args, user) } func (b *eventBiz) CreateConfig(action EventAction, id, name string, user web.User) { - b.create(EventTypeConfig, action, id, name, user) + args := data.Map{"id": id, "name": name} + b.create(EventTypeConfig, action, args, user) } func (b *eventBiz) CreateRole(action EventAction, id, name string, user web.User) { - b.create(EventTypeRole, action, id, name, user) + args := data.Map{"id": id, "name": name} + b.create(EventTypeRole, action, args, user) } func (b *eventBiz) CreateSetting(action EventAction, user web.User) { - b.create(EventTypeSetting, action, "", "Setting", user) + b.create(EventTypeSetting, action, nil, user) } func (b *eventBiz) CreateUser(action EventAction, id, name string, user web.User) { - b.create(EventTypeUser, action, id, name, user) + args := data.Map{"id": id, "name": name} + b.create(EventTypeUser, action, args, user) } func (b *eventBiz) CreateChart(action EventAction, id, title string, user web.User) { - b.create(EventTypeChart, action, id, title, user) + args := data.Map{"id": id, "name": title} + b.create(EventTypeChart, action, args, user) } diff --git a/biz/image.go b/biz/image.go index 0a5c1bb..5dde386 100644 --- a/biz/image.go +++ b/biz/image.go @@ -65,7 +65,7 @@ func (b *imageBiz) Search(node, name string, pageIndex, pageSize int) (images [] func (b *imageBiz) Delete(node, id string, user web.User) (err error) { err = b.d.ImageRemove(context.TODO(), node, id) if err == nil { - b.eb.CreateImage(EventActionDelete, id, user) + b.eb.CreateImage(EventActionDelete, node, id, user) } return } @@ -74,7 +74,7 @@ func (b *imageBiz) Prune(node string, user web.User) (count int, size uint64, er var report types.ImagesPruneReport if report, err = b.d.ImagePrune(context.TODO(), node); err == nil { count, size = len(report.ImagesDeleted), report.SpaceReclaimed - b.eb.CreateImage(EventActionPrune, "", user) + b.eb.CreateImage(EventActionPrune, node, "", user) } return } diff --git a/biz/volume.go b/biz/volume.go index fc9a8b6..84f297e 100644 --- a/biz/volume.go +++ b/biz/volume.go @@ -60,7 +60,7 @@ func (b *volumeBiz) Search(node, name string, pageIndex, pageSize int) (volumes 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) + b.eb.CreateVolume(EventActionDelete, node, name, user) } return } @@ -79,8 +79,8 @@ func (b *volumeBiz) Create(vol *Volume, user web.User) (err error) { } err = b.d.VolumeCreate(context.TODO(), vol.Node, options) - if err != nil { - b.eb.CreateVolume(EventActionDelete, vol.Name, user) + if err == nil { + b.eb.CreateVolume(EventActionDelete, vol.Node, vol.Name, user) } return } @@ -90,7 +90,7 @@ func (b *volumeBiz) Prune(node string, user web.User) (count int, size uint64, e report, err = b.d.VolumePrune(context.TODO(), node) if err == nil { count, size = len(report.VolumesDeleted), report.SpaceReclaimed - b.eb.CreateVolume(EventActionPrune, "", user) + b.eb.CreateVolume(EventActionPrune, node, "", user) } return } diff --git a/dao/bolt/event.go b/dao/bolt/event.go index 409ca36..c267154 100644 --- a/dao/bolt/event.go +++ b/dao/bolt/event.go @@ -5,6 +5,7 @@ import ( "sort" "time" + "github.com/cuigh/auxo/util/cast" "github.com/cuigh/swirl/dao" "github.com/cuigh/swirl/misc" ) @@ -21,7 +22,7 @@ func (d *Dao) EventSearch(ctx context.Context, args *dao.EventSearchArgs) (event match := true if args.Name != "" { - match = matchAny(args.Name, event.Name) + match = event.Args != nil && matchAny(args.Name, cast.ToString(event.Args["name"])) } if match && args.Type != "" { match = event.Type == args.Type diff --git a/dao/entity.go b/dao/entity.go index 9536491..9927acc 100644 --- a/dao/entity.go +++ b/dao/entity.go @@ -140,8 +140,7 @@ type Event struct { ID primitive.ObjectID `json:"id" bson:"_id"` Type string `json:"type" bson:"type"` Action string `json:"action" bson:"action"` - Code string `json:"code" bson:"code"` - Name string `json:"name" bson:"name"` + Args data.Map `json:"args" bson:"args"` UserID string `json:"userId" bson:"user_id"` Username string `json:"username" bson:"username"` Time Time `json:"time" bson:"time"` diff --git a/dao/mongo/event.go b/dao/mongo/event.go index 5127a2f..ff20089 100644 --- a/dao/mongo/event.go +++ b/dao/mongo/event.go @@ -15,7 +15,7 @@ func (d *Dao) EventSearch(ctx context.Context, args *dao.EventSearchArgs) (event filter["type"] = args.Type } if args.Name != "" { - filter["name"] = args.Name + filter["args.name"] = args.Name } opts := searchOptions{filter: filter, sorter: bson.M{"_id": -1}, pageIndex: args.PageIndex, pageSize: args.PageSize} events = []*dao.Event{} diff --git a/dao/mongo/mongo.go b/dao/mongo/mongo.go index 6cb35b2..2c57dd6 100644 --- a/dao/mongo/mongo.go +++ b/dao/mongo/mongo.go @@ -33,7 +33,7 @@ var indexes = map[string][]mongo.IndexModel{ }, "event": { mongo.IndexModel{Keys: bson.D{{"type", 1}}}, - mongo.IndexModel{Keys: bson.D{{"name", 1}}}, + mongo.IndexModel{Keys: bson.D{{"args.name", 1}}}, }, "session": { mongo.IndexModel{ diff --git a/ui/src/api/event.ts b/ui/src/api/event.ts index eba1ab5..a1b4412 100644 --- a/ui/src/api/event.ts +++ b/ui/src/api/event.ts @@ -4,8 +4,9 @@ export interface Event { id: string; type: string; action: string; - code: number; - name: string; + args: { + [key: string]: string; + }; userId: string; username: string; time: number; diff --git a/ui/src/components/chart/chart.ts b/ui/src/components/chart/chart.ts index 35122c6..1eb256f 100644 --- a/ui/src/components/chart/chart.ts +++ b/ui/src/components/chart/chart.ts @@ -291,236 +291,3 @@ export function createChart(dom: HTMLElement, info: ChartInfo): Chart { throw new Error('unknown chart type: ' + info.type) } } - -// export class ChartDashboardOptions { -// name: string; -// key?: string; -// period?: number = 30; -// refreshInterval?: number = 15; // seconds -// } - -// export class ChartDashboard { -// private $panel: JQuery; -// private readonly opts: ChartDashboardOptions; -// private charts: Chart[] = []; -// private timer: number; -// private dlg: ChartDialog; - -// constructor(elem: string | Element | JQuery, charts: ChartData[], opts?: ChartDashboardOptions) { -// this.opts = $.extend(new ChartDashboardOptions(), opts); -// this.$panel = $(elem); -// this.dlg = new ChartDialog(this); - -// charts.forEach(opts => this.createGraph(opts)); - -// // events -// Dispatcher.bind(this.$panel).on("remove-chart", e => { -// let name = $(e.target).closest("div.column").data("name"); -// Modal.confirm(`Are you sure to delete chart: ${name}?`, "Delete chart", dlg => { -// this.removeGraph(name); -// dlg.close(); -// }); -// }); -// $(window).resize(e => { -// $.each(this.charts, (i: number, g: Chart) => { -// g.resize(); -// }); -// }); - -// this.refresh(); -// } - -// refresh() { -// if (!this.timer) { -// this.loadData(); -// if (this.opts.refreshInterval > 0) { -// this.timer = setTimeout(this.refreshData.bind(this), this.opts.refreshInterval * 1000); -// } -// } -// } - -// private refreshData() { -// this.loadData(); -// if (this.opts.refreshInterval > 0) { -// this.timer = setTimeout(this.refreshData.bind(this), this.opts.refreshInterval * 1000); -// } -// } - -// stop() { -// clearTimeout(this.timer); -// this.timer = 0; -// } - -// setPeriod(period: number) { -// this.opts.period = period; -// this.loadData(); -// } - -// addGraph(opts: ChartData) { -// this.createGraph(opts); -// this.loadData(); -// } - -// private createGraph(opts: ChartData) { -// for (let i = 0; i < this.charts.length; i++) { -// let chart = this.charts[i]; -// if (chart.getOptions().name === opts.name) { -// // chart already added. -// return; -// } -// } - -// let chart = ChartFactory.create(opts); -// if (chart != null) { -// this.$panel.append(chart.getElem()); -// chart.init(); -// this.charts.push(chart); -// } -// } - -// removeGraph(name: string) { -// let index = -1; -// for (let i = 0; i < this.charts.length; i++) { -// let c = this.charts[i]; -// if (c.getOptions().name === name) { -// index = i; -// break; -// } -// } - -// if (index >= 0) { -// let $elem = this.charts[index].getElem(); -// this.charts.splice(index, 1); -// $elem.remove(); -// } -// } - -// save(asDefault: boolean = false) { -// let charts: any = []; -// this.$panel.children().each((index: number, elem: Element) => { -// let name = $(elem).data("name"); -// for (let i = 0; i < this.charts.length; i++) { -// let c = this.charts[i]; -// if (c.getOptions().name === name) { -// charts.push({ -// name: c.getOptions().name, -// width: c.getOptions().width, -// height: c.getOptions().height, -// }); -// break; -// } -// } -// }); -// let args = { -// name: this.opts.name, -// key: asDefault ? '' : (this.opts.key || ''), -// charts: charts, -// }; -// $ajax.post(`/system/chart/save_dashboard`, args).json((r: AjaxResult) => { -// if (r.success) { -// Notification.show("success", "Successfully saved."); -// } else { -// Notification.show("danger", r.message); -// } -// }); -// } - -// getOptions(): ChartDashboardOptions { -// return this.opts; -// } - -// private loadData() { -// if (this.charts.length == 0) { -// return -// } - -// let args: any = { -// charts: this.charts.map(c => c.getOptions().name).join(","), -// period: this.opts.period, -// }; -// if (this.opts.key) { -// args.key = this.opts.key; -// } -// $ajax.get(`/system/chart/data`, args).json((d: { [index: string]: any[] }) => { -// $.each(this.charts, (i: number, g: Chart) => { -// if (d[g.getOptions().name]) { -// g.setData(d[g.getOptions().name]); -// } -// }); -// }); -// } -// } - -// class ChartDialog { -// private dashboard: ChartDashboard; -// private fb: FilterBox; -// private charts: any; -// private $charts: JQuery; - -// constructor(dashboard: ChartDashboard) { -// this.dashboard = dashboard; -// this.fb = new FilterBox("#txt-query", this.filterCharts.bind(this)); -// $("#btn-add").click(this.showAddDlg.bind(this)); -// $("#btn-add-chart").click(this.addChart.bind(this)); -// $("#btn-save").click(() => { -// this.dashboard.save(); -// }); -// $("#btn-save-as-default").click(() => { -// this.dashboard.save(true); -// }); -// } - -// private showAddDlg() { -// let $panel = $("#nav-charts"); -// $panel.find("label.panel-block").remove(); - -// // load charts -// $ajax.get(`/system/chart/query`, { dashboard: this.dashboard.getOptions().name }).json((charts: any) => { -// for (let i = 0; i < charts.length; i++) { -// let c = charts[i]; -// $panel.append(``); -// } -// this.charts = charts; -// this.$charts = $panel.find("label.panel-block"); -// }); - -// let dlg = new Modal("#dlg-add-chart"); -// dlg.show(); -// } - -// private filterCharts(text: string) { -// if (!text) { -// this.$charts.show(); -// return; -// } - -// this.$charts.each((i, elem) => { -// let $elem = $(elem); -// let texts: string[] = [ -// this.charts[i].name.toLowerCase(), -// this.charts[i].title.toLowerCase(), -// this.charts[i].desc.toLowerCase(), -// ]; -// for (let i = 0; i < texts.length; i++) { -// let index = texts[i].indexOf(text); -// if (index >= 0) { -// $elem.show(); -// return; -// } -// } -// $elem.hide(); -// }) -// } - -// private addChart() { -// this.$charts.each((i, e) => { -// if ($(e).find(":checked").length > 0) { -// let c = this.charts[i]; -// this.dashboard.addGraph(c); -// } -// }); -// Modal.close(); -// } -// } \ No newline at end of file diff --git a/ui/src/components/tab/TabPane.vue b/ui/src/components/tab/TabPane.vue index 87748b1..0ad26da 100644 --- a/ui/src/components/tab/TabPane.vue +++ b/ui/src/components/tab/TabPane.vue @@ -1,8 +1,8 @@