Skip to content

Commit

Permalink
Merge pull request #2 from muxiyun/dev-andrew
Browse files Browse the repository at this point in the history
Dev andrew
  • Loading branch information
Andrewpqc authored Aug 17, 2018
2 parents 99ab747 + c7e03bc commit f7b3989
Show file tree
Hide file tree
Showing 71 changed files with 5,899 additions and 1,586 deletions.
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out.
.idea/
.vscode/
Mae
MAE
log/
conf/admin.kubeconfig
8 changes: 0 additions & 8 deletions .idea/MAE.iml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/misc.xml

This file was deleted.

8 changes: 0 additions & 8 deletions .idea/modules.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/vcs.xml

This file was deleted.

423 changes: 0 additions & 423 deletions .idea/workspace.xml

This file was deleted.

35 changes: 20 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
# MAE:Muxi APP Engine
# [muxi application engine(Mae)](https://github.com/muxiyun/Mae/tree/master)

[![Build Status](https://travis-ci.org/Andrewpqc/MAE.svg?branch=master)](https://travis-ci.org/Andrewpqc/MAE)
PaaS of Muxi-Studio. An easier way to manage Kubernetes cluser.

An easier way to manipulate Kubernetes cluser.
Click [http://zxc0328.github.io/2017/05/27/mae/](http://zxc0328.github.io/2017/05/27/mae/) to view details.

The PaaS of Muxi-Studio, Server Part of [Project MAE](http://zxc0328.github.io/2017/05/27/mae/)

TODO:
- [x] API Design
- [x] Domain UML & Db UML
Code Part: <br>
- [ ] Models
- [ ] 用户系统
- [ ] 接入Casbin
- [ ] 应用部分
- [ ] 服务部分
- [ ] 版本部分
- [ ] 查看log
- [ ] Nginx反向代理部分
- [x] api design
- [x] domain UML & database UML
- [x] user system
- [x] casbin access control
- [x] application (abstract entity)
- [x] service (abstract entity)
- [x] version (abstract entity)
- [x] log query
- [x] web terminal
- [x] email notification for admin
NEXT:

1.现在版本的切换采取的是删除原版本的资源之后创建新版本的资源,后面改为灰度发布

2.优化int类型的使用,重构部分代码

3.文档
227 changes: 227 additions & 0 deletions app_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
//app ,应用增删改查测试文件
package main

import (
"github.com/kataras/iris/httptest"
"github.com/muxiyun/Mae/model"
"testing"
"time"
)

func TestAppCRUD(t *testing.T) {
e := httptest.New(t, newApp(), httptest.URL("http://127.0.0.1:8080"))
defer model.DB.RWdb.DropTableIfExists("users")
defer model.DB.RWdb.DropTableIfExists("casbin_rule")
defer model.DB.RWdb.DropTableIfExists("apps")
defer model.DB.RWdb.DropTableIfExists("versions")
defer model.DB.RWdb.DropTableIfExists("services")

CreateUserForTest(e, "andrew", "andrew123", "andrewpqc@mails.ccnu.edu.cn")
CreateAdminForTest(e, "andrewadmin", "andrewadmin123", "3480437308@qq.com")
andrew_token := GetTokenForTest(e, "andrew", "andrew123", 60*60)
andrewadmin_token := GetTokenForTest(e, "andrewadmin", "andrewadmin123", 60*60)

// Anonymous to create an app
e.POST("/api/v1.0/app").WithJSON(map[string]interface{}{
"app_name": "学而",
"app_desc": "华师课程挖掘机",
}).Expect().Status(httptest.StatusForbidden)

//a normal user to create an app
e.POST("/api/v1.0/app").WithJSON(map[string]interface{}{
"app_name": "学而",
"app_desc": "华师课程挖掘机",
}).WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

//an admin to create an app
e.POST("/api/v1.0/app").WithJSON(map[string]interface{}{
"app_name": "华师匣子",
"app_desc": "华师校园助手",
}).WithBasicAuth(andrewadmin_token, "").Expect().Body().Contains("OK")

//Anonymous to get an app
e.GET("/api/v1.0/app/{appname}").WithPath("appname", "学而").Expect().Status(httptest.StatusForbidden)

//a normal user to get an app
e.GET("/api/v1.0/app/{appname}").WithPath("appname", "学而").WithBasicAuth(andrew_token, "").
Expect().Body().Contains("OK")

// an admin user to get an app
e.GET("/api/v1.0/app/{appname}").WithPath("appname", "学而").WithBasicAuth(andrewadmin_token, "").
Expect().Body().Contains("OK")

// Anonymous to update a app
e.PUT("/api/v1.0/app/{id}").WithPath("id", 1).WithJSON(map[string]interface{}{
"app_name": "xueer",
}).Expect().Status(httptest.StatusForbidden)

//a normal user to update an app
e.PUT("/api/v1.0/app/{id}").WithPath("id", 1).WithJSON(map[string]interface{}{
"app_name": "Xueer",
"app_desc": "华师课程挖掘机鸡鸡鸡鸡",
}).WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

//an admin user to update an app
e.PUT("/api/v1.0/app/{id}").WithPath("id", 1).WithJSON(map[string]interface{}{
"app_name": "xueer",
"app_desc": "山东蓝想挖掘机学学校",
}).WithBasicAuth(andrewadmin_token, "").Expect().Body().Contains("OK")

//anonymous to list apps
e.GET("/api/v1.0/app").Expect().Status(httptest.StatusForbidden)

//a normal user to list apps
e.GET("/api/v1.0/app").WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

// an admin user to list apps
e.GET("/api/v1.0/app").WithBasicAuth(andrewadmin_token, "").Expect().Body().Contains("OK")

// anonymous to delete an app
e.DELETE("/api/v1.0/app/{id}").WithPath("id", 1).Expect().Status(httptest.StatusForbidden)

//a normal user to delete an app
e.DELETE("/api/v1.0/app/{id}").WithPath("id", 1).WithBasicAuth(andrew_token, "").
Expect().Status(httptest.StatusForbidden)

//an admin user to delete an app
e.DELETE("/api/v1.0/app/{id}").WithPath("id", 1).WithBasicAuth(andrewadmin_token, "").
Expect().Body().Contains("OK")

// anonymous test app_name duplicate checker
e.GET("/api/v1.0/app/duplicate").WithQuery("appname", "华师匣子").
Expect().Status(httptest.StatusForbidden)

// a normal user to test app_name duplicate checker
e.GET("/api/v1.0/app/duplicate").WithQuery("appname", "华师匣子").
WithBasicAuth(andrew_token, "").Expect().Body().NotContains("record not found")

// an admin user to test app_name duplicate checker
e.GET("/api/v1.0/app/duplicate").WithQuery("appname", "木小犀机器人").
WithBasicAuth(andrewadmin_token, "").Expect().Body().Contains("record not found")
}



func TestRecursiveDeleteApp(t *testing.T){
time.Sleep(5*time.Second)
e := httptest.New(t, newApp(), httptest.URL("http://127.0.0.1:8080"))
defer model.DB.RWdb.DropTableIfExists("users")
defer model.DB.RWdb.DropTableIfExists("casbin_rule")
defer model.DB.RWdb.DropTableIfExists("apps")
defer model.DB.RWdb.DropTableIfExists("versions")
defer model.DB.RWdb.DropTableIfExists("services")

CreateUserForTest(e, "andrew", "andrew123", "andrewpqc@mails.ccnu.edu.cn")
CreateAdminForTest(e, "andrewadmin", "andrewadmin123", "3480437308@qq.com")
andrew_token := GetTokenForTest(e, "andrew", "andrew123", 60*60)
andrewadmin_token := GetTokenForTest(e, "andrewadmin", "andrewadmin123", 60*60)

//a normal user to create an app
e.POST("/api/v1.0/app").WithJSON(map[string]interface{}{
"app_name": "学而1",
"app_desc": "华师课程挖掘机",
}).WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

// delete an app which has no service
e.DELETE("/api/v1.0/app/{id}").WithPath("id", 1).WithBasicAuth(andrewadmin_token, "").
Expect().Body().Contains("OK")

time.Sleep(3*time.Second)

//a normal user to create an app
e.POST("/api/v1.0/app").WithJSON(map[string]interface{}{
"app_name": "学而2",
"app_desc": "华师课程挖掘机",
}).WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

// a normal user to create a service
e.POST("/api/v1.0/service").WithJSON(map[string]interface{}{
"app_id": 2,
"svc_name": "xueer_be2",
"svc_desc": "the backend part of xueer",
}).WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

// an admin to create a service
e.POST("/api/v1.0/service").WithJSON(map[string]interface{}{
"app_id": 2,
"svc_name": "xueer_fe2",
"svc_desc": "frontend part of xueer",
}).WithBasicAuth(andrewadmin_token, "").Expect().Body().Contains("OK")

// delete an app which has two services, but there are no versions of each service
e.DELETE("/api/v1.0/app/{id}").WithPath("id", 2).WithBasicAuth(andrewadmin_token, "").
Expect().Body().Contains("OK")

time.Sleep(3*time.Second)

//a normal user to create an app
e.POST("/api/v1.0/app").WithJSON(map[string]interface{}{
"app_name": "学而3",
"app_desc": "华师课程挖掘机",
}).WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

// a normal user to create a service
e.POST("/api/v1.0/service").WithJSON(map[string]interface{}{
"app_id": 3,
"svc_name": "xueer_be3",
"svc_desc": "the backend part of xueer",
}).WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

// an admin to create a service
e.POST("/api/v1.0/service").WithJSON(map[string]interface{}{
"app_id": 3,
"svc_name": "xueer_fe3",
"svc_desc": "frontend part of xueer",
}).WithBasicAuth(andrewadmin_token, "").Expect().Body().Contains("OK")

// create a namespace mae-test-g
e.POST("/api/v1.0/ns/{ns}").WithPath("ns", "mae-test-g").
WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

//create a version which belongs to service xueer_be
e.POST("/api/v1.0/version").WithJSON(map[string]interface{}{
"svc_id": 3,
"version_name": "xueer-be-v1",
"version_desc": "xueer be version 1",
"version_conf": map[string]interface{}{
"deployment": map[string]interface{}{
"deploy_name": "xueer-be-v1-deployment",
"name_space": "mae-test-g",
"replicas": 1,
"labels": map[string]string{"run": "xueer-be"},
"containers": [](map[string]interface{}){
map[string]interface{}{
"ctr_name": "xueer-be-v1-ct",
"image_url": "pqcsdockerhub/kube-test",
"start_cmd": []string{"gunicorn", "app:app", "-b", "0.0.0.0:8080", "--log-level", "DEBUG"},
"ports": [](map[string]interface{}){
map[string]interface{}{
"image_port": 8080,
"target_port": 8090,
"protocol": "TCP",
},
},
},
},
},
"svc": map[string]interface{}{
"svc_name": "xueer-be-v1-service",
"selector": map[string]string{"run": "xueer-be"},
"labels": map[string]string{"run": "xueer-be"},
},
},
}).WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

//apply version "xueer-be-v1"
e.GET("/api/v1.0/version/apply").WithQuery("version_name", "xueer-be-v1").
WithBasicAuth(andrew_token, "").Expect().Body().Contains("OK")

time.Sleep(3*time.Second)

// to recursive delete the app and the service of the app and the versions of the service.
e.DELETE("/api/v1.0/app/{id}").WithPath("id", 3).WithBasicAuth(andrewadmin_token, "").
Expect().Body().Contains("OK")

e.DELETE("/api/v1.0/ns/{ns}").WithPath("ns", "mae-test-g").WithBasicAuth(andrewadmin_token, "").
Expect().Body().Contains("OK")
}
14 changes: 14 additions & 0 deletions conf/casbinmodel.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[request_definition]
r = sub, dom, obj, act

[policy_definition]
p = sub, dom, obj, act

[role_definition]
g = _, _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && regexMatch(r.obj,p.obj) && r.act == p.act
26 changes: 26 additions & 0 deletions conf/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
runmode: debug # 开发模式, debug, release, test
addr: :8080 # HTTP绑定端口
name: mae_apiserver # API Server的名字
url: http://127.0.0.1:8080 # pingServer函数请求的API服务器的ip:port
max_ping_count: 10 # pingServer函数try的次数
jwt_secret: Rtg8BPKNEf2mB4mgvKONGPZZQSaJWNLijxR42qRgq0iBb5
casbinmodel: conf/casbinmodel.conf
kubeconfig: conf/admin.kubeconfig
tls:
addr: :8081
cert: conf/example.com+4.pem
key: conf/example.com+4-key.pem
log:
writers: file
logger_level: DEBUG
logger_file: log/mae.log
log_format_text: true
rollingPolicy: size
log_rotate_date: 1
log_rotate_size: 1
log_backup_count: 7
db:
name: mae
addr: 127.0.0.1:3306
username: root
password: pqc19960320
28 changes: 28 additions & 0 deletions conf/example.com+4-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRwGEphjEL6gOy
EbLZecjc0ieXl1cIAYcesPfcD/YTlj2ObU2ATyCifr6p3UFcR+DYdhTo8jL1ujbe
Q+qDtL5ZN2OtmuKJsGQj24szd3Ld0uMBzUYzFqEJ6z5jMKk49ctMo1TYgkMnc6Y/
YFGwY5XTVjc+A0TK98OYAH5HHKFNpLIXiSWOYaNmlz36QVXXVw3xVwkfSMskCpAf
cgzLR9MH5KcYpZvUjSsIFFAsk6qgV/nseNWz0Y3FirOgMKs3rT+Y9UesvQZRUE/P
7+X0vC4bil+e1uQQreK53sqvHqLAvGBW18B/Hyr5wxGQUCg3QNhq6Bq1/6uph1sp
kz1fxKQ3AgMBAAECggEALPAzoOrgLTZI7mi+Ubu23iCkXOUOv2dcZKXzpJFC3nVs
4MvoM9pAGrBe9xOxQi0gLiA2YKYrZtwrjzkr0GXz9jdYwsQRTwCco9YQn8kysfXR
rvwk0yNBA1gEOMofJ1X55YSE1BIsgxJTBvcC6XCck/e/xCh9H6Mvo6xPYbrvkCua
oOdXIo7Qk5QrsF9XUUBVCsjJCasiYp58zGn3hAQMJDKd/vjhJlBkJiZjHcDOcBcP
AWRsIym03toTYAkQ6icMvn1PlWlbujlWmE5DL5rQsemfwwlE9j+9Atp7bBZhcbep
Zg66Ik7/kte4Afq3/e+cnEj0ddxwrGVnGOzD5mD2eQKBgQDepfq8o6v1Z4+T9Bre
JJmQop7iOIPyKCxLxXhtN3IT92KXITFqn98st+5YYJSHFhxUuew/2dYwb1xTo+ZC
GTKuBXqRNbiEE2o++wuuEhbeu0CJMio8UxGE9Y8ODhMIq/8asGTM6z4MHQ5Y8v4W
fjFfoq/v0SlyE42Sn5O5WxML3QKBgQDxK9YilBIUIGGnbNWKOsvQkodK5uliWcRZ
7A6E1LtTKUDzg3GjMNKhxjFbucQGssXKM2qgiw6ZXZDz9P1cm5JFxkYJyqsmTccg
+UR+hQ8pVIp+zmGAbB4oTIQhqYbluaFpNVVbX6Qwtueu5vdF1k/zFh2k6G4ufD+f
U/punGhJIwKBgQDYFbSsohjBOroxOOdek5zqr7mOCpWcTvr2qvc+4GH6GM15qcBh
IDokF3reERX1qTLj0/IC4jMrnNi5YEeX/QafuDeFeOLUZFdoOpPSZEIH9yoiPSqa
k3BcX0pwtJ4qe2tCBtI9w03bydNj5qlNQTo//A/Oq2wTCAENvYxMh6SLjQKBgQCA
Oht/hRTbqJ/jYeVjuoE1Y0MV2xJJnYrdeLn7fBQhUjTbhI6+Aq5rHzKNH4cPPKwX
JyFRPL5FYs84NpEjVP//oz0H5b77/aybZo05a8u04ONGKrsCifm62XwDXdyAdiNR
Ce9ZRs/IquciQmFEu38Es0SNspsqkhtNvlvPxc9Y2wKBgDKy67pIxKQ1iDFO4448
WyHcbyR9+VWjAYPq6Cmzz4Qt9LpKbL3TuziYiiM15xS9/aGBjsNAg0rzJfZoxGgF
wcJaQSitwsGUtzWw6HIrjGYttiryRp0dxgKmUxIWTVnaOJB/LOqcayXrPsnOK0Gn
oHqmphc5ABcDLxhwPdLkRupL
-----END PRIVATE KEY-----
Loading

0 comments on commit f7b3989

Please sign in to comment.