show service name

This commit is contained in:
w-mj 2023-02-16 14:54:44 +08:00
parent 3dad446d95
commit 9eb3fb3fce
No known key found for this signature in database
GPG Key ID: 3A2CB5BE2F835897
7 changed files with 91 additions and 22 deletions

8
go.mod
View File

@ -20,21 +20,20 @@ require (
k8s.io/client-go v0.26.1
)
require (
github.com/goccy/go-json v0.10.0
github.com/thoas/go-funk v0.9.3
)
require github.com/thoas/go-funk v0.9.3
require (
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/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
@ -46,6 +45,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/spf13/pflag v1.0.5 // 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

3
go.sum
View File

@ -142,6 +142,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
@ -190,6 +192,7 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=

View File

@ -32,7 +32,8 @@ func main() {
fp, _ := fs.Sub(f, "static")
r.StaticFS("/static", http.FS(fp))
r.GET("/app", m.JWTAuthMiddleware, m.AppPage)
r.GET("/index", m.JWTAuthMiddleware, m.AppPage)
r.GET("/apps", m.JWTAuthMiddleware, m.GetAppsController)
r.POST("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
r.PUT("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
r.DELETE("/app", m.JWTAuthMiddleware, m.CreateUpdateDeleteApp)
@ -64,6 +65,6 @@ func Test(c *gin.Context) {
c.SetCookie("Authorization", "Bearer "+token, 0, "", "", false, false)
c.Header("Authorization", "Bearer "+token)
c.Header("Cache-Control", "no-store")
c.Redirect(http.StatusTemporaryRedirect, "/app")
c.Redirect(http.StatusTemporaryRedirect, "/index")
}
}

View File

@ -35,12 +35,18 @@ func (a *AppModel) Fill() error {
}
func (a *AppModel) Update() error {
if a.SvcName == "" {
a.SvcName = "svc"
}
db := DB()
db.Save(a)
return nil
}
func (a *AppModel) Create() error {
if a.SvcName == "" {
a.SvcName = "svc"
}
db := DB()
db.Create(a)
return nil
@ -66,13 +72,13 @@ func (a *AppModel) ContainerName() string {
func (a *AppModel) ServiceName() string {
if strings.TrimSpace(a.SvcName) != "" {
return a.SvcName
return fmt.Sprintf("%s-%s", a.NamePrefix(), a.SvcName)
}
return a.DefaultServiceName()
}
func (a *AppModel) DefaultServiceName() string {
return fmt.Sprintf("%s-service", a.NamePrefix())
return fmt.Sprintf("%s-svc", a.NamePrefix())
}
func (a *AppModel) DeploymentName() string {

View File

@ -1,17 +1,18 @@
package k8s_manager
import (
"encoding/json"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"github.com/thoas/go-funk"
v1 "k8s.io/api/apps/v1"
"net/http"
"strings"
)
type AppViewModel struct {
*AppModel
Status string
Status string
ServiceDisplayName string
}
type AppsViewModel struct {
@ -19,20 +20,32 @@ type AppsViewModel struct {
Apps []AppViewModel
}
func statusString(status *v1.DeploymentStatus, err error) string {
func statusString(a *AppViewModel) string {
_, err := K.GetDeploymentStatus(a.AppModel.DeploymentName())
if err != nil {
if strings.Contains(err.Error(), "not found") {
return "Stopped"
return "Halt"
}
return err.Error()
} else {
if status.AvailableReplicas > 0 {
return "Running"
} else {
return "Error"
pod := K.GetPodFromDeployment(a.AppModel.DeploymentName())
if pod == nil {
return "Internal Error 1."
}
if len(pod.Status.ContainerStatuses) == 0 {
return "Internal Error 2."
}
containerState := pod.Status.ContainerStatuses[0].State
if containerState.Waiting != nil {
return containerState.Waiting.Reason
} else if containerState.Running != nil {
return "Start at " + containerState.Running.StartedAt.String()
} else if containerState.Terminated != nil {
b, _ := json.Marshal(containerState.Terminated)
return "Terminated " + string(b)
}
return pod.Status.Message + "," + pod.Status.Reason
}
}
func AppPage(c *gin.Context) {
@ -40,8 +53,8 @@ func AppPage(c *gin.Context) {
appsvm := funk.Map(GetApps(username), func(a AppModel) AppViewModel { return AppViewModel{AppModel: &a} }).([]AppViewModel)
for i := range appsvm {
a := &appsvm[i]
d, e := K.GetDeploymentStatus(a.AppModel.DeploymentName())
a.Status = statusString(d, e)
a.Status = statusString(a)
a.ServiceDisplayName = a.ServiceName()
}
vm := &AppsViewModel{
Username: username,
@ -90,3 +103,9 @@ func CreateUpdateDeleteApp(c *gin.Context) {
}
}
}
func GetAppsController(c *gin.Context) {
username := c.MustGet("username").(string)
apps := GetApps(username)
c.JSON(http.StatusOK, apps)
}

View File

@ -10,7 +10,8 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"os"
"strings"
)
@ -21,7 +22,8 @@ type K8sClient struct {
func CreateClient() *K8sClient {
var err error
config, err := rest.InClusterConfig()
// config, err := rest.InClusterConfig()
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBE_CONFIG"))
if err != nil {
log.WithError(err).Error("InClusterConfig")
return nil
@ -64,6 +66,10 @@ func (c *K8sClient) UpdateDeployment(app *AppModel) {
var rep int32 = 1
labelKey, labelValue := app.GetLabel()
labels := map[string]string{labelKey: labelValue}
podLabels := map[string]string{
labelKey: labelValue,
"cg-deployment": app.DeploymentName(),
}
deployment := &appv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: app.DeploymentName(),
@ -76,7 +82,7 @@ func (c *K8sClient) UpdateDeployment(app *AppModel) {
},
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
Labels: podLabels,
},
Spec: v1.PodSpec{
Containers: []v1.Container{{
@ -160,6 +166,24 @@ func (c *K8sClient) DeleteApp(app *AppModel) {
}
}
func (c *K8sClient) DeleteAppService(app *AppModel) {
k, v := app.GetLabel()
label := labels.FormatLabels(map[string]string{k: v})
svcs, err := c.CoreV1().Services(c.Namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: label,
})
if err != nil {
log.WithError(err).Error("DeleteAppService Get")
return
}
for _, svc := range svcs.Items {
err := c.CoreV1().Services(c.Namespace).Delete(context.Background(), svc.Name, metav1.DeleteOptions{})
if err != nil {
log.WithError(err).WithField("name", svc.Name).Error("Delete svc")
}
}
}
func (c *K8sClient) DeleteDeployment(depName string) {
if !c.DeploymentExists(depName) {
return
@ -188,3 +212,17 @@ func (c *K8sClient) GetAllServices() *v1.ServiceList {
}
return list
}
func (c *K8sClient) GetPodFromDeployment(deploymentName string) *v1.Pod {
label := labels.FormatLabels(map[string]string{"cg-deployment": deploymentName})
pods, err := c.CoreV1().Pods(c.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: label})
if err != nil {
log.WithError(err).Error("GetPodFromDeployment")
return nil
}
if len(pods.Items) == 0 {
log.WithField("label", label).Error("GetPodFromDeployment no such label pod.")
return nil
}
return &pods.Items[0]
}

View File

@ -34,6 +34,7 @@
<th>启动命令</th>
<th>环境变量</th>
<th>状态</th>
<th>服务名</th>
<th>操作</th>
</tr>
</thead>
@ -48,6 +49,7 @@
<td class="app-field-cmd"> {{ $v.Command }}</td>
<td class="app-field-env"> {{ $v.Env }}</td>
<td class="app-field-status" id="app-status-{{ $v.Id }}"> {{ $v.Status }} </td>
<td class="app-field-svc"> {{ $v.ServiceDisplayName }} </td>
<td>
<div class="btn-group">
<button class="btn btn-success" onclick="startApp('{{$v.Id}}')">启动</button>