diff --git a/biz/docker/config.go b/biz/docker/config.go index 6bf0b39..74549c8 100644 --- a/biz/docker/config.go +++ b/biz/docker/config.go @@ -5,6 +5,7 @@ import ( "sort" "github.com/cuigh/swirl/misc" + "github.com/cuigh/swirl/model" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/swarm" @@ -34,18 +35,47 @@ func ConfigList(name string, pageIndex, pageSize int) (configs []swarm.Config, t } // ConfigCreate create a config. -func ConfigCreate(name string, data []byte, labels map[string]string) error { +func ConfigCreate(info *model.ConfigCreateInfo) error { return mgr.Do(func(ctx context.Context, cli *client.Client) (err error) { - // todo: spec := swarm.ConfigSpec{} - spec.Name = name - spec.Data = data - spec.Labels = labels + spec.Name = info.Name + spec.Data = []byte(info.Data) + spec.Labels = info.Labels.ToMap() _, err = cli.ConfigCreate(ctx, spec) return }) } +// ConfigUpdate update a config. +func ConfigUpdate(info *model.ConfigUpdateInfo) error { + return mgr.Do(func(ctx context.Context, cli *client.Client) (err error) { + var cfg swarm.Config + cfg, _, err = cli.ConfigInspectWithRaw(ctx, info.ID) + if err != nil { + return err + } + + spec := cfg.Spec + // only the Labels field can be updated on API 1.30 + //spec.Name = info.Name + //spec.Data = []byte(info.Data) + spec.Labels = info.Labels.ToMap() + return cli.ConfigUpdate(ctx, info.ID, cfg.Version, spec) + }) +} + +// ConfigInspect returns config information with raw data. +func ConfigInspect(id string) (cfg swarm.Config, raw []byte, err error) { + var ( + ctx context.Context + cli *client.Client + ) + if ctx, cli, err = mgr.Client(); err == nil { + cfg, raw, err = cli.ConfigInspectWithRaw(ctx, id) + } + return +} + // ConfigRemove remove a config. func ConfigRemove(ids []string) error { return mgr.Do(func(ctx context.Context, cli *client.Client) (err error) { diff --git a/biz/docker/secret.go b/biz/docker/secret.go index 9022230..9ff85ae 100644 --- a/biz/docker/secret.go +++ b/biz/docker/secret.go @@ -4,11 +4,12 @@ import ( "context" "sort" + "github.com/cuigh/swirl/misc" + "github.com/cuigh/swirl/model" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" - "github.com/cuigh/swirl/misc" ) // SecretList return all secrets. @@ -34,18 +35,47 @@ func SecretList(name string, pageIndex, pageSize int) (secrets []swarm.Secret, t } // SecretCreate create a secret. -func SecretCreate(name string, data []byte, labels map[string]string) error { +func SecretCreate(info *model.ConfigCreateInfo) error { return mgr.Do(func(ctx context.Context, cli *client.Client) (err error) { - // todo: spec := swarm.SecretSpec{} - spec.Name = name - spec.Data = data - spec.Labels = labels + spec.Name = info.Name + spec.Data = []byte(info.Data) + spec.Labels = info.Labels.ToMap() _, err = cli.SecretCreate(ctx, spec) return }) } +// SecretUpdate update a config. +func SecretUpdate(info *model.ConfigUpdateInfo) error { + return mgr.Do(func(ctx context.Context, cli *client.Client) (err error) { + var secret swarm.Secret + secret, _, err = cli.SecretInspectWithRaw(ctx, info.ID) + if err != nil { + return err + } + + spec := secret.Spec + // only the Labels field can be updated on API 1.30 + //spec.Name = info.Name + //spec.Data = []byte(info.Data) + spec.Labels = info.Labels.ToMap() + return cli.SecretUpdate(ctx, info.ID, secret.Version, spec) + }) +} + +// SecretInspect returns secret information with raw data. +func SecretInspect(id string) (secret swarm.Secret, raw []byte, err error) { + var ( + ctx context.Context + cli *client.Client + ) + if ctx, cli, err = mgr.Client(); err == nil { + secret, raw, err = cli.SecretInspectWithRaw(ctx, id) + } + return +} + // SecretRemove remove a secret. func SecretRemove(id string) error { return mgr.Do(func(ctx context.Context, cli *client.Client) (err error) { diff --git a/controller/config.go b/controller/config.go index e7ca659..26e4bb3 100644 --- a/controller/config.go +++ b/controller/config.go @@ -5,6 +5,7 @@ import ( "github.com/cuigh/auxo/net/web" "github.com/cuigh/auxo/util/cast" + "github.com/cuigh/swirl/biz" "github.com/cuigh/swirl/biz/docker" "github.com/cuigh/swirl/model" ) @@ -14,6 +15,8 @@ type ConfigController struct { Delete web.HandlerFunc `path:"/delete" method:"post" name:"config.delete" authorize:"!" desc:"delete config"` New web.HandlerFunc `path:"/new" name:"config.new" authorize:"!" desc:"new config page"` Create web.HandlerFunc `path:"/new" method:"post" name:"config.create" authorize:"!" desc:"create config"` + Edit web.HandlerFunc `path:"/:id/edit" name:"config.edit" authorize:"!" desc:"edit config page"` + Update web.HandlerFunc `path:"/:id/update" method:"post" name:"config.update" authorize:"!" desc:"update config"` } func Config() (c *ConfigController) { @@ -45,23 +48,35 @@ func Config() (c *ConfigController) { } c.Create = func(ctx web.Context) error { - v := struct { - Name string `json:"name"` - Data string `json:"data"` - Labels []struct { - Name string `json:"name"` - Value string `json:"value"` - } `json:"labels"` - }{} - err := ctx.Bind(&v) + v := &model.ConfigCreateInfo{} + err := ctx.Bind(v) if err == nil { - labels := make(map[string]string) - for _, l := range v.Labels { - if l.Name != "" && l.Value != "" { - labels[l.Name] = l.Value - } + err = docker.ConfigCreate(v) + if err == nil { + biz.Event.CreateConfig(model.EventActionCreate, v.Name, ctx.User()) + } + } + return ajaxResult(ctx, err) + } + + c.Edit = func(ctx web.Context) error { + id := ctx.P("id") + cfg, _, err := docker.ConfigInspect(id) + if err != nil { + return err + } + m := newModel(ctx).Add("Config", cfg) + return ctx.Render("config/edit", m) + } + + c.Update = func(ctx web.Context) error { + v := &model.ConfigUpdateInfo{} + err := ctx.Bind(v) + if err == nil { + err = docker.ConfigUpdate(v) + if err == nil { + biz.Event.CreateConfig(model.EventActionUpdate, v.Name, ctx.User()) } - err = docker.ConfigCreate(v.Name, []byte(v.Data), labels) } return ajaxResult(ctx, err) } diff --git a/controller/secret.go b/controller/secret.go index b6120d4..1d5f225 100644 --- a/controller/secret.go +++ b/controller/secret.go @@ -15,6 +15,8 @@ type SecretController struct { Delete web.HandlerFunc `path:"/delete" method:"post" name:"secret.delete" authorize:"!" desc:"delete secret"` New web.HandlerFunc `path:"/new" name:"secret.new" authorize:"!" desc:"new secret page"` Create web.HandlerFunc `path:"/new" method:"post" name:"secret.create" authorize:"!" desc:"create secret"` + Edit web.HandlerFunc `path:"/:id/edit" name:"secret.edit" authorize:"!" desc:"edit secret page"` + Update web.HandlerFunc `path:"/:id/update" method:"post" name:"secret.update" authorize:"!" desc:"update secret"` } func Secret() (c *SecretController) { @@ -54,23 +56,10 @@ func Secret() (c *SecretController) { } c.Create = func(ctx web.Context) error { - v := struct { - Name string `json:"name"` - Data string `json:"data"` - Labels []struct { - Name string `json:"name"` - Value string `json:"value"` - } `json:"labels"` - }{} - err := ctx.Bind(&v) + v := &model.ConfigCreateInfo{} + err := ctx.Bind(v) if err == nil { - labels := make(map[string]string) - for _, l := range v.Labels { - if l.Name != "" && l.Value != "" { - labels[l.Name] = l.Value - } - } - err = docker.SecretCreate(v.Name, []byte(v.Data), labels) + err = docker.SecretCreate(v) if err == nil { biz.Event.CreateSecret(model.EventActionCreate, v.Name, ctx.User()) } @@ -78,5 +67,27 @@ func Secret() (c *SecretController) { return ajaxResult(ctx, err) } + c.Edit = func(ctx web.Context) error { + id := ctx.P("id") + secret, _, err := docker.SecretInspect(id) + if err != nil { + return err + } + m := newModel(ctx).Add("Secret", secret) + return ctx.Render("secret/edit", m) + } + + c.Update = func(ctx web.Context) error { + v := &model.ConfigUpdateInfo{} + err := ctx.Bind(v) + if err == nil { + err = docker.SecretUpdate(v) + if err == nil { + biz.Event.CreateSecret(model.EventActionUpdate, v.Name, ctx.User()) + } + } + return ajaxResult(ctx, err) + } + return } diff --git a/misc/perm.go b/misc/perm.go index 89c044d..9ec14e7 100644 --- a/misc/perm.go +++ b/misc/perm.go @@ -104,8 +104,10 @@ var Perms = []PermGroup{ Perms: []Perm{ {Key: "secret.list", Text: "View list"}, {Key: "secret.new", Text: "View new"}, + {Key: "secret.edit", Text: "View edit"}, {Key: "secret.create", Text: "Create"}, {Key: "secret.delete", Text: "Delete"}, + {Key: "secret.update", Text: "Update"}, }, }, { @@ -113,8 +115,10 @@ var Perms = []PermGroup{ Perms: []Perm{ {Key: "config.list", Text: "View list"}, {Key: "config.new", Text: "View new"}, + {Key: "config.edit", Text: "View edit"}, {Key: "config.create", Text: "Create"}, {Key: "config.delete", Text: "Delete"}, + {Key: "config.update", Text: "Update"}, }, }, { diff --git a/model/docker.go b/model/docker.go index 3640bf6..2325445 100644 --- a/model/docker.go +++ b/model/docker.go @@ -3,11 +3,11 @@ package model import ( "encoding/base64" "encoding/json" + "fmt" + "os" + "strconv" "strings" "time" - "fmt" - "strconv" - "os" "github.com/cuigh/auxo/data/size" "github.com/docker/docker/api/types" @@ -466,6 +466,17 @@ func (pc *PlacementConstraint) ToConstraint() string { return "" } +type ConfigCreateInfo struct { + Name string `json:"name"` + Data string `json:"data"` + Labels Options `json:"labels"` +} + +type ConfigUpdateInfo struct { + ID string `json:"id"` + ConfigCreateInfo +} + type TaskInfo struct { swarm.Task NodeName string diff --git a/views/config/edit.jet b/views/config/edit.jet new file mode 100644 index 0000000..21fb244 --- /dev/null +++ b/views/config/edit.jet @@ -0,0 +1,76 @@ +{{ extends "../_layouts/default" }} +{{ import "../_modules/form" }} + +{{ block script() }} + +{{ end }} + +{{ block body() }} +
+
+
+

