mirror of
https://github.com/cuigh/swirl
synced 2024-12-28 14:51:57 +00:00
Add edit pages of secret and config
This commit is contained in:
parent
49eaee7cec
commit
605706b235
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -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
|
||||
|
76
views/config/edit.jet
Normal file
76
views/config/edit.jet
Normal file
@ -0,0 +1,76 @@
|
||||
{{ extends "../_layouts/default" }}
|
||||
{{ import "../_modules/form" }}
|
||||
|
||||
{{ block script() }}
|
||||
<script>$(() => new Swirl.Config.NewPage())</script>
|
||||
{{ end }}
|
||||
|
||||
{{ block body() }}
|
||||
<section class="hero is-info">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h1 class="title is-2">
|
||||
CONFIG
|
||||
</h1>
|
||||
<h2 class="subtitle is-5">
|
||||
Configs are non-sensitive information that can be used by services, such as configuration files.
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
<nav class="breadcrumb has-succeeds-separator is-small is-marginless" aria-label="breadcrumbs">
|
||||
<ul>
|
||||
<li><a href="/">Dashboard</a></li>
|
||||
<li><a href="/config/">Configs</a></li>
|
||||
<li class="is-active"><a>Edit</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<section class="hero is-small is-light">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h2 class="title is-2">
|
||||
{{ .Config.Spec.Name }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<nav class="navbar has-shadow">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
{*<a class="navbar-item is-tab" href="/config/{{.Config.ID}}/detail">Detail</a>*}
|
||||
{*<a class="navbar-item is-tab" href="/config/{{.Config.ID}}/raw">Raw</a>*}
|
||||
<a class="navbar-item is-tab is-active" href="/node/{{.Config.ID}}/edit">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<form method="post" action="update" data-form="ajax-json" data-form="ajax-json" data-url="/config/">
|
||||
<input name="id" value="{{ .Config.ID }}" type="hidden">
|
||||
{*<div class="field">*}
|
||||
{*<label class="label">Data</label>*}
|
||||
{*<div class="control">*}
|
||||
{*<textarea name="data" class="textarea" rows="12" placeholder="Config file content" data-v-rule="native" required></textarea>*}
|
||||
{*</div>*}
|
||||
{*</div>*}
|
||||
<div class="field">
|
||||
<label class="label">Labels</label>
|
||||
{{ yield options(name="label", items=.Config.Spec.Labels) }}
|
||||
</div>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button type="submit" class="button is-primary">Submit</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a href="/config/" class="button is-link">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
{{ end }}
|
@ -71,6 +71,7 @@
|
||||
<td>{{time(.CreatedAt)}}</td>
|
||||
<td>{{time(.UpdatedAt)}}</td>
|
||||
<td>
|
||||
<a href="{{.ID}}/edit" class="button is-small is-dark is-outlined">Edit</a>
|
||||
<button class="button is-small is-danger is-outlined" data-action="delete-config">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
70
views/secret/edit.jet
Normal file
70
views/secret/edit.jet
Normal file
@ -0,0 +1,70 @@
|
||||
{{ extends "../_layouts/default" }}
|
||||
{{ import "../_modules/form" }}
|
||||
|
||||
{{ block script() }}
|
||||
<script>$(() => new Swirl.Secret.NewPage())</script>
|
||||
{{ end }}
|
||||
|
||||
{{ block body() }}
|
||||
<section class="hero is-info">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h1 class="title is-2">
|
||||
SECRET
|
||||
</h1>
|
||||
<h2 class="subtitle is-5">
|
||||
Secrets are sensitive data that can be used by services.
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
<nav class="breadcrumb has-succeeds-separator is-small is-marginless" aria-label="breadcrumbs">
|
||||
<ul>
|
||||
<li><a href="/">Dashboard</a></li>
|
||||
<li><a href="/secret/">Secrets</a></li>
|
||||
<li class="is-active"><a>Edit</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<section class="hero is-small is-light">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h2 class="title is-2">
|
||||
{{ .Secret.Spec.Name }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<nav class="navbar has-shadow">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
{*<a class="navbar-item is-tab" href="/secret/{{.Secret.ID}}/detail">Detail</a>*}
|
||||
{*<a class="navbar-item is-tab" href="/secret/{{.Secret.ID}}/raw">Raw</a>*}
|
||||
<a class="navbar-item is-tab is-active" href="/node/{{.Secret.ID}}/edit">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<form method="post" action="update" data-form="ajax-json" data-form="ajax-json" data-url="/secret/">
|
||||
<input name="id" value="{{ .Secret.ID }}" type="hidden">
|
||||
<div class="field">
|
||||
<label class="label">Labels</label>
|
||||
{{ yield options(name="label", items=.Secret.Spec.Labels) }}
|
||||
</div>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<button type="submit" class="button is-primary">Submit</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a href="/secret/" class="button is-link">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
{{ end }}
|
@ -71,6 +71,7 @@
|
||||
<td>{{time(.CreatedAt)}}</td>
|
||||
<td>{{time(.UpdatedAt)}}</td>
|
||||
<td>
|
||||
<a href="{{.ID}}/edit" class="button is-small is-dark is-outlined">Edit</a>
|
||||
<button class="button is-small is-danger is-outlined" data-action="delete-secret">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
Loading…
Reference in New Issue
Block a user