Add application (#750)
* add schedulercluster to callsystem * update callsystem rest api * add cdncluster for callsystem Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
parent
206b3244c9
commit
06661c3506
3
go.mod
3
go.mod
|
|
@ -3,11 +3,9 @@ module d7y.io/dragonfly/v2
|
|||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/HuKeping/rbtree v0.0.0-20210106022122-8ad34838eb2b
|
||||
github.com/RichardKnop/machinery v1.10.6
|
||||
github.com/VividCortex/mysqlerr v1.0.0
|
||||
github.com/agiledragon/gomonkey v2.0.2+incompatible
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible
|
||||
github.com/appleboy/gin-jwt/v2 v2.6.5-0.20210827121450-79689222c755
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
|
||||
|
|
@ -49,7 +47,6 @@ require (
|
|||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.14.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/pborman/uuid v1.2.1
|
||||
github.com/pelletier/go-toml v1.8.1 // indirect
|
||||
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
|
|
|||
6
go.sum
6
go.sum
|
|
@ -46,8 +46,6 @@ github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW
|
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/HuKeping/rbtree v0.0.0-20210106022122-8ad34838eb2b h1:zDhQxG7rm8RLgLgi6NpfaVFsop+zxw5hwhbzHr624us=
|
||||
github.com/HuKeping/rbtree v0.0.0-20210106022122-8ad34838eb2b/go.mod h1:bODsl3NElqKlgf1UkBLj67fYmY5DsqkKrrYm/kMT/6Y=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
|
|
@ -70,7 +68,6 @@ github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3
|
|||
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
|
|
@ -382,7 +379,6 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
|
|
@ -667,8 +663,6 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+
|
|||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/getopt v0.0.0-20180729010549-6fdd0a2c7117/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
||||
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
|
||||
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ func migrate(db *gorm.DB) error {
|
|||
&model.User{},
|
||||
&model.Oauth{},
|
||||
&model.Config{},
|
||||
&model.Application{},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* Copyright 2020 The Dragonfly Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
// nolint
|
||||
_ "d7y.io/dragonfly/v2/manager/model"
|
||||
"d7y.io/dragonfly/v2/manager/types"
|
||||
)
|
||||
|
||||
// @Summary Create Application
|
||||
// @Description create by json config
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Application body types.CreateApplicationRequest true "Application"
|
||||
// @Success 200 {object} model.Application
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications [post]
|
||||
func (h *Handlers) CreateApplication(ctx *gin.Context) {
|
||||
var json types.CreateApplicationRequest
|
||||
if err := ctx.ShouldBindJSON(&json); err != nil {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
application, err := h.service.CreateApplication(ctx.Request.Context(), json)
|
||||
if err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, application)
|
||||
}
|
||||
|
||||
// @Summary Destroy Application
|
||||
// @Description Destroy by id
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Success 200
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications/{id} [delete]
|
||||
func (h *Handlers) DestroyApplication(ctx *gin.Context) {
|
||||
var params types.ApplicationParams
|
||||
if err := ctx.ShouldBindUri(¶ms); err != nil {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.DestroyApplication(ctx.Request.Context(), params.ID); err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
// @Summary Update Application
|
||||
// @Description Update by json config
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param Application body types.UpdateApplicationRequest true "Application"
|
||||
// @Success 200 {object} model.Application
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications/{id} [patch]
|
||||
func (h *Handlers) UpdateApplication(ctx *gin.Context) {
|
||||
var params types.ApplicationParams
|
||||
if err := ctx.ShouldBindUri(¶ms); err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
var json types.UpdateApplicationRequest
|
||||
if err := ctx.ShouldBindJSON(&json); err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
application, err := h.service.UpdateApplication(ctx.Request.Context(), params.ID, json)
|
||||
if err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, application)
|
||||
}
|
||||
|
||||
// @Summary Get Application
|
||||
// @Description Get Application by id
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Success 200 {object} model.Application
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications/{id} [get]
|
||||
func (h *Handlers) GetApplication(ctx *gin.Context) {
|
||||
var params types.ApplicationParams
|
||||
if err := ctx.ShouldBindUri(¶ms); err != nil {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
application, err := h.service.GetApplication(ctx.Request.Context(), params.ID)
|
||||
if err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, application)
|
||||
}
|
||||
|
||||
// @Summary Get Applications
|
||||
// @Description Get Applications
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int true "current page" default(0)
|
||||
// @Param per_page query int true "return max item count, default 10, max 50" default(10) minimum(2) maximum(50)
|
||||
// @Success 200 {object} []model.Application
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications [get]
|
||||
func (h *Handlers) GetApplications(ctx *gin.Context) {
|
||||
var query types.GetApplicationsQuery
|
||||
if err := ctx.ShouldBindQuery(&query); err != nil {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
h.setPaginationDefault(&query.Page, &query.PerPage)
|
||||
applications, count, err := h.service.GetApplications(ctx.Request.Context(), query)
|
||||
if err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
h.setPaginationLinkHeader(ctx, query.Page, query.PerPage, int(count))
|
||||
ctx.JSON(http.StatusOK, applications)
|
||||
}
|
||||
|
||||
// @Summary Add Scheduler to Application
|
||||
// @Description Add Scheduler to Application
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param scheduler_cluster_id path string true "scheduler cluster id"
|
||||
// @Success 200
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications/{id}/scheduler-clusters/{scheduler_cluster_id} [put]
|
||||
func (h *Handlers) AddSchedulerClusterToApplication(ctx *gin.Context) {
|
||||
var params types.AddSchedulerClusterToApplicationParams
|
||||
if err := ctx.ShouldBindUri(¶ms); err != nil {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.AddSchedulerClusterToApplication(ctx.Request.Context(), params.ID, params.SchedulerClusterID); err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
// @Summary Delete Scheduler to Application
|
||||
// @Description Delete Scheduler to Application
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param scheduler_cluster_id path string true "scheduler cluster id"
|
||||
// @Success 200
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications/{id}/scheduler-clusters/{scheduler_cluster_id} [delete]
|
||||
func (h *Handlers) DeleteSchedulerClusterToApplication(ctx *gin.Context) {
|
||||
var params types.DeleteSchedulerClusterToApplicationParams
|
||||
if err := ctx.ShouldBindUri(¶ms); err != nil {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.DeleteSchedulerClusterToApplication(ctx.Request.Context(), params.ID, params.SchedulerClusterID); err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
// @Summary Add CDN to Application
|
||||
// @Description Add CDN to Application
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param cdn_cluster_id path string true "cdn cluster id"
|
||||
// @Success 200
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications/{id}/cdn-clusters/{cdn_cluster_id} [put]
|
||||
func (h *Handlers) AddCDNClusterToApplication(ctx *gin.Context) {
|
||||
var params types.AddCDNClusterToApplicationParams
|
||||
if err := ctx.ShouldBindUri(¶ms); err != nil {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.AddCDNClusterToApplication(ctx.Request.Context(), params.ID, params.CDNClusterID); err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
// @Summary Delete CDN to Application
|
||||
// @Description Delete CDN to Application
|
||||
// @Tags Application
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "id"
|
||||
// @Param cdn_cluster_id path string true "cdn cluster id"
|
||||
// @Success 200
|
||||
// @Failure 400
|
||||
// @Failure 404
|
||||
// @Failure 500
|
||||
// @Router /applications/{id}/cdn-clusters/{cdn_cluster_id} [delete]
|
||||
func (h *Handlers) DeleteCDNClusterToApplication(ctx *gin.Context) {
|
||||
var params types.DeleteCDNClusterToApplicationParams
|
||||
if err := ctx.ShouldBindUri(¶ms); err != nil {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.DeleteCDNClusterToApplication(ctx.Request.Context(), params.ID, params.CDNClusterID); err != nil {
|
||||
ctx.Error(err) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2020 The Dragonfly Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
type Application struct {
|
||||
Model
|
||||
Name string `gorm:"column:name;type:varchar(256);index:uk_application_name,unique;not null;comment:name" json:"name"`
|
||||
DownloadRateLimit string `gorm:"column:download_rate_limit;type:varchar(1024);comment:download_rate_limit" json:"download_rate_limit"`
|
||||
URL string `gorm:"column:url;not null;comment:url" json:"url"`
|
||||
State string `gorm:"column:state;type:varchar(256);default:'enable';comment:state" json:"state"`
|
||||
BIO string `gorm:"column:bio;type:varchar(1024);comment:biography" json:"bio"`
|
||||
UserID uint `gorm:"comment:user id" json:"user_id"`
|
||||
SchedulerClusters []SchedulerCluster `json:"-"`
|
||||
CDNClusters []CDNCluster `json:"-"`
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ type CDNCluster struct {
|
|||
IsDefault bool `gorm:"column:is_default;not null;default:false;comment:default cdn cluster" json:"is_default"`
|
||||
CDNs []CDN `json:"-"`
|
||||
SecurityGroupID uint `gorm:"comment:security group id" json:"security_group_id"`
|
||||
ApplicationID uint `gorm:"comment:application id" json:"application_id"`
|
||||
SecurityGroup SecurityGroup `json:"-"`
|
||||
Jobs []Job `gorm:"many2many:job_cdn_cluster;" json:"jobs"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ func Paginate(page, perPage int) func(db *gorm.DB) *gorm.DB {
|
|||
}
|
||||
}
|
||||
|
||||
type JSONMap map[string]interface{}
|
||||
type (
|
||||
JSONMap map[string]interface{}
|
||||
Array []string
|
||||
)
|
||||
|
||||
func (m JSONMap) Value() (driver.Value, error) {
|
||||
if m == nil {
|
||||
|
|
@ -52,6 +55,14 @@ func (m JSONMap) Value() (driver.Value, error) {
|
|||
return string(ba), err
|
||||
}
|
||||
|
||||
func (a Array) Value() (driver.Value, error) {
|
||||
if a == nil {
|
||||
return nil, nil
|
||||
}
|
||||
ba, err := a.MarshalJSON()
|
||||
return string(ba), err
|
||||
}
|
||||
|
||||
func (m *JSONMap) Scan(val interface{}) error {
|
||||
var ba []byte
|
||||
switch v := val.(type) {
|
||||
|
|
@ -68,6 +79,22 @@ func (m *JSONMap) Scan(val interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (a *Array) Scan(val interface{}) error {
|
||||
var ba []byte
|
||||
switch v := val.(type) {
|
||||
case []byte:
|
||||
ba = v
|
||||
case string:
|
||||
ba = []byte(v)
|
||||
default:
|
||||
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", val))
|
||||
}
|
||||
t := []string{}
|
||||
err := json.Unmarshal(ba, &t)
|
||||
*a = Array(t)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m JSONMap) MarshalJSON() ([]byte, error) {
|
||||
if m == nil {
|
||||
return []byte("null"), nil
|
||||
|
|
@ -76,6 +103,14 @@ func (m JSONMap) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(t)
|
||||
}
|
||||
|
||||
func (a Array) MarshalJSON() ([]byte, error) {
|
||||
if a == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
t := ([]string)(a)
|
||||
return json.Marshal(t)
|
||||
}
|
||||
|
||||
func (m *JSONMap) UnmarshalJSON(b []byte) error {
|
||||
t := map[string]interface{}{}
|
||||
err := json.Unmarshal(b, &t)
|
||||
|
|
@ -83,6 +118,13 @@ func (m *JSONMap) UnmarshalJSON(b []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (a *Array) UnmarshalJSON(b []byte) error {
|
||||
t := []string{}
|
||||
err := json.Unmarshal(b, &t)
|
||||
*a = Array(t)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m JSONMap) GormDataType() string {
|
||||
return "jsonmap"
|
||||
}
|
||||
|
|
@ -90,3 +132,11 @@ func (m JSONMap) GormDataType() string {
|
|||
func (JSONMap) GormDBDataType(db *gorm.DB, field *schema.Field) string {
|
||||
return "text"
|
||||
}
|
||||
|
||||
func (Array) GormDataType() string {
|
||||
return "array"
|
||||
}
|
||||
|
||||
func (Array) GormDBDataType(db *gorm.DB, field *schema.Field) string {
|
||||
return "text"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,4 +29,5 @@ type SchedulerCluster struct {
|
|||
SecurityGroupID uint `gorm:"comment:security group id" json:"security_group_id"`
|
||||
SecurityGroup SecurityGroup `json:"-"`
|
||||
Jobs []Job `gorm:"many2many:job_scheduler_cluster;" json:"jobs"`
|
||||
ApplicationID uint `gorm:"comment:application id" json:"application_id"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,7 @@ const (
|
|||
OtelServiceName = "dragonfly-manager"
|
||||
)
|
||||
|
||||
var (
|
||||
GinLogFileName = "gin.log"
|
||||
)
|
||||
var GinLogFileName = "gin.log"
|
||||
|
||||
func Init(cfg *config.Config, service service.REST, enforcer *casbin.Enforcer) (*gin.Engine, error) {
|
||||
// Set mode
|
||||
|
|
@ -147,6 +145,18 @@ func Init(cfg *config.Config, service service.REST, enforcer *casbin.Enforcer) (
|
|||
s.GET(":id", h.GetScheduler)
|
||||
s.GET("", h.GetSchedulers)
|
||||
|
||||
// Application
|
||||
cs := apiv1.Group("/applications", jwt.MiddlewareFunc(), rbac)
|
||||
cs.POST("", h.CreateApplication)
|
||||
cs.DELETE(":id", h.DestroyApplication)
|
||||
cs.PATCH(":id", h.UpdateApplication)
|
||||
cs.GET(":id", h.GetApplication)
|
||||
cs.GET("", h.GetApplications)
|
||||
cs.PUT(":id/scheduler-clusters/:scheduler_cluster_id", h.AddSchedulerClusterToApplication)
|
||||
cs.DELETE(":id/scheduler-clusters/:scheduler_cluster_id", h.DeleteSchedulerClusterToApplication)
|
||||
cs.PUT(":id/cdn-clusters/:cdn_cluster_id", h.AddCDNClusterToApplication)
|
||||
cs.DELETE(":id/cdn-clusters/:cdn_cluster_id", h.DeleteCDNClusterToApplication)
|
||||
|
||||
// CDN Cluster
|
||||
cc := apiv1.Group("/cdn-clusters", jwt.MiddlewareFunc(), rbac)
|
||||
cc.POST("", h.CreateCDNCluster)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright 2020 The Dragonfly Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"d7y.io/dragonfly/v2/manager/model"
|
||||
"d7y.io/dragonfly/v2/manager/types"
|
||||
)
|
||||
|
||||
func (s *rest) CreateApplication(ctx context.Context, json types.CreateApplicationRequest) (*model.Application, error) {
|
||||
application := model.Application{
|
||||
Name: json.Name,
|
||||
DownloadRateLimit: json.DownloadRateLimit,
|
||||
URL: json.URL,
|
||||
UserID: json.UserID,
|
||||
BIO: json.BIO,
|
||||
State: json.State,
|
||||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Create(&application).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &application, nil
|
||||
}
|
||||
|
||||
func (s *rest) DestroyApplication(ctx context.Context, id uint) error {
|
||||
application := model.Application{}
|
||||
if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Unscoped().Delete(&model.Application{}, id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *rest) UpdateApplication(ctx context.Context, id uint, json types.UpdateApplicationRequest) (*model.Application, error) {
|
||||
application := model.Application{}
|
||||
if err := s.db.WithContext(ctx).First(&application, id).Updates(model.Application{
|
||||
Name: json.Name,
|
||||
DownloadRateLimit: json.DownloadRateLimit,
|
||||
URL: json.URL,
|
||||
State: json.State,
|
||||
BIO: json.BIO,
|
||||
UserID: json.UserID,
|
||||
}).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &application, nil
|
||||
}
|
||||
|
||||
func (s *rest) GetApplication(ctx context.Context, id uint) (*model.Application, error) {
|
||||
application := model.Application{}
|
||||
if err := s.db.WithContext(ctx).Preload("SchedulerClusters").First(&application, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &application, nil
|
||||
}
|
||||
|
||||
func (s *rest) GetApplications(ctx context.Context, q types.GetApplicationsQuery) (*[]model.Application, int64, error) {
|
||||
var count int64
|
||||
applications := []model.Application{}
|
||||
if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Preload("SchedulerClusters").Find(&applications).Count(&count).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return &applications, count, nil
|
||||
}
|
||||
|
||||
func (s *rest) AddSchedulerClusterToApplication(ctx context.Context, id, schedulerClusterID uint) error {
|
||||
application := model.Application{}
|
||||
if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
schedulerCluster := model.SchedulerCluster{}
|
||||
if err := s.db.WithContext(ctx).First(&schedulerCluster, schedulerClusterID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Model(&application).Association("SchedulerClusters").Append(&schedulerCluster); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *rest) DeleteSchedulerClusterToApplication(ctx context.Context, id, schedulerClusterID uint) error {
|
||||
application := model.Application{}
|
||||
if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
schedulerCluster := model.SchedulerCluster{}
|
||||
if err := s.db.WithContext(ctx).First(&schedulerCluster, schedulerClusterID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.db.Model(&application).Association("SchedulerClusters").Delete(&schedulerCluster); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *rest) AddCDNClusterToApplication(ctx context.Context, id, cdnClusterID uint) error {
|
||||
application := model.Application{}
|
||||
if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cdnCluster := model.CDNCluster{}
|
||||
if err := s.db.WithContext(ctx).First(&cdnCluster, cdnClusterID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Model(&application).Association("CDNClusters").Append(&cdnCluster); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *rest) DeleteCDNClusterToApplication(ctx context.Context, id, cdnClusterID uint) error {
|
||||
application := model.Application{}
|
||||
if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cdnCluster := model.CDNCluster{}
|
||||
if err := s.db.WithContext(ctx).First(&cdnCluster, cdnClusterID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.db.Model(&application).Association("CDNClusters").Delete(&cdnCluster); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -116,6 +116,16 @@ type REST interface {
|
|||
|
||||
CreateV1Preheat(context.Context, types.CreateV1PreheatRequest) (*types.CreateV1PreheatResponse, error)
|
||||
GetV1Preheat(context.Context, string) (*types.GetV1PreheatResponse, error)
|
||||
|
||||
CreateApplication(context.Context, types.CreateApplicationRequest) (*model.Application, error)
|
||||
DestroyApplication(context.Context, uint) error
|
||||
UpdateApplication(context.Context, uint, types.UpdateApplicationRequest) (*model.Application, error)
|
||||
GetApplication(context.Context, uint) (*model.Application, error)
|
||||
GetApplications(context.Context, types.GetApplicationsQuery) (*[]model.Application, int64, error)
|
||||
AddSchedulerClusterToApplication(context.Context, uint, uint) error
|
||||
DeleteSchedulerClusterToApplication(context.Context, uint, uint) error
|
||||
AddCDNClusterToApplication(context.Context, uint, uint) error
|
||||
DeleteCDNClusterToApplication(context.Context, uint, uint) error
|
||||
}
|
||||
|
||||
type rest struct {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2020 The Dragonfly Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package types
|
||||
|
||||
type ApplicationParams struct {
|
||||
ID uint `uri:"id" binding:"required"`
|
||||
}
|
||||
|
||||
type AddSchedulerClusterToApplicationParams struct {
|
||||
ID uint `uri:"id" binding:"required"`
|
||||
SchedulerClusterID uint `uri:"scheduler_cluster_id" binding:"required"`
|
||||
}
|
||||
|
||||
type DeleteSchedulerClusterToApplicationParams struct {
|
||||
ID uint `uri:"id" binding:"required"`
|
||||
SchedulerClusterID uint `uri:"scheduler_cluster_id" binding:"required"`
|
||||
}
|
||||
|
||||
type AddCDNClusterToApplicationParams struct {
|
||||
ID uint `uri:"id" binding:"required"`
|
||||
CDNClusterID uint `uri:"cdn_cluster_id" binding:"required"`
|
||||
}
|
||||
|
||||
type DeleteCDNClusterToApplicationParams struct {
|
||||
ID uint `uri:"id" binding:"required"`
|
||||
CDNClusterID uint `uri:"cdn_cluster_id" binding:"required"`
|
||||
}
|
||||
|
||||
type CreateApplicationRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
DownloadRateLimit string `json:"download_rate_limit" binding:"omitempty"`
|
||||
URL string `json:"url" binding:"omitempty"`
|
||||
BIO string `json:"bio" binding:"omitempty"`
|
||||
UserID uint `json:"user_id" binding:"omitempty"`
|
||||
State string `json:"state" binding:"required,oneof=enable disable"`
|
||||
}
|
||||
|
||||
type UpdateApplicationRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
DownloadRateLimit string `json:"download_rate_limit" binding:"required"`
|
||||
URL string `json:"url" binding:"required"`
|
||||
State string `json:"state" binding:"required,oneof=enable disable"`
|
||||
BIO string `json:"bio" binding:"omitempty"`
|
||||
UserID uint `json:"user_id" binding:"omitempty"`
|
||||
}
|
||||
|
||||
type GetApplicationsQuery struct {
|
||||
Page int `form:"page" binding:"omitempty,gte=1"`
|
||||
PerPage int `form:"per_page" binding:"omitempty,gte=1,lte=50"`
|
||||
}
|
||||
Loading…
Reference in New Issue