+ CONFIG +

+

+ Configs are non-sensitive information that can be used by services, such as configuration files. +

+
+
+
+ +
+ +
+
+
+
+

+ {{ .Config.Spec.Name }} +

+
+
+
+ + + +
+
+
+ + {*
*} + {**} + {*
*} + {**} + {*
*} + {*
*} +
+ + {{ yield options(name="label", items=.Config.Spec.Labels) }} +
+
+
+ +
+
+ Cancel +
+
+
+
+
+{{ end }} \ No newline at end of file diff --git a/views/config/list.jet b/views/config/list.jet index 58d85cb..264023b 100644 --- a/views/config/list.jet +++ b/views/config/list.jet @@ -71,6 +71,7 @@ {{time(.CreatedAt)}} {{time(.UpdatedAt)}} + Edit diff --git a/views/secret/edit.jet b/views/secret/edit.jet new file mode 100644 index 0000000..652fe5d --- /dev/null +++ b/views/secret/edit.jet @@ -0,0 +1,70 @@ +{{ extends "../_layouts/default" }} +{{ import "../_modules/form" }} + +{{ block script() }} + +{{ end }} + +{{ block body() }} +
+
+
+

+ SECRET +

+

+ Secrets are sensitive data that can be used by services. +

+
+
+
+ +
+ +
+
+
+
+

+ {{ .Secret.Spec.Name }} +

+
+
+
+ + + +
+
+
+ +
+ + {{ yield options(name="label", items=.Secret.Spec.Labels) }} +
+
+
+ +
+
+ Cancel +
+
+
+
+
+{{ end }} \ No newline at end of file diff --git a/views/secret/list.jet b/views/secret/list.jet index 1c3fe4c..cfc9d2b 100644 --- a/views/secret/list.jet +++ b/views/secret/list.jet @@ -71,6 +71,7 @@ {{time(.CreatedAt)}} {{time(.UpdatedAt)}} + Edit