diff --git a/install.yaml b/install.yaml index 9e2630c..911b9e0 100644 --- a/install.yaml +++ b/install.yaml @@ -33,11 +33,15 @@ spec: value: "!bd832W0@CG" - name: ASE_KEY value: A5es$&!0GeoEast + - name: NFS_HOST + value: 192.168.252.250 + - name: NFS_PATH + value: /mnt/CGdata/ms volumeMounts: - - name: persistent-storage - mountPath: /nfs + - name: k8s-manager-nfs-volume + mountPath: /mnt/CGdata/ms volumes: - - name: persistent-storage + - name: k8s-manager-nfs-volume nfs: server: 192.168.252.250 path: /mnt/CGdata/ms diff --git a/main.go b/main.go index ed1f6c0..bb6a127 100644 --- a/main.go +++ b/main.go @@ -21,21 +21,10 @@ import ( //go:embed template/* static/* var f embed.FS -var jwtKey string -var aseKey string - func main() { + m.InitConfig() m.InitClient() - jwtKey = os.Getenv("JWT_KEY") - aseKey = os.Getenv("ASE_KEY") - if jwtKey == "" { - panic("No jwt key") - } - if aseKey == "" { - panic("No ase key") - } - r := gin.Default() fp, _ := fs.Sub(f, "static") @@ -52,7 +41,9 @@ func main() { r.POST("/dep", m.JWTAuthMiddleware, m.CreateDeleteDeployment) r.DELETE("/dep", m.JWTAuthMiddleware, m.CreateDeleteDeployment) - r.GET("/login", Test) + r.GET("/pod", m.JWTAuthMiddleware, m.GetPodStatus) + + r.GET("/login", LoginToken) r.Any("/test_token", TestToken) r.GET("/username", m.JWTAuthMiddleware, m.GetUsername) err := r.Run(":8000") @@ -76,10 +67,10 @@ func ParseCGToken(token string) (string, error) { return "", err } - jwtString := AesDecryptECB(aesEncrypt, []byte(aseKey)) + jwtString := AesDecryptECB(aesEncrypt, []byte(m.GetConfig().AseKey)) jwtResult, err := jwt.ParseWithClaims(string(jwtString), &CGJWTClaim{}, func(token *jwt.Token) (i interface{}, err error) { - return []byte(jwtKey), nil + return []byte(m.GetConfig().JwtKey), nil // return hmac.New(sha256.New, []byte(jwtKey)), nil }) if err != nil { @@ -146,7 +137,7 @@ func AesDecrypt(data []byte, key []byte) ([]byte, error) { return crypted, nil } -func Test(c *gin.Context) { +func LoginToken(c *gin.Context) { username := c.Request.URL.Query().Get("username") var err error if username == "" { @@ -158,26 +149,30 @@ func Test(c *gin.Context) { "msg": "user name error", }) } else { - token, err := m.GenerateToken(username) - if err != nil { - log.Error(err) - c.Abort() - return - } - log.WithField("user name", username).Info("Login success.") - c.SetCookie("Authorization", "Bearer "+token, 0, "", "", false, false) - c.Header("Authorization", "Bearer "+token) - c.Header("Cache-Control", "no-store") - redirectUrl := "" - if os.Getenv("URL_PREFIX") == "" { - redirectUrl = "/index" - } else { - redirectUrl = fmt.Sprintf("/%s/index", os.Getenv("URL_PREFIX")) - } - c.Redirect(http.StatusTemporaryRedirect, redirectUrl) + Login(c, username) } } +func Login(c *gin.Context, username string) { + token, err := m.GenerateToken(username) + if err != nil { + log.Error(err) + c.Abort() + return + } + log.WithField("user name", username).Info("Login success.") + c.SetCookie("Authorization", "Bearer "+token, 0, "", "", false, false) + c.Header("Authorization", "Bearer "+token) + c.Header("Cache-Control", "no-store") + redirectUrl := "" + if os.Getenv("URL_PREFIX") == "" { + redirectUrl = "/index" + } else { + redirectUrl = fmt.Sprintf("/%s/index", os.Getenv("URL_PREFIX")) + } + c.Redirect(http.StatusTemporaryRedirect, redirectUrl) +} + func TestToken(c *gin.Context) { token := c.Request.URL.Query().Get("cgtoken") if token == "" { diff --git a/src/app_model.go b/src/app_model.go index 9c7e2e4..0fd0bcd 100644 --- a/src/app_model.go +++ b/src/app_model.go @@ -37,21 +37,25 @@ func (a *AppModel) Fill() error { return res.Error } -func (a *AppModel) Update() error { +func (a *AppModel) fillDefaults() { if a.SvcName == "" { a.SvcName = "svc" } a.SvcName = strings.TrimPrefix(a.SvcName, a.NamePrefix()+"-") + if a.PersistentPath == "" { + a.PersistentPath = "/data/" + } +} + +func (a *AppModel) Update() error { + a.fillDefaults() db := DB() db.Save(a) return nil } func (a *AppModel) Create() error { - if a.SvcName == "" { - a.SvcName = "svc" - } - a.SvcName = strings.TrimPrefix(a.SvcName, a.NamePrefix()+"-") + a.fillDefaults() db := DB() db.Create(a) return nil @@ -156,7 +160,7 @@ func (a *AppModel) PersistentVolumeName() string { } func (a *AppModel) NFSPath() string { - return "/data/" + a.UserName + return GetConfig().NFSPath + "/" + a.UserName } func (a *AppModel) PersistentVolumeClaimName() string { @@ -166,3 +170,7 @@ func (a *AppModel) PersistentVolumeClaimName() string { func (a *AppModel) StorageClassName() string { return a.NamePrefix() + "-storage-class" } + +func (a *AppModel) PersistentVolumeMountName() string { + return a.NamePrefix() + "-pvm" +} diff --git a/src/config.go b/src/config.go new file mode 100644 index 0000000..2ec2909 --- /dev/null +++ b/src/config.go @@ -0,0 +1,60 @@ +package k8s_manager + +import ( + "fmt" + "os" + "reflect" +) + +type Config struct { + JwtKey string + AseKey string + DBHost string + DBUser string + DBPassword string + NFSHost string + NFSPath string +} + +var config *Config + +func getField(v *Config, field string) string { + r := reflect.ValueOf(v) + f := reflect.Indirect(r).FieldByName(field) + return f.String() +} + +func setField(v *Config, field string, value string) { + r := reflect.ValueOf(v) + f := reflect.Indirect(r).FieldByName(field) + f.SetString(value) +} + +func InitConfig() { + config = &Config{} + config.JwtKey = os.Getenv("JWT_KEY") + config.AseKey = os.Getenv("ASE_KEY") + config.DBHost = os.Getenv("DB_HOST") + config.DBUser = os.Getenv("DB_USER") + config.DBPassword = os.Getenv("DB_PASS") + config.NFSHost = os.Getenv("NFS_HOST") + config.NFSPath = os.Getenv("NFS_PATH") + + mustFields := []string{"JwtKey", "AseKey", "DBHost", "DBUser", "DBPassword", "NFSHost", "NFSPath"} + optionalFields := map[string]string{} + for _, f := range mustFields { + if getField(config, f) == "" { + panic(fmt.Sprintf("field %s must be set.", f)) + } + } + for f, v := range optionalFields { + if getField(config, f) == "" { + setField(config, f, v) + } + } + +} + +func GetConfig() *Config { + return config +} diff --git a/src/deployment_manager.go b/src/deployment_manager.go index f67ccf8..b86f0bf 100644 --- a/src/deployment_manager.go +++ b/src/deployment_manager.go @@ -49,3 +49,20 @@ func CreateDeleteDeployment(c *gin.Context) { } c.JSON(http.StatusOK, gin.H{"msg": "ok"}) } + +func GetPodStatus(c *gin.Context) { + id := c.Query("id") + if strings.TrimSpace(id) == "" { + c.JSON(http.StatusBadRequest, gin.H{"msg": "no app id"}) + return + } + appId, err := strconv.Atoi(id) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"msg": "wrong id"}) + return + } + app := AppModel{Id: appId} + app.Fill() + pod := K.GetPodFromDeployment(app.DeploymentName()) + c.JSON(http.StatusOK, pod.Status) +} diff --git a/src/k8s_client.go b/src/k8s_client.go index eea2897..526b65f 100644 --- a/src/k8s_client.go +++ b/src/k8s_client.go @@ -72,20 +72,27 @@ func (c *K8sClient) DeploymentExists(deploymentName string) bool { } func (c *K8sClient) UpdateDeployment(app *AppModel) { - var rep int32 = 1 labelKey, labelValue := app.GetLabel() l := map[string]string{labelKey: labelValue} + if _, err := os.Stat(app.NFSPath()); os.IsNotExist(err) { + os.MkdirAll(app.NFSPath(), os.ModeDir) + } podLabels := map[string]string{ labelKey: labelValue, "cg-deployment": app.DeploymentName(), } + containerPorts := funk.Map(app.GetPorts(), func(port int32) v1.ContainerPort { + return v1.ContainerPort{ + ContainerPort: port, + } + }).([]v1.ContainerPort) deployment := &appv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: app.DeploymentName(), Labels: l, }, Spec: appv1.DeploymentSpec{ - Replicas: &rep, + Replicas: UnnamedPointer(int32(1)), Selector: &metav1.LabelSelector{ MatchLabels: l, }, @@ -102,14 +109,30 @@ func (c *K8sClient) UpdateDeployment(app *AppModel) { Name: "URL_PREFIX", Value: app.ServiceName(), }), - VolumeMounts: nil, - Ports: []v1.ContainerPort{ - {ContainerPort: 80}, - }, + //VolumeMounts: []v1.VolumeMount{ + // { + // Name: app.PersistentVolumeMountName(), + // ReadOnly: false, + // MountPath: app.PersistentPath, + // }, + //}, + Ports: containerPorts, SecurityContext: &v1.SecurityContext{ RunAsUser: UnnamedPointer(int64(0)), }, }}, + //Volumes: []v1.Volume{ + // { + // Name: app.PersistentVolumeMountName(), + // VolumeSource: v1.VolumeSource{ + // NFS: &v1.NFSVolumeSource{ + // Server: config.NFSHost, + // Path: app.NFSPath(), + // ReadOnly: false, + // }, + // }, + // }, + //}, }, }, }, @@ -362,7 +385,7 @@ func (c *K8sClient) CreatePersistentVolume(app *AppModel) { StorageClassName: app.StorageClassName(), PersistentVolumeSource: v1.PersistentVolumeSource{ NFS: &v1.NFSVolumeSource{ - Server: "192.168.1.1", + Server: GetConfig().NFSHost, Path: app.NFSPath(), ReadOnly: false, }, diff --git a/src/orm.go b/src/orm.go index 2f00370..1b25cb7 100644 --- a/src/orm.go +++ b/src/orm.go @@ -5,7 +5,6 @@ import ( "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/gorm" - "os" "sync" ) @@ -16,18 +15,9 @@ func opendb() *gorm.DB { if instance == nil { lock.Lock() if instance == nil { - db_host, ok := os.LookupEnv("DB_HOST") - if !ok { - panic("DB_HOST NOT SET") - } - db_user, ok := os.LookupEnv("DB_USER") - if !ok { - panic("DB_USER NOT SET") - } - db_pass, ok := os.LookupEnv("DB_PASS") - if !ok { - panic("DB_PASS NOT SET") - } + db_host := GetConfig().DBHost + db_user := GetConfig().DBUser + db_pass := GetConfig().DBPassword dsn := fmt.Sprintf("%s:%s@tcp(%s:3306)/k8s?charset=utf8mb4&parseTime=True&loc=Local", db_user, db_pass, db_host) var err error instance, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) @@ -43,6 +33,9 @@ func opendb() *gorm.DB { func checkdb(cnt int) *gorm.DB { ans := opendb() + if ans == nil { + return nil + } db, err := ans.DB() if err != nil { logrus.WithError(err).Error("Cannot get *sql.DB.") diff --git a/template/app_view.html b/template/app_view.html index f85c4d1..0f5d874 100644 --- a/template/app_view.html +++ b/template/app_view.html @@ -48,8 +48,15 @@ {{ item.Image }} {{ item.Command }} {{ item.Env }} - {{ item.Status }} - {{ item.ServiceDisplayName }} + + + {{ item.Status }} + + + {{ item.Status }} + + + {{ item.ServiceDisplayName }} {{ item.Ports }}
@@ -112,7 +119,14 @@
+ placeholder="端口号"/> +
+ +
+ +
@@ -136,13 +150,27 @@ 请求失败
-
- {{ toastText }} +
+ + + @@ -165,8 +193,11 @@ Comment: "", Env: "", SvcName: "", + PersistentPath: "", Ports: "", - } + }, + timer: null, + podStatus: "" } }, methods: { @@ -216,11 +247,22 @@ this.username = r.data.Username this.apps = r.data.Apps }) + }, + showPodStatus(app) { + axios.get("pod?id=" + app.Id).then(r => { + this.podStatus = JSON.stringify(r.data, null, 2); + (new bootstrap.Modal("#pod-status-modal")).show(); + }); } }, mounted() { this.blankApp = JSON.parse(JSON.stringify(this.selectApp)) this.refresh() + if (this.timer) { + clearInterval(this.timer) + this.timer = null + } + setInterval(this.timer, this.refresh, 5000) } }).mount("#app")