mirror of
https://github.com/cuigh/swirl
synced 2024-12-29 07:12:11 +00:00
Add support for service rollback
This commit is contained in:
parent
39f4f897ab
commit
ac5184037a
@ -1756,7 +1756,9 @@ var Swirl;
|
|||||||
class ListPage {
|
class ListPage {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.table = new Table("#table-items");
|
this.table = new Table("#table-items");
|
||||||
this.table.on("delete-service", this.deleteService.bind(this)).on("scale-service", this.scaleService.bind(this));
|
this.table.on("delete-service", this.deleteService.bind(this))
|
||||||
|
.on("scale-service", this.scaleService.bind(this))
|
||||||
|
.on("rollback-service", this.rollbackService.bind(this));
|
||||||
$("#btn-delete").click(this.deleteServices.bind(this));
|
$("#btn-delete").click(this.deleteServices.bind(this));
|
||||||
}
|
}
|
||||||
deleteService(e) {
|
deleteService(e) {
|
||||||
@ -1796,6 +1798,14 @@ var Swirl;
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
rollbackService(e) {
|
||||||
|
let $btn = $(e.target).closest("button"), $tr = $btn.closest("tr"), name = $tr.find("td:eq(1)").text().trim();
|
||||||
|
Modal.confirm(`Are you sure to rollback service: <strong>${name}</strong>?`, "Rollback service", (dlg, e) => {
|
||||||
|
$ajax.post("rollback", { name: name }).trigger(e.target).encoder("form").json(() => {
|
||||||
|
dlg.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Service.ListPage = ListPage;
|
Service.ListPage = ListPage;
|
||||||
})(Service = Swirl.Service || (Swirl.Service = {}));
|
})(Service = Swirl.Service || (Swirl.Service = {}));
|
||||||
|
File diff suppressed because one or more lines are too long
@ -11,7 +11,9 @@ namespace Swirl.Service {
|
|||||||
this.table = new Table("#table-items");
|
this.table = new Table("#table-items");
|
||||||
|
|
||||||
// bind events
|
// bind events
|
||||||
this.table.on("delete-service", this.deleteService.bind(this)).on("scale-service", this.scaleService.bind(this));
|
this.table.on("delete-service", this.deleteService.bind(this))
|
||||||
|
.on("scale-service", this.scaleService.bind(this))
|
||||||
|
.on("rollback-service", this.rollbackService.bind(this));
|
||||||
$("#btn-delete").click(this.deleteServices.bind(this));
|
$("#btn-delete").click(this.deleteServices.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ namespace Swirl.Service {
|
|||||||
let $tr = $(e.target).closest("tr");
|
let $tr = $(e.target).closest("tr");
|
||||||
let name = $tr.find("td:eq(1)").text().trim();
|
let name = $tr.find("td:eq(1)").text().trim();
|
||||||
Modal.confirm(`Are you sure to remove service: <strong>${name}</strong>?`, "Delete service", (dlg, e) => {
|
Modal.confirm(`Are you sure to remove service: <strong>${name}</strong>?`, "Delete service", (dlg, e) => {
|
||||||
$ajax.post("delete", { names: name }).trigger(e.target).encoder("form").json<AjaxResult>(() => {
|
$ajax.post("delete", {names: name}).trigger(e.target).encoder("form").json<AjaxResult>(() => {
|
||||||
$tr.remove();
|
$tr.remove();
|
||||||
dlg.close();
|
dlg.close();
|
||||||
})
|
})
|
||||||
@ -34,7 +36,7 @@ namespace Swirl.Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Modal.confirm(`Are you sure to remove ${names.length} services?`, "Delete services", (dlg, e) => {
|
Modal.confirm(`Are you sure to remove ${names.length} services?`, "Delete services", (dlg, e) => {
|
||||||
$ajax.post("delete", { names: names.join(",") }).trigger(e.target).encoder("form").json<AjaxResult>(() => {
|
$ajax.post("delete", {names: names.join(",")}).trigger(e.target).encoder("form").json<AjaxResult>(() => {
|
||||||
this.table.selectedRows().remove();
|
this.table.selectedRows().remove();
|
||||||
dlg.close();
|
dlg.close();
|
||||||
})
|
})
|
||||||
@ -55,5 +57,16 @@ namespace Swirl.Service {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private rollbackService(e: JQueryEventObject) {
|
||||||
|
let $btn = $(e.target).closest("button"),
|
||||||
|
$tr = $btn.closest("tr"),
|
||||||
|
name = $tr.find("td:eq(1)").text().trim();
|
||||||
|
Modal.confirm(`Are you sure to rollback service: <strong>${name}</strong>?`, "Rollback service", (dlg, e) => {
|
||||||
|
$ajax.post("rollback", {name: name}).trigger(e.target).encoder("form").json<AjaxResult>(() => {
|
||||||
|
dlg.close();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -697,3 +697,28 @@ func ServiceCommand(name string) (cmd string, err error) {
|
|||||||
cmd = b.String()
|
cmd = b.String()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServiceRollback rollbacks a service.
|
||||||
|
func ServiceRollback(name string) error {
|
||||||
|
return mgr.Do(func(ctx context.Context, cli *client.Client) (err error) {
|
||||||
|
service, _, err := cli.ServiceInspectWithRaw(ctx, name, types.ServiceInspectOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if service.PreviousSpec == nil {
|
||||||
|
return errors.New("can't rollback service, previous spec is not exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
spec := *service.PreviousSpec
|
||||||
|
options := types.ServiceUpdateOptions{
|
||||||
|
RegistryAuthFrom: types.RegistryAuthFromPreviousSpec,
|
||||||
|
QueryRegistry: false,
|
||||||
|
}
|
||||||
|
resp, err := cli.ServiceUpdate(context.Background(), name, service.Version, spec, options)
|
||||||
|
if err == nil && len(resp.Warnings) > 0 {
|
||||||
|
mgr.Logger().Warnf("service %s was rollbacked but got warnings: %v", name, resp.Warnings)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ button.update: Update
|
|||||||
button.return: Return
|
button.return: Return
|
||||||
button.leave: Leave
|
button.leave: Leave
|
||||||
button.scale: Scale
|
button.scale: Scale
|
||||||
|
button.rollback: Rollback
|
||||||
button.previous: Previous
|
button.previous: Previous
|
||||||
button.next: Next
|
button.next: Next
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ button.update: 更新
|
|||||||
button.return: 返回
|
button.return: 返回
|
||||||
button.leave: 离开
|
button.leave: 离开
|
||||||
button.scale: 调整
|
button.scale: 调整
|
||||||
|
button.rollback: 回退
|
||||||
button.previous: 前一页
|
button.previous: 前一页
|
||||||
button.next: 后一页
|
button.next: 后一页
|
||||||
|
|
||||||
|
@ -17,31 +17,33 @@ import (
|
|||||||
|
|
||||||
// ServiceController is a controller of docker service
|
// ServiceController is a controller of docker service
|
||||||
type ServiceController struct {
|
type ServiceController struct {
|
||||||
List web.HandlerFunc `path:"/" name:"service.list" authorize:"!" desc:"service list page"`
|
List web.HandlerFunc `path:"/" name:"service.list" authorize:"!" desc:"service list page"`
|
||||||
Detail web.HandlerFunc `path:"/:name/detail" name:"service.detail" authorize:"!" desc:"service detail page"`
|
Detail web.HandlerFunc `path:"/:name/detail" name:"service.detail" authorize:"!" desc:"service detail page"`
|
||||||
Raw web.HandlerFunc `path:"/:name/raw" name:"service.raw" authorize:"!" desc:"service raw page"`
|
Raw web.HandlerFunc `path:"/:name/raw" name:"service.raw" authorize:"!" desc:"service raw page"`
|
||||||
Logs web.HandlerFunc `path:"/:name/logs" name:"service.logs" authorize:"!" desc:"service logs page"`
|
Logs web.HandlerFunc `path:"/:name/logs" name:"service.logs" authorize:"!" desc:"service logs page"`
|
||||||
Delete web.HandlerFunc `path:"/delete" method:"post" name:"service.delete" authorize:"!" desc:"delete service"`
|
Delete web.HandlerFunc `path:"/delete" method:"post" name:"service.delete" authorize:"!" desc:"delete service"`
|
||||||
Scale web.HandlerFunc `path:"/scale" method:"post" name:"service.scale" authorize:"!" desc:"scale service"`
|
Scale web.HandlerFunc `path:"/scale" method:"post" name:"service.scale" authorize:"!" desc:"scale service"`
|
||||||
New web.HandlerFunc `path:"/new" name:"service.new" authorize:"!" desc:"new service page"`
|
Rollback web.HandlerFunc `path:"/rollback" method:"post" name:"service.rollback" authorize:"!" desc:"rollback service"`
|
||||||
Create web.HandlerFunc `path:"/new" method:"post" name:"service.create" authorize:"!" desc:"create service"`
|
New web.HandlerFunc `path:"/new" name:"service.new" authorize:"!" desc:"new service page"`
|
||||||
Edit web.HandlerFunc `path:"/:name/edit" name:"service.edit" authorize:"!" desc:"service edit page"`
|
Create web.HandlerFunc `path:"/new" method:"post" name:"service.create" authorize:"!" desc:"create service"`
|
||||||
Update web.HandlerFunc `path:"/:name/edit" method:"post" name:"service.update" authorize:"!" desc:"update service"`
|
Edit web.HandlerFunc `path:"/:name/edit" name:"service.edit" authorize:"!" desc:"service edit page"`
|
||||||
|
Update web.HandlerFunc `path:"/:name/edit" method:"post" name:"service.update" authorize:"!" desc:"update service"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service creates an instance of ServiceController
|
// Service creates an instance of ServiceController
|
||||||
func Service() (c *ServiceController) {
|
func Service() (c *ServiceController) {
|
||||||
return &ServiceController{
|
return &ServiceController{
|
||||||
List: serviceList,
|
List: serviceList,
|
||||||
Detail: serviceDetail,
|
Detail: serviceDetail,
|
||||||
Raw: serviceRaw,
|
Raw: serviceRaw,
|
||||||
Logs: serviceLogs,
|
Logs: serviceLogs,
|
||||||
Delete: serviceDelete,
|
Delete: serviceDelete,
|
||||||
New: serviceNew,
|
New: serviceNew,
|
||||||
Create: serviceCreate,
|
Create: serviceCreate,
|
||||||
Edit: serviceEdit,
|
Edit: serviceEdit,
|
||||||
Update: serviceUpdate,
|
Update: serviceUpdate,
|
||||||
Scale: serviceScale,
|
Scale: serviceScale,
|
||||||
|
Rollback: serviceRollback,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,3 +265,12 @@ func serviceScale(ctx web.Context) error {
|
|||||||
}
|
}
|
||||||
return ajaxResult(ctx, err)
|
return ajaxResult(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func serviceRollback(ctx web.Context) error {
|
||||||
|
name := ctx.F("name")
|
||||||
|
err := docker.ServiceRollback(name)
|
||||||
|
if err == nil {
|
||||||
|
biz.Event.CreateService(model.EventActionRollback, name, ctx.User())
|
||||||
|
}
|
||||||
|
return ajaxResult(ctx, err)
|
||||||
|
}
|
||||||
|
@ -56,6 +56,7 @@ var Perms = []PermGroup{
|
|||||||
{Key: "service.delete", Text: "Delete"},
|
{Key: "service.delete", Text: "Delete"},
|
||||||
{Key: "service.update", Text: "Update"},
|
{Key: "service.update", Text: "Update"},
|
||||||
{Key: "service.scale", Text: "Scale"},
|
{Key: "service.scale", Text: "Scale"},
|
||||||
|
{Key: "service.rollback", Text: "Rollback"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -86,6 +86,7 @@ type ServiceListInfo struct {
|
|||||||
Actives uint64
|
Actives uint64
|
||||||
Replicas uint64
|
Replicas uint64
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
|
Rollback bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceListInfo(service swarm.Service, actives uint64) *ServiceListInfo {
|
func NewServiceListInfo(service swarm.Service, actives uint64) *ServiceListInfo {
|
||||||
@ -94,6 +95,7 @@ func NewServiceListInfo(service swarm.Service, actives uint64) *ServiceListInfo
|
|||||||
Image: normalizeImage(service.Spec.TaskTemplate.ContainerSpec.Image),
|
Image: normalizeImage(service.Spec.TaskTemplate.ContainerSpec.Image),
|
||||||
Actives: actives,
|
Actives: actives,
|
||||||
UpdatedAt: service.UpdatedAt.Local(),
|
UpdatedAt: service.UpdatedAt.Local(),
|
||||||
|
Rollback: service.PreviousSpec != nil,
|
||||||
}
|
}
|
||||||
if service.Spec.Mode.Replicated != nil && service.Spec.Mode.Replicated.Replicas != nil {
|
if service.Spec.Mode.Replicated != nil && service.Spec.Mode.Replicated.Replicas != nil {
|
||||||
info.Mode = "replicated"
|
info.Mode = "replicated"
|
||||||
|
@ -38,6 +38,7 @@ const (
|
|||||||
EventActionDelete EventAction = "Delete"
|
EventActionDelete EventAction = "Delete"
|
||||||
EventActionUpdate EventAction = "Update"
|
EventActionUpdate EventAction = "Update"
|
||||||
EventActionScale EventAction = "Scale"
|
EventActionScale EventAction = "Scale"
|
||||||
|
EventActionRollback EventAction = "Rollback"
|
||||||
EventActionDisconnect EventAction = "Disconnect"
|
EventActionDisconnect EventAction = "Disconnect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
<th>{{ i18n("field.image") }}</th>
|
<th>{{ i18n("field.image") }}</th>
|
||||||
<th width="145">Mode</th>
|
<th width="145">Mode</th>
|
||||||
<th>{{ i18n("field.updated-at") }}</th>
|
<th>{{ i18n("field.updated-at") }}</th>
|
||||||
<th width="110">{{ i18n("field.action") }}</th>
|
<th width="140">{{ i18n("field.action") }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -73,6 +73,11 @@
|
|||||||
<span class="icon"><i class="fa fa-arrows"></i></span>
|
<span class="icon"><i class="fa fa-arrows"></i></span>
|
||||||
</button>
|
</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if .Rollback }}
|
||||||
|
<button type="button" class="button is-small is-info is-outlined tooltip is-tooltip-bottom" data-tooltip="{{ i18n("button.rollback") }}" data-action="rollback-service">
|
||||||
|
<span class="icon"><i class="fa fa-history"></i></span>
|
||||||
|
</button>
|
||||||
|
{{end}}
|
||||||
<button class="button is-small is-danger is-outlined tooltip is-tooltip-bottom" data-tooltip="{{ i18n("button.delete") }}" data-action="delete-service">
|
<button class="button is-small is-danger is-outlined tooltip is-tooltip-bottom" data-tooltip="{{ i18n("button.delete") }}" data-action="delete-service">
|
||||||
<span class="icon"><i class="fa fa-remove"></i></span>
|
<span class="icon"><i class="fa fa-remove"></i></span>
|
||||||
</button>
|
</button>
|
||||||
|
Loading…
Reference in New Issue
Block a user