Add support for service rollback

This commit is contained in:
cuigh 2017-10-26 16:16:51 +08:00
parent 39f4f897ab
commit ac5184037a
11 changed files with 96 additions and 26 deletions

View File

@ -1756,7 +1756,9 @@ var Swirl;
class ListPage {
constructor() {
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));
}
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 = Swirl.Service || (Swirl.Service = {}));

File diff suppressed because one or more lines are too long

View File

@ -11,7 +11,9 @@ namespace Swirl.Service {
this.table = new Table("#table-items");
// 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));
}
@ -19,7 +21,7 @@ namespace Swirl.Service {
let $tr = $(e.target).closest("tr");
let name = $tr.find("td:eq(1)").text().trim();
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();
dlg.close();
})
@ -34,7 +36,7 @@ namespace Swirl.Service {
}
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();
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();
})
});
}
}
}

View File

@ -697,3 +697,28 @@ func ServiceCommand(name string) (cmd string, err error) {
cmd = b.String()
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
})
}

View File

@ -18,6 +18,7 @@ button.update: Update
button.return: Return
button.leave: Leave
button.scale: Scale
button.rollback: Rollback
button.previous: Previous
button.next: Next

View File

@ -18,6 +18,7 @@ button.update: 更新
button.return: 返回
button.leave: 离开
button.scale: 调整
button.rollback: 回退
button.previous: 前一页
button.next: 后一页

View File

@ -17,31 +17,33 @@ import (
// ServiceController is a controller of docker service
type ServiceController struct {
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"`
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"`
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"`
New web.HandlerFunc `path:"/new" name:"service.new" authorize:"!" desc:"new service page"`
Create web.HandlerFunc `path:"/new" method:"post" name:"service.create" authorize:"!" desc:"create 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"`
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"`
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"`
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"`
Rollback web.HandlerFunc `path:"/rollback" method:"post" name:"service.rollback" authorize:"!" desc:"rollback service"`
New web.HandlerFunc `path:"/new" name:"service.new" authorize:"!" desc:"new service page"`
Create web.HandlerFunc `path:"/new" method:"post" name:"service.create" authorize:"!" desc:"create 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
func Service() (c *ServiceController) {
return &ServiceController{
List: serviceList,
Detail: serviceDetail,
Raw: serviceRaw,
Logs: serviceLogs,
Delete: serviceDelete,
New: serviceNew,
Create: serviceCreate,
Edit: serviceEdit,
Update: serviceUpdate,
Scale: serviceScale,
List: serviceList,
Detail: serviceDetail,
Raw: serviceRaw,
Logs: serviceLogs,
Delete: serviceDelete,
New: serviceNew,
Create: serviceCreate,
Edit: serviceEdit,
Update: serviceUpdate,
Scale: serviceScale,
Rollback: serviceRollback,
}
}
@ -263,3 +265,12 @@ func serviceScale(ctx web.Context) error {
}
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)
}

View File

@ -56,6 +56,7 @@ var Perms = []PermGroup{
{Key: "service.delete", Text: "Delete"},
{Key: "service.update", Text: "Update"},
{Key: "service.scale", Text: "Scale"},
{Key: "service.rollback", Text: "Rollback"},
},
},
{

View File

@ -86,6 +86,7 @@ type ServiceListInfo struct {
Actives uint64
Replicas uint64
UpdatedAt time.Time
Rollback bool
}
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),
Actives: actives,
UpdatedAt: service.UpdatedAt.Local(),
Rollback: service.PreviousSpec != nil,
}
if service.Spec.Mode.Replicated != nil && service.Spec.Mode.Replicated.Replicas != nil {
info.Mode = "replicated"

View File

@ -38,6 +38,7 @@ const (
EventActionDelete EventAction = "Delete"
EventActionUpdate EventAction = "Update"
EventActionScale EventAction = "Scale"
EventActionRollback EventAction = "Rollback"
EventActionDisconnect EventAction = "Disconnect"
)

View File

@ -48,7 +48,7 @@
<th>{{ i18n("field.image") }}</th>
<th width="145">Mode</th>
<th>{{ i18n("field.updated-at") }}</th>
<th width="110">{{ i18n("field.action") }}</th>
<th width="140">{{ i18n("field.action") }}</th>
</tr>
</thead>
<tbody>
@ -73,6 +73,11 @@
<span class="icon"><i class="fa fa-arrows"></i></span>
</button>
{{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">
<span class="icon"><i class="fa fa-remove"></i></span>
</button>