host from template ui
This commit is contained in:
parent
699b8e71a6
commit
7c9334233d
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
|
||||||
@ -55,6 +56,10 @@ func hostOrTemplate(cfg *localconfig.Config, name string) (host *localconfig.Hos
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wsHostsFromTemplateList(req *restful.Request, resp *restful.Response) {
|
||||||
|
hostsFromTemplate.WsList(resp, "")
|
||||||
|
}
|
||||||
|
|
||||||
func wsHostsFromTemplateSet(req *restful.Request, resp *restful.Response) {
|
func wsHostsFromTemplateSet(req *restful.Request, resp *restful.Response) {
|
||||||
name := req.PathParameter("name")
|
name := req.PathParameter("name")
|
||||||
|
|
||||||
@ -78,6 +83,10 @@ func wsHostsFromTemplateSet(req *restful.Request, resp *restful.Response) {
|
|||||||
wsBadRequest(resp, "ip is required")
|
wsBadRequest(resp, "ip is required")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if _, err := netip.ParseAddr(v.IP); err != nil {
|
||||||
|
wsBadRequest(resp, "bad IP: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
for _, ht := range cfg.HostTemplates {
|
for _, ht := range cfg.HostTemplates {
|
||||||
|
@ -76,6 +76,8 @@ func registerWS(rest *restful.Container) {
|
|||||||
ws.Route(ws.GET("/clusters").To(wsListClusters).
|
ws.Route(ws.GET("/clusters").To(wsListClusters).
|
||||||
Doc("List clusters"))
|
Doc("List clusters"))
|
||||||
|
|
||||||
|
ws.Route(ws.GET("/hosts-from-template").To(wsHostsFromTemplateList).
|
||||||
|
Doc("List host template instances"))
|
||||||
ws.Route(ws.POST("/hosts-from-template/{name}").To(wsHostsFromTemplateSet).
|
ws.Route(ws.POST("/hosts-from-template/{name}").To(wsHostsFromTemplateSet).
|
||||||
Reads(HostFromTemplate{}).
|
Reads(HostFromTemplate{}).
|
||||||
Doc("Create or update a host template instance"))
|
Doc("Create or update a host template instance"))
|
||||||
|
@ -87,11 +87,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Admin actions</h2>
|
<h2>Admin actions</h2>
|
||||||
|
|
||||||
<h3>Config</h3>
|
<h3>Config</h3>
|
||||||
<form @submit="uploadConfig">
|
<form @submit="uploadConfig">
|
||||||
<input type="file" ref="configUpload" required />
|
<input type="file" ref="configUpload" required />
|
||||||
<input type="submit" value="upload config" />
|
<input type="submit" value="upload config" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<h3>Store</h3>
|
<h3>Store</h3>
|
||||||
<p><a :href="'/public/store.tar?token='+state.Store.DownloadToken" target="_blank">Download</a></p>
|
<p><a :href="'/public/store.tar?token='+state.Store.DownloadToken" target="_blank">Download</a></p>
|
||||||
<form @submit="storeAddKey" action="/store/add-key">
|
<form @submit="storeAddKey" action="/store/add-key">
|
||||||
@ -109,6 +111,27 @@
|
|||||||
<p v-if="state.Store.KeyNames">Available names:
|
<p v-if="state.Store.KeyNames">Available names:
|
||||||
<template v-for="k,i in state.Store.KeyNames">{{i?", ":""}}<code @click="forms.delKey.name=k">{{k}}</code></template>.</p>
|
<template v-for="k,i in state.Store.KeyNames">{{i?", ":""}}<code @click="forms.delKey.name=k">{{k}}</code></template>.</p>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<template v-if="state.HostTemplates">
|
||||||
|
<h3>Hosts from template</h3>
|
||||||
|
<form @submit="hostFromTemplateAdd" action="">
|
||||||
|
<p>Add a host from template instance:</p>
|
||||||
|
<input type="text" v-model="forms.hostFromTemplate.name" required placeholder="Name" />
|
||||||
|
<select v-model="forms.hostFromTemplate.Template" required>
|
||||||
|
<option v-for="name in state.HostTemplates" :value="name">{{name}}</option>
|
||||||
|
</select>
|
||||||
|
<input type="text" v-model="forms.hostFromTemplate.IP" required placeholder="IP" />
|
||||||
|
<input type="submit" value="add instance" />
|
||||||
|
</form>
|
||||||
|
<form @submit="hostFromTemplateDel" action="">
|
||||||
|
<p>Remove a host from template instance:</p>
|
||||||
|
<select v-model="forms.hostFromTemplateDel" required>
|
||||||
|
<option v-for="h in hostsFromTemplate" :value="h.Name">{{h.Name}}</option>
|
||||||
|
</select>
|
||||||
|
<input type="submit" value="delete instance" :disabled="!forms.hostFromTemplateDel" />
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ export default {
|
|||||||
<section>
|
<section>
|
||||||
<div><small>Cluster: {{ host.Cluster }}<template v-if="host.Template"> ({{ host.Template }})</template></small></div>
|
<div><small>Cluster: {{ host.Cluster }}<template v-if="host.Template"> ({{ host.Template }})</template></small></div>
|
||||||
<template v-for="ip in host.IPs">
|
<template v-for="ip in host.IPs">
|
||||||
<tt>{{ ip }}</tt>
|
<code>{{ ip }}</code>
|
||||||
</template>
|
</template>
|
||||||
</section>
|
</section>
|
||||||
<div class="section">Downloads</div>
|
<div class="section">Downloads</div>
|
||||||
|
@ -12,6 +12,8 @@ createApp({
|
|||||||
store: {},
|
store: {},
|
||||||
storeUpload: {},
|
storeUpload: {},
|
||||||
delKey: {},
|
delKey: {},
|
||||||
|
hostFromTemplate: {},
|
||||||
|
hostFromTemplateDel: "",
|
||||||
},
|
},
|
||||||
session: {},
|
session: {},
|
||||||
error: null,
|
error: null,
|
||||||
@ -54,6 +56,12 @@ createApp({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
hostsFromTemplate() {
|
||||||
|
return (this.state.Hosts||[]).filter((h) => h.Template)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
copyText(text) {
|
copyText(text) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@ -104,9 +112,21 @@ createApp({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
uploadConfig() {
|
uploadConfig() {
|
||||||
event.preventDefault()
|
|
||||||
this.apiPost('/configs', this.$refs.configUpload.files[0], (v) => {}, "text/vnd.yaml")
|
this.apiPost('/configs', this.$refs.configUpload.files[0], (v) => {}, "text/vnd.yaml")
|
||||||
},
|
},
|
||||||
|
hostFromTemplateAdd() {
|
||||||
|
let v = this.forms.hostFromTemplate;
|
||||||
|
this.apiPost('/hosts-from-template/'+v.name, v, (v) => { this.forms.hostFromTemplate = {} });
|
||||||
|
},
|
||||||
|
hostFromTemplateDel() {
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
let v = this.forms.hostFromTemplateDel;
|
||||||
|
if (!confirm("delete host template instance "+v+"?")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.apiDelete('/hosts-from-template/'+v, (v) => { this.forms.hostFromTemplateDel = "" });
|
||||||
|
},
|
||||||
apiPost(action, data, onload, contentType = 'application/json') {
|
apiPost(action, data, onload, contentType = 'application/json') {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
@ -155,6 +175,27 @@ createApp({
|
|||||||
xhr.send(data)
|
xhr.send(data)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
apiDelete(action, data, onload) {
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest()
|
||||||
|
xhr.onload = (r) => {
|
||||||
|
if (xhr.status != 200) {
|
||||||
|
this.error = xhr.response
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.error = null
|
||||||
|
if (onload) {
|
||||||
|
onload(xhr.response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.open("DELETE", action)
|
||||||
|
xhr.setRequestHeader('Accept', 'application/json')
|
||||||
|
if (this.session.token) {
|
||||||
|
xhr.setRequestHeader('Authorization', 'Bearer '+this.session.token)
|
||||||
|
}
|
||||||
|
xhr.send()
|
||||||
|
},
|
||||||
download(url) {
|
download(url) {
|
||||||
event.target.target = '_blank'
|
event.target.target = '_blank'
|
||||||
event.target.href = this.downloadLink(url)
|
event.target.href = this.downloadLink(url)
|
||||||
|
Loading…
Reference in New Issue
Block a user