mirror of
https://github.com/cuigh/swirl
synced 2025-01-01 00:32:09 +00:00
Add ‘Template’ option to configs and secrets
This commit is contained in:
parent
4266fcd296
commit
6e5a27b66d
@ -41,6 +41,12 @@ func ConfigCreate(info *model.ConfigCreateInfo) error {
|
|||||||
spec.Name = info.Name
|
spec.Name = info.Name
|
||||||
spec.Data = []byte(info.Data)
|
spec.Data = []byte(info.Data)
|
||||||
spec.Labels = info.Labels.ToMap()
|
spec.Labels = info.Labels.ToMap()
|
||||||
|
if info.Template.Name != "" {
|
||||||
|
spec.Templating = &swarm.Driver{
|
||||||
|
Name: info.Template.Name,
|
||||||
|
Options: info.Template.Options,
|
||||||
|
}
|
||||||
|
}
|
||||||
_, err = cli.ConfigCreate(ctx, spec)
|
_, err = cli.ConfigCreate(ctx, spec)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
apiVersion = "1.32"
|
defaultAPIVersion = "1.32"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mgr = &manager{}
|
var mgr = &manager{}
|
||||||
@ -37,11 +37,15 @@ func (m *manager) Client() (ctx context.Context, cli *client.Client, err error)
|
|||||||
defer m.locker.Unlock()
|
defer m.locker.Unlock()
|
||||||
|
|
||||||
if m.client == nil {
|
if m.client == nil {
|
||||||
|
apiVersion := misc.Options.DockerAPIVersion
|
||||||
|
if apiVersion == "" {
|
||||||
|
apiVersion = defaultAPIVersion
|
||||||
|
}
|
||||||
if misc.Options.DockerEndpoint == "" {
|
if misc.Options.DockerEndpoint == "" {
|
||||||
os.Setenv("DOCKER_API_VERSION", apiVersion)
|
os.Setenv("DOCKER_API_VERSION", apiVersion)
|
||||||
m.client, err = client.NewEnvClient()
|
m.client, err = client.NewClientWithOpts(client.FromEnv)
|
||||||
} else {
|
} else {
|
||||||
m.client, err = client.NewClient(misc.Options.DockerEndpoint, apiVersion, nil, nil)
|
m.client, err = client.NewClientWithOpts(client.WithHost(misc.Options.DockerEndpoint), client.WithVersion(apiVersion))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -41,6 +41,12 @@ func SecretCreate(info *model.ConfigCreateInfo) error {
|
|||||||
spec.Name = info.Name
|
spec.Name = info.Name
|
||||||
spec.Data = []byte(info.Data)
|
spec.Data = []byte(info.Data)
|
||||||
spec.Labels = info.Labels.ToMap()
|
spec.Labels = info.Labels.ToMap()
|
||||||
|
if info.Template.Name != "" {
|
||||||
|
spec.Templating = &swarm.Driver{
|
||||||
|
Name: info.Template.Name,
|
||||||
|
Options: info.Template.Options,
|
||||||
|
}
|
||||||
|
}
|
||||||
_, err = cli.SecretCreate(ctx, spec)
|
_, err = cli.SecretCreate(ctx, spec)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
@ -34,6 +34,7 @@ field.login-name: Login name
|
|||||||
field.password: Password
|
field.password: Password
|
||||||
field.id: ID
|
field.id: ID
|
||||||
field.tag: Tags
|
field.tag: Tags
|
||||||
|
field.label: Labels
|
||||||
field.size: Size
|
field.size: Size
|
||||||
field.created-at: Created at
|
field.created-at: Created at
|
||||||
field.created-by: Created by
|
field.created-by: Created by
|
||||||
@ -57,6 +58,8 @@ field.title: Title
|
|||||||
field.legend: Legend
|
field.legend: Legend
|
||||||
field.desc: Description
|
field.desc: Description
|
||||||
field.dashboard: Dashboard
|
field.dashboard: Dashboard
|
||||||
|
field.data: Data
|
||||||
|
field.template: Template
|
||||||
|
|
||||||
# menu
|
# menu
|
||||||
menu.home: Home
|
menu.home: Home
|
||||||
|
@ -34,6 +34,7 @@ field.login-name: 登录名称
|
|||||||
field.password: 密码
|
field.password: 密码
|
||||||
field.id: ID
|
field.id: ID
|
||||||
field.tag: 标签
|
field.tag: 标签
|
||||||
|
field.label: 标签
|
||||||
field.size: 大小
|
field.size: 大小
|
||||||
field.created-at: 创建时间
|
field.created-at: 创建时间
|
||||||
field.created-by: 创建人
|
field.created-by: 创建人
|
||||||
@ -57,6 +58,8 @@ field.title: 标题
|
|||||||
field.legend: 图例
|
field.legend: 图例
|
||||||
field.desc: 描述
|
field.desc: 描述
|
||||||
field.dashboard: 仪表盘
|
field.dashboard: 仪表盘
|
||||||
|
field.data: 数据
|
||||||
|
field.template: 模板
|
||||||
|
|
||||||
# menu
|
# menu
|
||||||
menu.home: 首页
|
menu.home: 首页
|
||||||
|
@ -8,10 +8,12 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
keyDockerEndpoint = "swirl.docker_endpoint"
|
keyDockerEndpoint = "swirl.docker_endpoint"
|
||||||
|
keyDockerAPIVersion = "swirl.docker_api_version"
|
||||||
keyDBType = "swirl.db_type"
|
keyDBType = "swirl.db_type"
|
||||||
keyDBAddress = "swirl.db_address"
|
keyDBAddress = "swirl.db_address"
|
||||||
keyAuthTimeout = "swirl.auth_timeout"
|
keyAuthTimeout = "swirl.auth_timeout"
|
||||||
envDockerEndpoint = "DOCKER_ENDPOINT"
|
envDockerEndpoint = "DOCKER_ENDPOINT"
|
||||||
|
envDockerAPIVersion = "DOCKER_API_VERSION"
|
||||||
envDBType = "DB_TYPE"
|
envDBType = "DB_TYPE"
|
||||||
envDBAddress = "DB_ADDRESS"
|
envDBAddress = "DB_ADDRESS"
|
||||||
envAuthTimeout = "AUTH_TIMEOUT"
|
envAuthTimeout = "AUTH_TIMEOUT"
|
||||||
@ -52,6 +54,7 @@ var TimeZones = []struct {
|
|||||||
// Options holds custom options of swirl.
|
// Options holds custom options of swirl.
|
||||||
var Options = &struct {
|
var Options = &struct {
|
||||||
DockerEndpoint string
|
DockerEndpoint string
|
||||||
|
DockerAPIVersion string
|
||||||
DBType string
|
DBType string
|
||||||
DBAddress string
|
DBAddress string
|
||||||
AuthTimeout time.Duration
|
AuthTimeout time.Duration
|
||||||
@ -64,6 +67,7 @@ var Options = &struct {
|
|||||||
// BindOptions binds options to environment variables.
|
// BindOptions binds options to environment variables.
|
||||||
func BindOptions() {
|
func BindOptions() {
|
||||||
config.BindEnv(keyDockerEndpoint, envDockerEndpoint)
|
config.BindEnv(keyDockerEndpoint, envDockerEndpoint)
|
||||||
|
config.BindEnv(keyDockerAPIVersion, envDockerAPIVersion)
|
||||||
config.BindEnv(keyDBType, envDBType)
|
config.BindEnv(keyDBType, envDBType)
|
||||||
config.BindEnv(keyDBAddress, envDBAddress)
|
config.BindEnv(keyDBAddress, envDBAddress)
|
||||||
config.BindEnv(keyAuthTimeout, envAuthTimeout)
|
config.BindEnv(keyAuthTimeout, envAuthTimeout)
|
||||||
|
@ -553,10 +553,16 @@ func (pc *PlacementConstraint) ToConstraint() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Driver struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Options map[string]string `json:"options,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type ConfigCreateInfo struct {
|
type ConfigCreateInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
Labels Options `json:"labels"`
|
Labels Options `json:"labels"`
|
||||||
|
Template Driver `json:"template"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigUpdateInfo struct {
|
type ConfigUpdateInfo struct {
|
||||||
|
@ -50,16 +50,29 @@
|
|||||||
<input name="id" value="{{ .Config.ID }}" type="hidden">
|
<input name="id" value="{{ .Config.ID }}" type="hidden">
|
||||||
<input name="version" value="{{ .Config.Version.Index }}" data-type="integer" type="hidden">
|
<input name="version" value="{{ .Config.Version.Index }}" data-type="integer" type="hidden">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Data</label>
|
<label class="label">{{ i18n("field.data") }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<textarea class="textarea" rows="12" readonly>{{ .Config.Spec.Data }}</textarea>
|
<textarea class="textarea" rows="12" readonly>{{ .Config.Spec.Data }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<p class="help is-danger">Editing is not supported now!</p>
|
<p class="help">Editing is not supported now!</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Labels</label>
|
<label class="label">{{ i18n("field.label") }}</label>
|
||||||
{{ yield options(name="label", items=.Config.Spec.Labels) }}
|
{{ yield options(name="label", items=.Config.Spec.Labels) }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ i18n("field.template") }}</label>
|
||||||
|
<div class="control">
|
||||||
|
{{ if .Config.Spec.Templating }}
|
||||||
|
{{ yield radio(name="template.name", value="", label="None", disabled=true, checked=.Config.Spec.Templating.Name) }}
|
||||||
|
{{ yield radio(name="template.name", value="golang", label="Golang", disabled=true, checked=.Config.Spec.Templating.Name) }}
|
||||||
|
{{ else }}
|
||||||
|
{{ yield radio(name="template.name", value="", label="None", disabled=true, checked="") }}
|
||||||
|
{{ yield radio(name="template.name", value="golang", label="Golang", disabled=true) }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<p class="help">Template feature needs Docker API version 1.37+</p>
|
||||||
|
</div>
|
||||||
{{ yield form_submit(url="/config/") }}
|
{{ yield form_submit(url="/config/") }}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,52 +19,31 @@
|
|||||||
<h2 class="title">Create config</h2>
|
<h2 class="title">Create config</h2>
|
||||||
<hr>
|
<hr>
|
||||||
<form method="post" data-form="ajax-json" data-url="/config/">
|
<form method="post" data-form="ajax-json" data-url="/config/">
|
||||||
<div class="field is-horizontal">
|
<div class="field">
|
||||||
<div class="field-label is-normal">
|
|
||||||
<label class="label">{{ i18n("field.name") }}</label>
|
<label class="label">{{ i18n("field.name") }}</label>
|
||||||
</div>
|
<div class="control">
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
|
||||||
<p class="control is-expanded">
|
|
||||||
<input name="name" class="input" type="text" placeholder="Config file name" data-v-rule="native" required>
|
<input name="name" class="input" type="text" placeholder="Config file name" data-v-rule="native" required>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="field is-horizontal">
|
|
||||||
<div class="field-label is-normal">
|
|
||||||
<label class="label">Data</label>
|
|
||||||
</div>
|
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
<label class="label">{{ i18n("field.data") }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<textarea name="data" class="textarea" rows="12" placeholder="Config file content" data-v-rule="native" required></textarea>
|
<textarea name="data" class="textarea" rows="12" placeholder="Config file content" data-v-rule="native" required></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field is-horizontal">
|
|
||||||
<div class="field-label is-normal">
|
|
||||||
<label class="label">Labels</label>
|
|
||||||
</div>
|
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
<label class="label">{{ i18n("field.label") }}</label>
|
||||||
{{ yield options(name="label") }}
|
{{ yield options(name="label") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field is-horizontal">
|
|
||||||
<div class="field-label">
|
|
||||||
</div>
|
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
<label class="label">{{ i18n("field.template") }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button type="submit" class="button is-primary">{{ i18n("button.submit") }}</button>
|
{{ yield radio(name="template.name", value="", label="None", checked="") }}
|
||||||
<a href="/config/" class="button is-link">{{ i18n("button.cancel") }}</a>
|
{{ yield radio(name="template.name", value="golang", label="Golang") }}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="help">Template feature needs Docker API version 1.37+</p>
|
||||||
</div>
|
</div>
|
||||||
|
{{ yield form_submit(url="/config/") }}
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
{{ end }}
|
{{ end }}
|
@ -50,16 +50,29 @@
|
|||||||
<input name="id" value="{{ .Secret.ID }}" type="hidden">
|
<input name="id" value="{{ .Secret.ID }}" type="hidden">
|
||||||
<input name="version" value="{{ .Secret.Version.Index }}" data-type="integer" type="hidden">
|
<input name="version" value="{{ .Secret.Version.Index }}" data-type="integer" type="hidden">
|
||||||
{*<div class="field">*}
|
{*<div class="field">*}
|
||||||
{*<label class="label">Data</label>*}
|
{*<label class="label">{{ i18n("field.data") }}</label>*}
|
||||||
{*<div class="control">*}
|
{*<div class="control">*}
|
||||||
{*<textarea class="textarea" rows="12" readonly>{{ .Secret.Spec.Data }}</textarea>*}
|
{*<textarea class="textarea" rows="12" readonly>{{ .Secret.Spec.Data }}</textarea>*}
|
||||||
{*</div>*}
|
{*</div>*}
|
||||||
{*<p class="help is-danger">Editing is not supported now!</p>*}
|
{*<p class="help">Editing is not supported now!</p>*}
|
||||||
{*</div>*}
|
{*</div>*}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Labels</label>
|
<label class="label">{{ i18n("field.label") }}</label>
|
||||||
{{ yield options(name="label", items=.Secret.Spec.Labels) }}
|
{{ yield options(name="label", items=.Secret.Spec.Labels) }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">{{ i18n("field.template") }}</label>
|
||||||
|
<div class="control">
|
||||||
|
{{ if .Secret.Spec.Templating }}
|
||||||
|
{{ yield radio(name="template.name", value="", label="None", disabled=true, checked=.Secret.Spec.Templating.Name) }}
|
||||||
|
{{ yield radio(name="template.name", value="golang", label="Golang", disabled=true, checked=.Secret.Spec.Templating.Name) }}
|
||||||
|
{{ else }}
|
||||||
|
{{ yield radio(name="template.name", value="", label="None", disabled=true, checked="") }}
|
||||||
|
{{ yield radio(name="template.name", value="golang", label="Golang", disabled=true) }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<p class="help">Template feature needs Docker API version 1.37+</p>
|
||||||
|
</div>
|
||||||
{{ yield form_submit(url="/secret/") }}
|
{{ yield form_submit(url="/secret/") }}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,52 +19,31 @@
|
|||||||
<h2 class="title">Create secret</h2>
|
<h2 class="title">Create secret</h2>
|
||||||
<hr>
|
<hr>
|
||||||
<form method="post" data-form="ajax-json" data-url="/secret/">
|
<form method="post" data-form="ajax-json" data-url="/secret/">
|
||||||
<div class="field is-horizontal">
|
<div class="field">
|
||||||
<div class="field-label is-normal">
|
|
||||||
<label class="label">{{ i18n("field.name") }}</label>
|
<label class="label">{{ i18n("field.name") }}</label>
|
||||||
</div>
|
<div class="control">
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
|
||||||
<p class="control is-expanded">
|
|
||||||
<input name="name" class="input" type="text" placeholder="Secret file name" data-v-rule="native" required>
|
<input name="name" class="input" type="text" placeholder="Secret file name" data-v-rule="native" required>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="field is-horizontal">
|
|
||||||
<div class="field-label is-normal">
|
|
||||||
<label class="label">Data</label>
|
|
||||||
</div>
|
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
<label class="label">{{ i18n("field.data") }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<textarea name="data" class="textarea" rows="12" placeholder="Secret file content" data-v-rule="native" required></textarea>
|
<textarea name="data" class="textarea" rows="12" placeholder="Secret file content" data-v-rule="native" required></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field is-horizontal">
|
|
||||||
<div class="field-label is-normal">
|
|
||||||
<label class="label">Labels</label>
|
|
||||||
</div>
|
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
<label class="label">{{ i18n("field.label") }}</label>
|
||||||
{{ yield options(name="label") }}
|
{{ yield options(name="label") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field is-horizontal">
|
|
||||||
<div class="field-label">
|
|
||||||
</div>
|
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
<label class="label">{{ i18n("field.template") }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button type="submit" class="button is-primary">{{ i18n("button.submit") }}</button>
|
{{ yield radio(name="template.name", value="", label="None", checked="") }}
|
||||||
<a href="/secret/" class="button is-link">{{ i18n("button.cancel") }}</a>
|
{{ yield radio(name="template.name", value="golang", label="Golang") }}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="help">Template feature needs Docker API version 1.37+</p>
|
||||||
</div>
|
</div>
|
||||||
|
{{ yield form_submit(url="/secret/") }}
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
{{ end }}
|
{{ end }}
|
Loading…
Reference in New Issue
Block a user