Basic web page

This commit is contained in:
w-mj 2023-02-13 15:37:40 +08:00
parent 865b5014e1
commit a2e7d8b148
No known key found for this signature in database
GPG Key ID: 3A2CB5BE2F835897
12 changed files with 176 additions and 55 deletions

14
go.mod
View File

@ -2,24 +2,30 @@ module k8s-manager
go 1.19
require (
github.com/gin-gonic/gin v1.8.2
github.com/golang-jwt/jwt/v4 v4.3.0
github.com/sirupsen/logrus v1.9.0
gorm.io/driver/mysql v1.4.6
gorm.io/gorm v1.24.5
)
require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.8.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.11.2 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/goccy/go-json v0.10.0 // indirect
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/net v0.6.0 // indirect
@ -27,6 +33,4 @@ require (
golang.org/x/text v0.7.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.4.6 // indirect
gorm.io/gorm v1.24.5 // indirect
)

13
go.sum
View File

@ -1,9 +1,12 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
@ -17,6 +20,7 @@ github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@ -26,6 +30,9 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
@ -37,7 +44,9 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -48,6 +57,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
@ -61,14 +71,17 @@ golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.4.6 h1:5zS3vIKcyb46byXZNcYxaT9EWNIhXzu0gPuvvVrwZ8s=
gorm.io/driver/mysql v1.4.6/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc=

37
main.go
View File

@ -3,10 +3,10 @@ package main
import (
"embed"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"html/template"
"io/fs"
m "k8s-manager/src"
"log"
"net/http"
)
@ -16,14 +16,45 @@ var f embed.FS
func main() {
r := gin.Default()
r.SetHTMLTemplate(template.Must(template.New("").ParseFS(f, "template/*")))
r.SetFuncMap(template.FuncMap{
"inc": m.Inc,
})
tmp := template.Must(template.New("").
Funcs(template.FuncMap{
"inc": m.Inc,
}).
ParseFS(f, "template/*"))
r.SetHTMLTemplate(tmp)
fp, _ := fs.Sub(f, "static")
r.StaticFS("/static", http.FS(fp))
r.GET("/app", m.JWTAuthMiddleware, m.AppPage)
r.GET("/test/:username", m.Test)
r.GET("/login/:username", Test)
err := r.Run()
if err != nil {
log.Fatal(err)
}
}
func Test(c *gin.Context) {
username := c.Param("username")
if username == "" {
c.JSON(http.StatusNotFound, gin.H{
"code": http.StatusNotFound,
"msg": "No user name.",
})
} else {
token, err := m.GenerateToken(username)
if err != nil {
log.Error(err)
c.Abort()
return
}
c.SetCookie("Authorization", "Bearer "+token, 0, "", "", false, false)
c.Header("Authorization", "Bearer "+token)
c.Header("Cache-Control", "no-store")
c.Redirect(http.StatusTemporaryRedirect, "/app")
}
}

View File

@ -6,6 +6,7 @@ type AppModel struct {
UserName string
Image string
Command string
Comment string
Env string
SvcName string
}

View File

@ -4,14 +4,11 @@ import (
"errors"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4"
"github.com/sirupsen/logrus"
"net/http"
"strings"
"time"
)
var log = logrus.New()
type MyClaims struct {
Username string `json:"username"`
jwt.RegisteredClaims
@ -83,24 +80,3 @@ func JWTAuthMiddleware(c *gin.Context) {
}
c.Set("username", mc.Username)
}
func Test(c *gin.Context) {
username := c.Param("username")
if username == "" {
c.JSON(http.StatusNotFound, gin.H{
"code": http.StatusNotFound,
"msg": "No user name.",
})
} else {
token, err := GenerateToken(username)
if err != nil {
log.Error(err)
c.Abort()
return
}
c.SetCookie("Authorization", "Bearer "+token, 0, "", "", false, false)
c.Header("Authorization", "Bearer "+token)
c.Header("Cache-Control", "no-store")
c.Redirect(http.StatusTemporaryRedirect, "/app")
}
}

5
src/template_func.go Normal file
View File

@ -0,0 +1,5 @@
package k8s_manager
func Inc(i int) int {
return i + 1
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -11,12 +11,108 @@
<div class="container">
<h1>应用管理页面</h1>
<p>用户名:{{ .Username }}</p>
{{ range .Apps }}
<p>{{ . }}</p>
{{ end }}
<br/>
<div class="d-flex">
<div class="align-self-start">用户名:{{ .Username }}</div>
<div class="ms-auto align-self-end">
<button class="btn btn-success" onclick="showModal('')">添加应用</button>
</div>
</div>
<br/>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>应用名</th>
<th>描述</th>
<th>镜像名</th>
<th>启动命令</th>
<th>环境变量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{ range $i, $v := .Apps }}
<tr id="app-list-{{ $v.Id }}">
<td> {{ inc $i }}</td>
<td> {{ $v.AppName }}</td>
<td> {{ $v.Comment }}</td>
<td> {{ $v.Image }}</td>
<td> {{ $v.Command }}</td>
<td> {{ $v.Env }}</td>
<td>
<div class="btn-group">
<button class="btn btn-primary" onclick="showModal('app-list-{{ $v.Id }}')">修改</button>
<button class="btn btn-danger">删除</button>
</div>
</td>
</tr>
{{ else }}
<tr>
<td colspan="7" style="text-align: center;">点击+按钮添加应用</td>
</tr>
{{ end }}
</tbody>
</table>
<div class="modal" tabindex="-1" id="edit-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">编辑应用</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-auto">
<label for="app-name" class="form-label">应用名</label>
<input type="text" id="app-name" class="form-control" placeholder="只能为字母、数字和下划线" />
</div>
<div class="col-auto">
<label for="app-image" class="form-label">镜像</label>
<input type="text" id="app-image" class="form-control" placeholder="Docker镜像名" />
</div>
</div>
<div class="row">
<label for="app-cmd" class="form-label">镜像</label>
<input type="text" id="app-cmd" class="form-control" placeholder="启动命令,可选" />
</div>
<div class="row">
<label for="app-env" class="form-label">镜像</label>
<input type="text" id="app-env" class="form-control" placeholder="环境变量,可选" />
</div>
<div class="row">
<label for="app-comment" class="form-label">镜像</label>
<textarea type="text" id="app-comment" class="form-control" placeholder="应用描述"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary">保存</button>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
function showModal(id) {
const modal = new bootstrap.Modal("#edit-modal")
console.log(modal)
modal.show()
}
</script>
</html>