diff --git a/server/controller/cloud/aliyun/aliyun.go b/server/controller/cloud/aliyun/aliyun.go index 9a36b9a0646..9d141118822 100644 --- a/server/controller/cloud/aliyun/aliyun.go +++ b/server/controller/cloud/aliyun/aliyun.go @@ -37,6 +37,7 @@ var log = logging.MustGetLogger("cloud.aliyun") type Aliyun struct { orgID int + teamID int uuid string uuidGenerate string regionUuid string @@ -93,8 +94,9 @@ func NewAliyun(orgID int, domain mysql.Domain, cfg cloudconfig.CloudConfig) (*Al } return &Aliyun{ - orgID: orgID, - uuid: domain.Lcuuid, + orgID: orgID, + teamID: domain.TeamID, + uuid: domain.Lcuuid, // TODO: display_name后期需要修改为uuid_generate uuidGenerate: domain.DisplayName, regionUuid: config.Get("region_uuid").MustString(), diff --git a/server/controller/cloud/aliyun/sub_domain.go b/server/controller/cloud/aliyun/sub_domain.go index d53bfa9f81b..5349e21a06f 100644 --- a/server/controller/cloud/aliyun/sub_domain.go +++ b/server/controller/cloud/aliyun/sub_domain.go @@ -55,6 +55,7 @@ func (a *Aliyun) getSubDomains(region model.Region) ([]model.SubDomain, error) { } configJson, _ := json.Marshal(config) retSubDomains = append(retSubDomains, model.SubDomain{ + TeamID: a.teamID, Lcuuid: common.GenerateUUIDByOrgID(a.orgID, clusterID), Name: cluster.Get("name").MustString(), DisplayName: clusterID, diff --git a/server/controller/cloud/aws/aws.go b/server/controller/cloud/aws/aws.go index 9c66f418414..081224299ef 100644 --- a/server/controller/cloud/aws/aws.go +++ b/server/controller/cloud/aws/aws.go @@ -44,6 +44,7 @@ const ( type Aws struct { orgID int + teamID int name string lcuuid string regionUUID string @@ -117,6 +118,7 @@ func NewAws(orgID int, domain mysql.Domain, cfg cloudconfig.CloudConfig) (*Aws, return &Aws{ // TODO: display_name后期需要修改为uuid_generate orgID: orgID, + teamID: domain.TeamID, name: domain.Name, lcuuid: domain.Lcuuid, uuidGenerate: domain.DisplayName, diff --git a/server/controller/cloud/aws/sub_domain.go b/server/controller/cloud/aws/sub_domain.go index 3e3762765d4..fc8505ac94a 100644 --- a/server/controller/cloud/aws/sub_domain.go +++ b/server/controller/cloud/aws/sub_domain.go @@ -80,6 +80,7 @@ func (a *Aws) getSubDomains(region awsRegion) ([]model.SubDomain, error) { } configJson, _ := json.Marshal(config) retSubDomains = append(retSubDomains, model.SubDomain{ + TeamID: a.teamID, Lcuuid: common.GetUUIDByOrgID(a.orgID, name), Name: name, DisplayName: name, diff --git a/server/controller/cloud/baidubce/sub_domain.go b/server/controller/cloud/baidubce/sub_domain.go index 0080a0b5adf..827338b9276 100644 --- a/server/controller/cloud/baidubce/sub_domain.go +++ b/server/controller/cloud/baidubce/sub_domain.go @@ -72,6 +72,7 @@ func (b *BaiduBce) getSubDomains(region model.Region, vpcIdToLcuuid map[string]s } configJson, _ := json.Marshal(config) retSubDomains = append(retSubDomains, model.SubDomain{ + TeamID: b.teamID, Lcuuid: common.GenerateUUIDByOrgID(b.orgID, cluster.ClusterUuid), Name: cluster.ClusterName, DisplayName: cluster.ClusterUuid, diff --git a/server/controller/cloud/kubernetes_gather/kubernetes_gather.go b/server/controller/cloud/kubernetes_gather/kubernetes_gather.go index b5af31e9509..38b6effb405 100644 --- a/server/controller/cloud/kubernetes_gather/kubernetes_gather.go +++ b/server/controller/cloud/kubernetes_gather/kubernetes_gather.go @@ -102,6 +102,7 @@ func NewKubernetesGather(db *mysql.DB, domain *mysql.Domain, subDomain *mysql.Su log.Error("subdomain model is nil") return nil } + teamID = subDomain.TeamID name = subDomain.Name lcuuid = subDomain.Lcuuid displayName = subDomain.DisplayName diff --git a/server/controller/cloud/model/model.go b/server/controller/cloud/model/model.go index 6c4d25a4318..60e314f2bf3 100644 --- a/server/controller/cloud/model/model.go +++ b/server/controller/cloud/model/model.go @@ -319,6 +319,7 @@ type RDSInstance struct { } type SubDomain struct { + TeamID int `json:"team_id" binding:"required"` Lcuuid string `json:"lcuuid" binding:"required"` Name string `json:"name" binding:"required"` DisplayName string `json:"display_name" binding:"required"` diff --git a/server/controller/cloud/qingcloud/sub_domain.go b/server/controller/cloud/qingcloud/sub_domain.go index 8342c630c5a..0c12d0bcfa2 100644 --- a/server/controller/cloud/qingcloud/sub_domain.go +++ b/server/controller/cloud/qingcloud/sub_domain.go @@ -72,6 +72,7 @@ func (q *QingCloud) GetSubDomains() ([]model.SubDomain, error) { } configJson, _ := json.Marshal(config) retSubDomains = append(retSubDomains, model.SubDomain{ + TeamID: q.teamID, Lcuuid: common.GenerateUUIDByOrgID(q.orgID, clusterId), Name: cluster.Get("name").MustString(), DisplayName: clusterId, diff --git a/server/controller/common/const.go b/server/controller/common/const.go index 6b4ed1c965c..a48f338f0fd 100644 --- a/server/controller/common/const.go +++ b/server/controller/common/const.go @@ -30,6 +30,7 @@ const ( DEFAULT_USER_TYPE = 1 DEFAULT_USER_ID = 1 DEFAULT_TEAM_ID = 1 + DEFAULT_APP_KEY = "8c434f9a48bf1b7e729bde006e0409f8" ORG_ID_MAX = 1024 ) @@ -683,4 +684,10 @@ const ( INGESTER_BODY_ORG_ID = "org-id" HEADER_KEY_X_USER_TYPE = "X-User-Type" HEADER_KEY_X_USER_ID = "X-User-Id" + HEADER_X_APP_KEY = "X-App-Key" +) + +const ( + SET_RESOURCE_TYPE_DOMAIN = "domain" + SET_RESOURCE_TYPE_SUB_DOMAIN = "sub_domain" ) diff --git a/server/controller/db/mysql/migration/rawsql/init.sql b/server/controller/db/mysql/migration/rawsql/init.sql index 84dd4480aef..2400fbcc2e3 100644 --- a/server/controller/db/mysql/migration/rawsql/init.sql +++ b/server/controller/db/mysql/migration/rawsql/init.sql @@ -450,6 +450,7 @@ INSERT INTO az (id, name, lcuuid, region, domain) values(1, '系统默认', 'fff CREATE TABLE IF NOT EXISTS domain ( id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, team_id INTEGER DEFAULT 1, + user_id INTEGER DEFAULT 1, name VARCHAR(64), icon_id INTEGER, display_name VARCHAR(64) DEFAULT '', @@ -473,6 +474,7 @@ TRUNCATE TABLE domain; CREATE TABLE IF NOT EXISTS sub_domain ( id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, + team_id INTEGER DEFAULT 1, domain CHAR(64) DEFAULT '', name VARCHAR(64) DEFAULT '', display_name VARCHAR(64) DEFAULT '', diff --git a/server/controller/db/mysql/migration/rawsql/issu/6.5.1.32.sql b/server/controller/db/mysql/migration/rawsql/issu/6.5.1.32.sql new file mode 100644 index 00000000000..d2521b583bd --- /dev/null +++ b/server/controller/db/mysql/migration/rawsql/issu/6.5.1.32.sql @@ -0,0 +1,36 @@ +-- modify start, add upgrade sql +DROP PROCEDURE IF EXISTS AddColumnIfNotExists; + +CREATE PROCEDURE AddColumnIfNotExists( + IN tableName VARCHAR(255), + IN colName VARCHAR(255), + IN afterCol VARCHAR(255) +) +BEGIN + DECLARE column_count INT; + + -- 检查列是否存在 + SELECT COUNT(*) + INTO column_count + FROM information_schema.columns + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = tableName + AND column_name = colName; + + -- 如果列不存在,则添加列 + IF column_count = 0 THEN + SET @sql = CONCAT('ALTER TABLE ', tableName, ' ADD COLUMN ', colName, ' INTEGER DEFAULT 1 AFTER ', afterCol); + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + END IF; +END; + +CALL AddColumnIfNotExists('domain', 'user_id', 'team_id'); +CALL AddColumnIfNotExists('sub_domain', 'team_id', 'id'); + +DROP PROCEDURE AddColumnIfNotExists; + +-- update db_version to latest, remeber update DB_VERSION_EXPECT in migrate/init.go +UPDATE db_version SET version='6.5.1.32'; +-- modify end diff --git a/server/controller/db/mysql/migration/version.go b/server/controller/db/mysql/migration/version.go index e6b0d4f429e..7a5a5803bd4 100644 --- a/server/controller/db/mysql/migration/version.go +++ b/server/controller/db/mysql/migration/version.go @@ -18,5 +18,5 @@ package migration const ( DB_VERSION_TABLE = "db_version" - DB_VERSION_EXPECTED = "6.5.1.31" + DB_VERSION_EXPECTED = "6.5.1.32" ) diff --git a/server/controller/db/mysql/platform_rsc_model.go b/server/controller/db/mysql/platform_rsc_model.go index fa26f936699..f93a329683f 100644 --- a/server/controller/db/mysql/platform_rsc_model.go +++ b/server/controller/db/mysql/platform_rsc_model.go @@ -93,6 +93,7 @@ type Domain struct { OperatedTime `gorm:"embedded" mapstructure:",squash"` SyncedAt *time.Time `gorm:"column:synced_at" json:"SYNCED_AT" mapstructure:"SYNCED_AT"` TeamID int `gorm:"column:team_id;type:int;default:1" json:"TEAM_ID" mapstructure:"TEAM_ID"` + UserID int `gorm:"column:user_id;type:int;default:1" json:"USER_ID" mapstructure:"USER_ID"` Name string `gorm:"column:name;type:varchar(64)" json:"NAME" mapstructure:"NAME"` IconID int `gorm:"column:icon_id;type:int" json:"ICON_ID" mapstructure:"ICON_ID"` DisplayName string `gorm:"column:display_name;type:varchar(64);default:''" json:"DISPLAY_NAME" mapstructure:"DISPLAY_NAME"` @@ -110,6 +111,7 @@ type Domain struct { type SubDomain struct { Base `gorm:"embedded" mapstructure:",squash"` OperatedTime `gorm:"embedded" mapstructure:",squash"` + TeamID int `gorm:"column:team_id;type:int;default:1" json:"TEAM_ID" mapstructure:"TEAM_ID"` SyncedAt *time.Time `gorm:"column:synced_at" json:"SYNCED_AT" mapstructure:"SYNCED_AT"` Domain string `gorm:"column:domain;type:char(64);default:''" json:"DOMAIN" mapstructure:"DOMAIN"` Name string `gorm:"column:name;type:varchar(64);default:''" json:"NAME" mapstructure:"NAME"` diff --git a/server/controller/http/common/const.go b/server/controller/http/common/const.go index cb77d72aeb9..57cde4cf938 100644 --- a/server/controller/http/common/const.go +++ b/server/controller/http/common/const.go @@ -34,6 +34,8 @@ const ( GET_ORG_DB_FAIL = "GET_ORG_DB_FAIL" K8S_SET_VTAP_FAIL = "K8S_SET_VTAP_FAIL" ORG_ID_INVALID = "ORG_ID_INVALID" + CHECK_SCOPE_TEAMS_FAIL = "CHECK_SCOPE_TEAMS_FAIL" + SET_RESOUORCE_FAIL = "SET_RESOUORCE_FAIL" // http status codes STATUES_PARTIAL_CONTENT = "STATUES_PARTIAL_CONTENT" // 206 diff --git a/server/controller/http/router/resource/domain.go b/server/controller/http/router/resource/domain.go index 34927c03f52..c20dc29eacc 100644 --- a/server/controller/http/router/resource/domain.go +++ b/server/controller/http/router/resource/domain.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "net/url" + "strconv" "strings" "github.com/gin-gonic/gin" @@ -31,6 +32,7 @@ import ( "github.com/deepflowio/deepflow/server/controller/config" httpcommon "github.com/deepflowio/deepflow/server/controller/http/common" "github.com/deepflowio/deepflow/server/controller/http/router/common" + svc "github.com/deepflowio/deepflow/server/controller/http/service" "github.com/deepflowio/deepflow/server/controller/http/service/resource" "github.com/deepflowio/deepflow/server/controller/model" ) @@ -48,18 +50,18 @@ func NewDomain(cfg *config.ControllerConfig) *Domain { // TODO: 后续通过header中携带的用户信息校验用户权限 func (d *Domain) RegisterTo(e *gin.Engine) { // TODO: 后续统一为v2 - e.GET("/v2/domains/:lcuuid/", getDomain) - e.GET("/v2/domains/", getDomains) + e.GET("/v2/domains/:lcuuid/", getDomain(d.cfg)) + e.GET("/v2/domains/", getDomains(d.cfg)) e.POST("/v1/domains/", createDomain(d.cfg)) e.PATCH("/v1/domains/:lcuuid/", updateDomain(d.cfg)) - e.DELETE("/v1/domains/:name-or-uuid/", deleteDomainByNameOrUUID) - e.DELETE("/v1/domains/", deleteDomainByName) + e.DELETE("/v1/domains/:name-or-uuid/", deleteDomainByNameOrUUID(d.cfg)) + e.DELETE("/v1/domains/", deleteDomainByName(d.cfg)) - e.GET("/v2/sub-domains/:lcuuid/", getSubDomain) - e.GET("/v2/sub-domains/", getSubDomains) - e.POST("/v2/sub-domains/", createSubDomain) - e.PATCH("/v2/sub-domains/:lcuuid/", updateSubDomain) - e.DELETE("/v2/sub-domains/:lcuuid/", deleteSubDomain) + e.GET("/v2/sub-domains/:lcuuid/", getSubDomain(d.cfg)) + e.GET("/v2/sub-domains/", getSubDomains(d.cfg)) + e.POST("/v2/sub-domains/", createSubDomain(d.cfg)) + e.PATCH("/v2/sub-domains/:lcuuid/", updateSubDomain(d.cfg)) + e.DELETE("/v2/sub-domains/:lcuuid/", deleteSubDomain(d.cfg)) e.PUT("/v1/domain-additional-resources/", applyDomainAddtionalResource) e.GET("/v1/domain-additional-resources/", listDomainAddtionalResource) @@ -68,28 +70,76 @@ func (d *Domain) RegisterTo(e *gin.Engine) { e.GET("/v1/domain-additional-resources/advanced/", getDomainAddtionalResourceAdvanced) } -func getDomain(c *gin.Context) { - args := make(map[string]interface{}) - args["lcuuid"] = c.Param("lcuuid") - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } - data, err := resource.GetDomains(db, args) - common.JsonResponse(c, data, err) +func getDomain(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + args := make(map[string]interface{}) + args["lcuuid"] = c.Param("lcuuid") + if uValue, ok := c.GetQuery("user_id"); ok { + userID, err := strconv.Atoi(uValue) + if err != nil { + common.BadRequestResponse(c, httpcommon.INVALID_PARAMETERS, err.Error()) + } + args["user_id"] = userID + } + if tValue, ok := c.GetQuery("team_id"); ok { + teamID, err := strconv.Atoi(tValue) + if err != nil { + common.BadRequestResponse(c, httpcommon.INVALID_PARAMETERS, err.Error()) + } + args["team_id"] = teamID + } + db, err := common.GetContextOrgDB(c) + if err != nil { + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) + } + excludeTeamIDs := []int{} + teamIDs, err := svc.GetUnauthorizedTeamIDs(svc.GetUserInfo(c), &cfg.FPermit) + if err != nil { + common.BadRequestResponse(c, httpcommon.CHECK_SCOPE_TEAMS_FAIL, err.Error()) + } + for k := range teamIDs { + excludeTeamIDs = append(excludeTeamIDs, k) + } + data, err := resource.GetDomains(db, excludeTeamIDs, args) + common.JsonResponse(c, data, err) + }) } -func getDomains(c *gin.Context) { - args := make(map[string]interface{}) - if value, ok := c.GetQuery("name"); ok { - args["name"] = value - } - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } - data, err := resource.GetDomains(db, args) - common.JsonResponse(c, data, err) +func getDomains(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + args := make(map[string]interface{}) + if value, ok := c.GetQuery("name"); ok { + args["name"] = value + } + if uValue, ok := c.GetQuery("user_id"); ok { + userID, err := strconv.Atoi(uValue) + if err != nil { + common.BadRequestResponse(c, httpcommon.INVALID_PARAMETERS, err.Error()) + } + args["user_id"] = userID + } + if tValue, ok := c.GetQuery("team_id"); ok { + teamID, err := strconv.Atoi(tValue) + if err != nil { + common.BadRequestResponse(c, httpcommon.INVALID_PARAMETERS, err.Error()) + } + args["team_id"] = teamID + } + db, err := common.GetContextOrgDB(c) + if err != nil { + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) + } + excludeTeamIDs := []int{} + teamIDs, err := svc.GetUnauthorizedTeamIDs(svc.GetUserInfo(c), &cfg.FPermit) + if err != nil { + common.BadRequestResponse(c, httpcommon.CHECK_SCOPE_TEAMS_FAIL, err.Error()) + } + for k := range teamIDs { + excludeTeamIDs = append(excludeTeamIDs, k) + } + data, err := resource.GetDomains(db, excludeTeamIDs, args) + common.JsonResponse(c, data, err) + }) } func createDomain(cfg *config.ControllerConfig) gin.HandlerFunc { @@ -101,7 +151,6 @@ func createDomain(cfg *config.ControllerConfig) gin.HandlerFunc { err = c.ShouldBindBodyWith(&domainCreate, binding.JSON) if err != nil { common.BadRequestResponse(c, httpcommon.INVALID_POST_DATA, err.Error()) - return } db, err := common.GetContextOrgDB(c) @@ -109,7 +158,13 @@ func createDomain(cfg *config.ControllerConfig) gin.HandlerFunc { common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) } - data, err := resource.CreateDomain(db, domainCreate, cfg) + userInfo := svc.GetUserInfo(c) + err = svc.IsAddPermitted(cfg.FPermit, userInfo, domainCreate.TeamID) + if err != nil { + common.BadRequestResponse(c, httpcommon.CHECK_SCOPE_TEAMS_FAIL, err.Error()) + } + //create with the user id in the header + data, err := resource.CreateDomain(userInfo, db, domainCreate, cfg) common.JsonResponse(c, data, err) }) } @@ -126,12 +181,6 @@ func updateDomain(cfg *config.ControllerConfig) gin.HandlerFunc { return } - var vTapValue string - v, ok := domainUpdate.Config["vtap_id"] - if ok && v != nil { - vTapValue = v.(string) - } - // transfer json format to map patchMap := map[string]interface{}{} c.ShouldBindBodyWith(&patchMap, binding.JSON) @@ -143,146 +192,156 @@ func updateDomain(cfg *config.ControllerConfig) gin.HandlerFunc { common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) } - // set vtap - err = resource.KubernetesSetVtap(lcuuid, vTapValue, false, db) + data, err := resource.UpdateDomain(lcuuid, patchMap, svc.GetUserInfo(c), cfg, db) + common.JsonResponse(c, data, err) + }) +} + +func deleteDomainByNameOrUUID(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + db, err := common.GetContextOrgDB(c) if err != nil { - common.BadRequestResponse(c, httpcommon.K8S_SET_VTAP_FAIL, err.Error()) - return + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) } - data, err := resource.UpdateDomain(lcuuid, patchMap, cfg, db) + nameOrUUID := c.Param("name-or-uuid") + data, err := resource.DeleteDomainByNameOrUUID(nameOrUUID, db, svc.GetUserInfo(c), cfg) common.JsonResponse(c, data, err) }) } -func deleteDomainByNameOrUUID(c *gin.Context) { - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } - nameOrUUID := c.Param("name-or-uuid") - data, err := resource.DeleteDomainByNameOrUUID(nameOrUUID, db) - common.JsonResponse(c, data, err) -} - -func deleteDomainByName(c *gin.Context) { - rawQuery := strings.Split(c.Request.URL.RawQuery, "name=") - if len(rawQuery) < 1 { - common.JsonResponse(c, nil, fmt.Errorf("please fill in the name parameter: domains/?name={}")) - return - } - name := rawQuery[1] - name, err := url.QueryUnescape(name) - if err != nil { - log.Warning(err) - name = rawQuery[1] - } - log.Infof("delete domain by name(%v)", name) - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } - data, err := resource.DeleteDomainByNameOrUUID(name, db) - common.JsonResponse(c, data, err) +func deleteDomainByName(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + rawQuery := strings.Split(c.Request.URL.RawQuery, "name=") + if len(rawQuery) < 1 { + common.JsonResponse(c, nil, fmt.Errorf("please fill in the name parameter: domains/?name={}")) + return + } + name := rawQuery[1] + name, err := url.QueryUnescape(name) + if err != nil { + log.Warning(err) + name = rawQuery[1] + } + log.Infof("delete domain by name(%v)", name) + db, err := common.GetContextOrgDB(c) + if err != nil { + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) + } + data, err := resource.DeleteDomainByNameOrUUID(name, db, svc.GetUserInfo(c), cfg) + common.JsonResponse(c, data, err) + }) } -func getSubDomain(c *gin.Context) { - args := make(map[string]interface{}) - args["lcuuid"] = c.Param("lcuuid") - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } - data, err := resource.GetSubDomains(db, args) - common.JsonResponse(c, data, err) +func getSubDomain(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + args := make(map[string]interface{}) + args["lcuuid"] = c.Param("lcuuid") + db, err := common.GetContextOrgDB(c) + if err != nil { + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) + } + excludeTeamIDs := []int{} + teamIDs, err := svc.GetUnauthorizedTeamIDs(svc.GetUserInfo(c), &cfg.FPermit) + if err != nil { + common.BadRequestResponse(c, httpcommon.CHECK_SCOPE_TEAMS_FAIL, err.Error()) + } + for k := range teamIDs { + excludeTeamIDs = append(excludeTeamIDs, k) + } + data, err := resource.GetSubDomains(db, excludeTeamIDs, args) + common.JsonResponse(c, data, err) + }) } -func getSubDomains(c *gin.Context) { - args := make(map[string]interface{}) - if value, ok := c.GetQuery("domain"); ok { - args["domain"] = value - } - if value, ok := c.GetQuery("cluster_id"); ok { - args["cluster_id"] = value - } - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } - data, err := resource.GetSubDomains(db, args) - common.JsonResponse(c, data, err) +func getSubDomains(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + args := make(map[string]interface{}) + if value, ok := c.GetQuery("domain"); ok { + args["domain"] = value + } + if value, ok := c.GetQuery("cluster_id"); ok { + args["cluster_id"] = value + } + db, err := common.GetContextOrgDB(c) + if err != nil { + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) + } + excludeTeamIDs := []int{} + teamIDs, err := svc.GetUnauthorizedTeamIDs(svc.GetUserInfo(c), &cfg.FPermit) + if err != nil { + common.BadRequestResponse(c, httpcommon.CHECK_SCOPE_TEAMS_FAIL, err.Error()) + } + for k := range teamIDs { + excludeTeamIDs = append(excludeTeamIDs, k) + } + data, err := resource.GetSubDomains(db, excludeTeamIDs, args) + common.JsonResponse(c, data, err) + }) } -func createSubDomain(c *gin.Context) { - var err error - var subDomainCreate model.SubDomainCreate +func createSubDomain(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + var err error + var subDomainCreate model.SubDomainCreate - // 参数校验 - err = c.ShouldBindBodyWith(&subDomainCreate, binding.JSON) - if err != nil { - common.BadRequestResponse(c, httpcommon.INVALID_POST_DATA, err.Error()) - return - } + // 参数校验 + err = c.ShouldBindBodyWith(&subDomainCreate, binding.JSON) + if err != nil { + common.BadRequestResponse(c, httpcommon.INVALID_POST_DATA, err.Error()) + } - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } + db, err := common.GetContextOrgDB(c) + if err != nil { + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) + } - data, err := resource.CreateSubDomain(db, subDomainCreate) - common.JsonResponse(c, data, err) + data, err := resource.CreateSubDomain(subDomainCreate, db, svc.GetUserInfo(c), cfg) + common.JsonResponse(c, data, err) + }) } -func deleteSubDomain(c *gin.Context) { - var err error +func deleteSubDomain(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + var err error - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } + db, err := common.GetContextOrgDB(c) + if err != nil { + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) + } - lcuuid := c.Param("lcuuid") - data, err := resource.DeleteSubDomain(lcuuid, db) - common.JsonResponse(c, data, err) + lcuuid := c.Param("lcuuid") + data, err := resource.DeleteSubDomain(lcuuid, db, svc.GetUserInfo(c), cfg) + common.JsonResponse(c, data, err) + }) } -func updateSubDomain(c *gin.Context) { - var err error - var subDomainUpdate model.SubDomainUpdate - - // 参数校验 - err = c.ShouldBindBodyWith(&subDomainUpdate, binding.JSON) - if err != nil { - common.BadRequestResponse(c, httpcommon.INVALID_PARAMETERS, err.Error()) - return - } - - var vTapValue string - v, ok := subDomainUpdate.Config["vtap_id"] - if ok && v != nil { - vTapValue = v.(string) - } +func updateSubDomain(cfg *config.ControllerConfig) gin.HandlerFunc { + return gin.HandlerFunc(func(c *gin.Context) { + var err error + var subDomainUpdate model.SubDomainUpdate - // 接收参数 - // 避免struct会有默认值,这里转为map作为函数入参 - patchMap := map[string]interface{}{} - c.ShouldBindBodyWith(&patchMap, binding.JSON) + // 参数校验 + err = c.ShouldBindBodyWith(&subDomainUpdate, binding.JSON) + if err != nil { + common.BadRequestResponse(c, httpcommon.INVALID_PARAMETERS, err.Error()) + } - lcuuid := c.Param("lcuuid") + // 接收参数 + // 避免struct会有默认值,这里转为map作为函数入参 + patchMap := map[string]interface{}{} + c.ShouldBindBodyWith(&patchMap, binding.JSON) - db, err := common.GetContextOrgDB(c) - if err != nil { - common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) - } + lcuuid := c.Param("lcuuid") - err = resource.KubernetesSetVtap(lcuuid, vTapValue, true, db) - if err != nil { - common.BadRequestResponse(c, httpcommon.K8S_SET_VTAP_FAIL, err.Error()) - return - } + db, err := common.GetContextOrgDB(c) + if err != nil { + common.BadRequestResponse(c, httpcommon.GET_ORG_DB_FAIL, err.Error()) + } - data, err := resource.UpdateSubDomain(lcuuid, db, patchMap) - common.JsonResponse(c, data, err) + data, err := resource.UpdateSubDomain(lcuuid, db, svc.GetUserInfo(c), cfg, patchMap) + common.JsonResponse(c, data, err) + }) } func applyDomainAddtionalResource(c *gin.Context) { diff --git a/server/controller/http/service/permission_verification.go b/server/controller/http/service/permission_verification.go index 9d97b58ba32..7bde68e8f78 100644 --- a/server/controller/http/service/permission_verification.go +++ b/server/controller/http/service/permission_verification.go @@ -52,11 +52,8 @@ func isPermitted(fpermit config.FPermit, userInfo *UserInfo, m PermitVerifyMetho if err != nil { return err } - result, err := response.Get("DATA").Bool() - if err != nil { - return err - } - if result == false { + havePermission := response.Get("DATA").MustBool() + if !havePermission { if des := response.Get("DESCRIPTION").MustString(); des != "" { fmt.Errorf("%w %s", httpcommon.ERR_NO_PERMISSIONS, des) } diff --git a/server/controller/http/service/resource/domain.go b/server/controller/http/service/resource/domain.go index d8ea939f784..37affa22b29 100644 --- a/server/controller/http/service/resource/domain.go +++ b/server/controller/http/service/resource/domain.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "math/rand" + "net/http" "os" "strconv" "strings" @@ -37,6 +38,7 @@ import ( "github.com/deepflowio/deepflow/server/controller/db/mysql" mysqlcommon "github.com/deepflowio/deepflow/server/controller/db/mysql/common" httpcommon "github.com/deepflowio/deepflow/server/controller/http/common" + svc "github.com/deepflowio/deepflow/server/controller/http/service" servicecommon "github.com/deepflowio/deepflow/server/controller/http/service/common" "github.com/deepflowio/deepflow/server/controller/model" "github.com/deepflowio/deepflow/server/controller/recorder/constraint" @@ -91,7 +93,7 @@ func getGrpcServerAndPort(db *mysql.DB, controllerIP string, cfg *config.Control } } -func GetDomains(orgDB *mysql.DB, filter map[string]interface{}) (resp []model.Domain, err error) { +func GetDomains(orgDB *mysql.DB, excludeTeamIDs []int, filter map[string]interface{}) (resp []model.Domain, err error) { var response []model.Domain var domains []mysql.Domain var azs []mysql.AZ @@ -103,18 +105,30 @@ func GetDomains(orgDB *mysql.DB, filter map[string]interface{}) (resp []model.Do var controllerIPToName map[string]string db := orgDB.DB - if _, ok := filter["lcuuid"]; ok { - db = orgDB.Where("lcuuid = ?", filter["lcuuid"]) + if fLcuuid, ok := filter["lcuuid"]; ok { + db = orgDB.Where("lcuuid = ?", fLcuuid) } - if _, ok := filter["name"]; ok { - db = orgDB.Where("name = ?", filter["name"]) + if fName, ok := filter["name"]; ok { + db = orgDB.Where("name = ?", fName) + } + if fTeamID, ok := filter["team_id"]; ok { + db = orgDB.Where("team_id = ?", fTeamID) + } + if fUserID, ok := filter["user_id"]; ok { + db = orgDB.Where("user_id = ?", fUserID) + } + err = db.Not(map[string]interface{}{"team_id": excludeTeamIDs}).Order("created_at DESC").Find(&domains).Error + if err != nil { + return response, err } - db.Order("created_at DESC").Find(&domains) for _, domain := range domains { domainLcuuids = append(domainLcuuids, domain.Lcuuid) } - db.Where("domain IN (?)", domainLcuuids).Find(&azs) + err = orgDB.Where("domain IN (?)", domainLcuuids).Find(&azs).Error + if err != nil { + return response, err + } domainToAZLcuuids = make(map[string][]string) domainToRegionLcuuidsToAZLcuuids = make(map[string]map[string][]string) @@ -129,13 +143,19 @@ func GetDomains(orgDB *mysql.DB, filter map[string]interface{}) (resp []model.Do } } - db.Find(&controllers) + err = orgDB.Find(&controllers).Error + if err != nil { + return response, err + } controllerIPToName = make(map[string]string) for _, controller := range controllers { controllerIPToName[controller.IP] = controller.Name } - db.Find(&subDomains) + err = orgDB.Find(&subDomains).Error + if err != nil { + return response, err + } domainToSubDomainNames := make(map[string][]string) for _, subDomain := range subDomains { domainToSubDomainNames[subDomain.Domain] = append( @@ -160,6 +180,7 @@ func GetDomains(orgDB *mysql.DB, filter map[string]interface{}) (resp []model.Do ControllerIP: domain.ControllerIP, IconID: domain.IconID, // 后续与前端沟通icon作为默认配置 TeamID: domain.TeamID, + UserID: domain.UserID, CreatedAt: domain.CreatedAt.Format(common.GO_BIRTHDAY), SyncedAt: syncedAt, Lcuuid: domain.Lcuuid, @@ -190,11 +211,11 @@ func GetDomains(orgDB *mysql.DB, filter map[string]interface{}) (resp []model.Do } } else { var k8sCluster mysql.KubernetesCluster - if err = db.Where("cluster_id = ?", domain.ClusterID).First(&k8sCluster).Error; err == nil { + if err = orgDB.Where("cluster_id = ?", domain.ClusterID).First(&k8sCluster).Error; err == nil { v := strings.Split(k8sCluster.Value, "-") if len(v) == 2 { var vtap mysql.VTap - if err = db.Where("ctrl_ip = ? AND ctrl_mac = ?", v[0], v[1]).First(&vtap).Error; err == nil { + if err = orgDB.Where("ctrl_ip = ? AND ctrl_mac = ?", v[0], v[1]).First(&vtap).Error; err == nil { domainResp.VTapName = vtap.Name domainResp.VTapCtrlIP = vtap.CtrlIP domainResp.VTapCtrlMAC = vtap.CtrlMac @@ -223,7 +244,7 @@ func maskDomainInfo(domainCreate model.DomainCreate) model.DomainCreate { return info } -func CreateDomain(db *mysql.DB, domainCreate model.DomainCreate, cfg *config.ControllerConfig) (*model.Domain, error) { +func CreateDomain(userInfo *svc.UserInfo, db *mysql.DB, domainCreate model.DomainCreate, cfg *config.ControllerConfig) (*model.Domain, error) { var count int64 db.Model(&mysql.Domain{}).Where("name = ?", domainCreate.Name).Count(&count) @@ -252,14 +273,26 @@ func CreateDomain(db *mysql.DB, domainCreate model.DomainCreate, cfg *config.Con } } + displayName := common.GetUUID(k8sClusterIDCreate, uuid.Nil) + lcuuid := common.GetUUID(displayName, uuid.Nil) + body := map[string]interface{}{ + "team_id": domainCreate.TeamID, + "owner_user_id": userInfo.ID, + "resource_type": common.SET_RESOURCE_TYPE_DOMAIN, + "resource_id": lcuuid, + } + err := svc.SetReource(http.MethodPost, cfg.FPermit, body, userInfo) + if err != nil { + return nil, err + } + log.Infof("create domain (%v)", maskDomainInfo(domainCreate)) domain := mysql.Domain{} - displayName := common.GetUUID(k8sClusterIDCreate, uuid.Nil) - lcuuid := common.GetUUID(displayName, uuid.Nil) domain.Lcuuid = lcuuid domain.Name = domainCreate.Name domain.TeamID = domainCreate.TeamID + domain.UserID = userInfo.ID domain.DisplayName = displayName domain.Type = domainCreate.Type domain.IconID = domainCreate.IconID @@ -332,14 +365,14 @@ func CreateDomain(db *mysql.DB, domainCreate model.DomainCreate, cfg *config.Con domain.ClusterID = "d-" + common.GenerateShortUUID() } } - err := db.Clauses(clause.Insert{Modifier: "IGNORE"}).Create(&domain).Error + err = db.Clauses(clause.Insert{Modifier: "IGNORE"}).Create(&domain).Error if err != nil { return nil, servicecommon.NewError(httpcommon.SERVER_ERROR, fmt.Sprintf("create domain (%s) failed", domainCreate.Name)) } if domainCreate.Type == common.KUBERNETES { createKubernetesRelatedResources(db, domain, regionLcuuid) } - response, _ := GetDomains(db, map[string]interface{}{"lcuuid": lcuuid}) + response, _ := GetDomains(db, []int{}, map[string]interface{}{"lcuuid": lcuuid}) return &response[0], nil } @@ -382,9 +415,7 @@ func createKubernetesRelatedResources(db *mysql.DB, domain mysql.Domain, regionL return } -func UpdateDomain( - lcuuid string, domainUpdate map[string]interface{}, cfg *config.ControllerConfig, db *mysql.DB, -) (*model.Domain, error) { +func UpdateDomain(lcuuid string, domainUpdate map[string]interface{}, userInfo *svc.UserInfo, cfg *config.ControllerConfig, db *mysql.DB) (*model.Domain, error) { var domain mysql.Domain var dbUpdateMap = make(map[string]interface{}) @@ -394,36 +425,67 @@ func UpdateDomain( ) } - log.Infof("update domain (%s) config (%v)", domain.Name, domainUpdate) + err := svc.IsUpdatePermitted(cfg.FPermit, userInfo, domain.TeamID) + if err != nil { + return nil, err + } + + resourceUp := map[string]interface{}{} + // team id + uTeamID, exist := domainUpdate["TEAM_ID"] + if exist { + dbUpdateMap["team_id"] = uTeamID + resourceUp["team_id"] = uTeamID + } + + // user id + if uUserID, ok := domainUpdate["USER_ID"]; ok { + dbUpdateMap["user_id"] = uUserID + resourceUp["owner_user_id"] = uUserID + } + + if len(resourceUp) != 0 { + body := map[string]interface{}{ + "resource_where": map[string]interface{}{ + "resource_type": common.SET_RESOURCE_TYPE_DOMAIN, + "resource_id": lcuuid, + }, + "resource_up": resourceUp, + } + err := svc.SetReource(http.MethodPatch, cfg.FPermit, body, userInfo) + if err != nil { + return nil, err + } + } // 修改名称 - if _, ok := domainUpdate["NAME"]; ok { - dbUpdateMap["name"] = domainUpdate["NAME"] + if uName, ok := domainUpdate["NAME"]; ok { + dbUpdateMap["name"] = uName } // 禁用/启用 - if _, ok := domainUpdate["ENABLED"]; ok { - dbUpdateMap["enabled"] = domainUpdate["ENABLED"] + if uEnabled, ok := domainUpdate["ENABLED"]; ok { + dbUpdateMap["enabled"] = uEnabled } // 图标 - if _, ok := domainUpdate["ICON_ID"]; ok { - dbUpdateMap["icon_id"] = domainUpdate["ICON_ID"] + if uIconID, ok := domainUpdate["ICON_ID"]; ok { + dbUpdateMap["icon_id"] = uIconID } // 控制器IP - if _, ok := domainUpdate["CONTROLLER_IP"]; ok { - dbUpdateMap["controller_ip"] = domainUpdate["CONTROLLER_IP"] - domain.ControllerIP = domainUpdate["CONTROLLER_IP"].(string) + if uControllerIP, ok := domainUpdate["CONTROLLER_IP"]; ok { + dbUpdateMap["controller_ip"] = uControllerIP + domain.ControllerIP = uControllerIP.(string) } // config // 注意:密码相关字段因为返回是****,所以不能直接把页面更新入库 - if _, ok := domainUpdate["CONFIG"]; ok && domainUpdate["CONFIG"] != nil { + if fConfig, ok := domainUpdate["CONFIG"]; ok && fConfig != nil { config := make(map[string]interface{}) json.Unmarshal([]byte(domain.Config), &config) - configUpdate := domainUpdate["CONFIG"].(map[string]interface{}) + configUpdate := fConfig.(map[string]interface{}) // 如果存在资源同步控制器IP的修改,则需要更新controller_ip字段 if controllerIP, ok := configUpdate["controller_ip"]; ok { @@ -465,12 +527,34 @@ func UpdateDomain( } configStr, _ := json.Marshal(configUpdate) dbUpdateMap["config"] = string(configStr) + + // set vtap + var vTapValue string + v, ok := configUpdate["vtap_id"] + if ok && v != nil { + vTapValue = v.(string) + } + err := KubernetesSetVtap(lcuuid, vTapValue, false, db) + if err != nil { + return nil, err + } } + log.Infof("update domain (%s) config (%v)", domain.Name, domainUpdate) + // 更新domain DB - db.Model(&domain).Updates(dbUpdateMap) + err = db.Model(&domain).Updates(dbUpdateMap).Error + if err != nil { + return nil, err + } + if exist { + err = db.Model(&mysql.SubDomain{}).Where("domain = ?", domain.Lcuuid).Update("team_id", uTeamID).Error + if err != nil { + return nil, err + } + } - response, _ := GetDomains(db, map[string]interface{}{"lcuuid": domain.Lcuuid}) + response, _ := GetDomains(db, []int{}, map[string]interface{}{"lcuuid": domain.Lcuuid}) return &response[0], nil } @@ -503,7 +587,7 @@ func cleanSoftDeletedResource(db *mysql.DB, lcuuid string) { log.Info("clean soft deleted resources completed") } -func DeleteDomainByNameOrUUID(nameOrUUID string, db *mysql.DB) (map[string]string, error) { +func DeleteDomainByNameOrUUID(nameOrUUID string, db *mysql.DB, userInfo *svc.UserInfo, cfg *config.ControllerConfig) (map[string]string, error) { var domain mysql.Domain err1 := db.Where("lcuuid = ?", nameOrUUID).First(&domain).Error var domains []mysql.Domain @@ -515,7 +599,7 @@ func DeleteDomainByNameOrUUID(nameOrUUID string, db *mysql.DB) (map[string]strin } // delete domain by lcuuid if err1 == nil { - return deleteDomain(&domain, db) + return deleteDomain(&domain, db, userInfo, cfg) } if len(domains) > 1 { @@ -525,7 +609,7 @@ func DeleteDomainByNameOrUUID(nameOrUUID string, db *mysql.DB) (map[string]strin } // delete domain by name if err2 == nil && len(domains) > 0 { - return deleteDomain(&domains[0], db) + return deleteDomain(&domains[0], db, userInfo, cfg) } return nil, servicecommon.NewError( @@ -533,9 +617,23 @@ func DeleteDomainByNameOrUUID(nameOrUUID string, db *mysql.DB) (map[string]strin ) } -func deleteDomain(domain *mysql.Domain, db *mysql.DB) (map[string]string, error) { // TODO whether release resource ids +func deleteDomain(domain *mysql.Domain, db *mysql.DB, userInfo *svc.UserInfo, cfg *config.ControllerConfig) (map[string]string, error) { // TODO whether release resource ids log.Infof("delete domain (%s) resources started", domain.Name) + err := svc.IsDeletePermitted(cfg.FPermit, userInfo, domain.TeamID) + if err != nil { + return map[string]string{}, err + } + + body := map[string]interface{}{ + "resource_type": common.SET_RESOURCE_TYPE_DOMAIN, + "resource_ids": domain.Lcuuid, + } + err = svc.SetReource(http.MethodDelete, cfg.FPermit, body, userInfo) + if err != nil { + return nil, err + } + lcuuid := domain.Lcuuid db.Unscoped().Where("domain = ?", lcuuid).Delete(&mysql.WANIP{}) // TODO use forceDelete func db.Unscoped().Where("domain = ?", lcuuid).Delete(&mysql.LANIP{}) @@ -708,24 +806,27 @@ func KubernetesSetVtap(lcuuid, value string, isSubDomain bool, db *mysql.DB) err return nil } -func GetSubDomains(orgDB *mysql.DB, filter map[string]interface{}) ([]*model.SubDomain, error) { +func GetSubDomains(orgDB *mysql.DB, excludeTeamIDs []int, filter map[string]interface{}) ([]*model.SubDomain, error) { var response []*model.SubDomain var subDomains []mysql.SubDomain var vpcs []mysql.VPC db := orgDB.DB - if _, ok := filter["lcuuid"]; ok { - db = db.Where("lcuuid = ?", filter["lcuuid"]) + if fLcuuid, ok := filter["lcuuid"]; ok { + db = db.Where("lcuuid = ?", fLcuuid) } - if _, ok := filter["domain"]; ok { - db = db.Where("domain = ?", filter["domain"]) + if fDomain, ok := filter["domain"]; ok { + db = db.Where("domain = ?", fDomain) } - if _, ok := filter["cluster_id"]; ok { - db = db.Where("cluster_id = ?", filter["cluster_id"]) + if fClusterID, ok := filter["cluster_id"]; ok { + db = db.Where("cluster_id = ?", fClusterID) + } + err := db.Not(map[string]interface{}{"team_id": excludeTeamIDs}).Order("created_at DESC").Find(&subDomains).Error + if err != nil { + return response, err } - db.Order("created_at DESC").Find(&subDomains) - db.Select("name", "lcuuid").Find(&vpcs) + orgDB.Select("name", "lcuuid").Find(&vpcs) lcuuidToVPCName := make(map[string]string) for _, vpc := range vpcs { lcuuidToVPCName[vpc.Lcuuid] = vpc.Name @@ -761,11 +862,11 @@ func GetSubDomains(orgDB *mysql.DB, filter map[string]interface{}) ([]*model.Sub } var k8sCluster mysql.KubernetesCluster - if err := db.Where("cluster_id = ?", subDomain.ClusterID).First(&k8sCluster).Error; err == nil { + if err := orgDB.Where("cluster_id = ?", subDomain.ClusterID).First(&k8sCluster).Error; err == nil { v := strings.Split(k8sCluster.Value, "-") if len(v) == 2 { var vtap mysql.VTap - if err = db.Where("ctrl_ip = ? AND ctrl_mac = ?", v[0], v[1]).First(&vtap).Error; err == nil { + if err = orgDB.Where("ctrl_ip = ? AND ctrl_mac = ?", v[0], v[1]).First(&vtap).Error; err == nil { subDomainResp.Config["vtap_id"] = vtap.Name } } @@ -773,7 +874,7 @@ func GetSubDomains(orgDB *mysql.DB, filter map[string]interface{}) ([]*model.Sub // get domain name var domain mysql.Domain - if err := db.Where("lcuuid = ?", subDomain.Domain).First(&domain).Error; err != nil { + if err := orgDB.Where("lcuuid = ?", subDomain.Domain).First(&domain).Error; err != nil { log.Error(err) } subDomainResp.DomainName = domain.Name @@ -783,13 +884,15 @@ func GetSubDomains(orgDB *mysql.DB, filter map[string]interface{}) ([]*model.Sub return response, nil } -func CreateSubDomain(db *mysql.DB, subDomainCreate model.SubDomainCreate) (*model.SubDomain, error) { - var domainCount int64 - if err := db.Model(&mysql.Domain{}).Where("lcuuid = ?", subDomainCreate.Domain).Count(&domainCount).Error; err != nil { +func CreateSubDomain(subDomainCreate model.SubDomainCreate, db *mysql.DB, userInfo *svc.UserInfo, cfg *config.ControllerConfig) (*model.SubDomain, error) { + var domain mysql.Domain + if err := db.Model(&mysql.Domain{}).Where("lcuuid = ?", subDomainCreate.Domain).First(&domain).Error; err != nil { return nil, err } - if domainCount == 0 { - return nil, servicecommon.NewError(httpcommon.RESOURCE_NOT_FOUND, fmt.Sprintf("domain lcuuid (%s) does not exit", subDomainCreate.Domain)) + + err := svc.IsAddPermitted(cfg.FPermit, userInfo, domain.TeamID) + if err != nil { + return nil, err } var count int64 @@ -798,12 +901,24 @@ func CreateSubDomain(db *mysql.DB, subDomainCreate model.SubDomainCreate) (*mode return nil, servicecommon.NewError(httpcommon.RESOURCE_ALREADY_EXIST, fmt.Sprintf("sub_domain (%s) already exist", subDomainCreate.Name)) } + displayName := common.GetUUID("", uuid.Nil) + lcuuid := common.GetUUID(displayName, uuid.Nil) + body := map[string]interface{}{ + "team_id": domain.TeamID, + "owner_user_id": userInfo.ID, + "resource_type": common.SET_RESOURCE_TYPE_SUB_DOMAIN, + "resource_id": lcuuid, + } + err = svc.SetReource(http.MethodPost, cfg.FPermit, body, userInfo) + if err != nil { + return nil, err + } + log.Infof("create sub_domain (%v)", subDomainCreate) subDomain := mysql.SubDomain{} - displayName := common.GetUUID("", uuid.Nil) - lcuuid := common.GetUUID(displayName, uuid.Nil) subDomain.Lcuuid = lcuuid + subDomain.TeamID = domain.TeamID subDomain.Name = subDomainCreate.Name subDomain.DisplayName = displayName subDomain.CreateMethod = common.CREATE_METHOD_USER_DEFINE @@ -813,11 +928,11 @@ func CreateSubDomain(db *mysql.DB, subDomainCreate model.SubDomainCreate) (*mode subDomain.Config = string(configStr) db.Create(&subDomain) - response, _ := GetSubDomains(db, map[string]interface{}{"lcuuid": lcuuid}) + response, _ := GetSubDomains(db, []int{}, map[string]interface{}{"lcuuid": lcuuid}) return response[0], nil } -func UpdateSubDomain(lcuuid string, db *mysql.DB, subDomainUpdate map[string]interface{}) (*model.SubDomain, error) { +func UpdateSubDomain(lcuuid string, db *mysql.DB, userInfo *svc.UserInfo, cfg *config.ControllerConfig, subDomainUpdate map[string]interface{}) (*model.SubDomain, error) { if _, ok := subDomainUpdate["NAME"]; ok { return nil, errors.New("name field cannot be modified") } @@ -833,28 +948,60 @@ func UpdateSubDomain(lcuuid string, db *mysql.DB, subDomainUpdate map[string]int ) } + err := svc.IsUpdatePermitted(cfg.FPermit, userInfo, subDomain.TeamID) + if err != nil { + return nil, err + } + log.Infof("update sub_domain (%s) config (%v)", subDomain.Name, subDomainUpdate) // config - if _, ok := subDomainUpdate["CONFIG"]; ok { - configStr, _ := json.Marshal(subDomainUpdate["CONFIG"]) + fConfig, ok := subDomainUpdate["CONFIG"] + if ok { + configStr, _ := json.Marshal(fConfig) dbUpdateMap["config"] = string(configStr) } + var vTapValue string + v, ok := fConfig.(map[string]interface{})["vtap_id"] + if ok && v != nil { + vTapValue = v.(string) + } + + err = KubernetesSetVtap(lcuuid, vTapValue, true, db) + if err != nil { + return nil, err + } + // 更新domain DB db.Model(&subDomain).Updates(dbUpdateMap) - response, _ := GetSubDomains(db, map[string]interface{}{"lcuuid": lcuuid}) + response, _ := GetSubDomains(db, []int{}, map[string]interface{}{"lcuuid": lcuuid}) return response[0], nil } -func DeleteSubDomain(lcuuid string, db *mysql.DB) (map[string]string, error) { +func DeleteSubDomain(lcuuid string, db *mysql.DB, userInfo *svc.UserInfo, cfg *config.ControllerConfig) (map[string]string, error) { var subDomain mysql.SubDomain if ret := db.Where("lcuuid = ?", lcuuid).First(&subDomain); ret.Error != nil { return nil, servicecommon.NewError( httpcommon.RESOURCE_NOT_FOUND, fmt.Sprintf("sub_domain (%s) not found", lcuuid), ) } + + err := svc.IsDeletePermitted(cfg.FPermit, userInfo, subDomain.TeamID) + if err != nil { + return map[string]string{}, err + } + + body := map[string]interface{}{ + "resource_type": common.SET_RESOURCE_TYPE_SUB_DOMAIN, + "resource_ids": lcuuid, + } + err = svc.SetReource(http.MethodDelete, cfg.FPermit, body, userInfo) + if err != nil { + return nil, err + } + log.Infof("delete sub_domain (%s) resources started", subDomain.Name) var podCluster mysql.PodCluster diff --git a/server/controller/http/service/resource/domain_test.go b/server/controller/http/service/resource/domain_test.go index 3f4a1eec87c..8d5c8816976 100644 --- a/server/controller/http/service/resource/domain_test.go +++ b/server/controller/http/service/resource/domain_test.go @@ -30,7 +30,10 @@ import ( "gorm.io/gorm" "gorm.io/gorm/schema" + "github.com/deepflowio/deepflow/server/controller/config" "github.com/deepflowio/deepflow/server/controller/db/mysql" + "github.com/deepflowio/deepflow/server/controller/db/mysql/common" + "github.com/deepflowio/deepflow/server/controller/http/service" ) const ( @@ -192,7 +195,7 @@ func (t *SuiteTest) TestDeleteDomain() { r = t.db.Create(&mysql.Pod{Base: mysql.Base{Lcuuid: uuid.NewString()}, Domain: domain.Lcuuid}) assert.Equal(t.T(), r.RowsAffected, int64(1)) - DeleteDomainByNameOrUUID(domain.Lcuuid, &mysql.DB{t.db, 1, ""}) + DeleteDomainByNameOrUUID(domain.Lcuuid, &mysql.DB{DB: t.db, ORGID: common.DEFAULT_ORG_ID}, &service.UserInfo{}, &config.ControllerConfig{}) var azs []mysql.AZ t.db.Unscoped().Where("domain = ?", domain.Lcuuid).Find(&azs) @@ -356,7 +359,7 @@ func (t *SuiteTest) TestDeleteSubDomain() { r = t.db.Create(&mysql.Pod{Base: mysql.Base{Lcuuid: uuid.NewString()}, SubDomain: lcuuid}) assert.Equal(t.T(), r.RowsAffected, int64(1)) - DeleteSubDomain(lcuuid, &mysql.DB{t.db, 1, ""}) + DeleteSubDomain(lcuuid, &mysql.DB{DB: t.db, ORGID: common.DEFAULT_ORG_ID}, &service.UserInfo{}, &config.ControllerConfig{}) var networks []mysql.Network t.db.Unscoped().Where("sub_domain = ?", lcuuid).Find(&networks) @@ -427,7 +430,7 @@ func (t *SuiteTest) TestDeleteSoftDeletedResource() { t.db.Unscoped().Where("domain = ?", domainLcuuid).Find(&azs) assert.Equal(t.T(), 1, len(azs)) - cleanSoftDeletedResource(domainLcuuid) + cleanSoftDeletedResource(&mysql.DB{DB: t.db, ORGID: common.DEFAULT_ORG_ID}, domainLcuuid) t.db.Unscoped().Find(&azs) assert.Equal(t.T(), 1, len(azs)) t.db.Unscoped().Where("domain = ?", domainLcuuid).Find(&azs) diff --git a/server/controller/http/service/set_resource.go b/server/controller/http/service/set_resource.go new file mode 100644 index 00000000000..2785a4077a7 --- /dev/null +++ b/server/controller/http/service/set_resource.go @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2024 Yunshan Networks + * + * 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 ( + "fmt" + + "github.com/deepflowio/deepflow/server/controller/common" + "github.com/deepflowio/deepflow/server/controller/config" +) + +func SetReource(method string, fpermit config.FPermit, body map[string]interface{}, userInfo *UserInfo) error { + if !fpermit.Enabled { + return nil + } + + _, err := common.CURLPerform( + method, + fmt.Sprintf("http://%s:%d/v1/org/%d/resource", fpermit.Host, fpermit.Port, userInfo.ORGID), + body, + common.WithHeader(common.HEADER_X_APP_KEY, common.DEFAULT_APP_KEY), + common.WithHeader(common.HEADER_KEY_X_USER_TYPE, fmt.Sprintf("%d", userInfo.Type)), + common.WithHeader(common.HEADER_KEY_X_USER_ID, fmt.Sprintf("%d", userInfo.ID)), + ) + if err != nil { + return err + } + return nil +} diff --git a/server/controller/model/model.go b/server/controller/model/model.go index 65e8decb31d..8cc430fa86c 100644 --- a/server/controller/model/model.go +++ b/server/controller/model/model.go @@ -315,6 +315,7 @@ type Domain struct { VTapCtrlMAC string `json:"VTAP_CTRL_MAC"` IconID int `json:"ICON_ID"` TeamID int `json:"TEAM_ID"` + UserID int `json:"USER_ID"` K8sEnabled int `json:"K8S_ENABLED"` Config map[string]interface{} `json:"CONFIG"` AZCount int `json:"AZ_COUNT"` @@ -328,7 +329,7 @@ type Domain struct { type DomainCreate struct { Name string `json:"NAME" binding:"required"` Type int `json:"TYPE" binding:"required"` - TeamID int `json:"TEAM_ID"` + TeamID int `json:"TEAM_ID" binding:"required"` KubernetesClusterID string `json:"KUBERNETES_CLUSTER_ID"` IconID int `json:"ICON_ID"` // TODO: 修改为required ControllerIP string `json:"CONTROLLER_IP"` // TODO: 修改为required @@ -340,6 +341,7 @@ type DomainUpdate struct { Enabled int `json:"ENABLED"` IconID int `json:"ICON_ID"` TeamID int `json:"TEAM_ID"` + UserID int `json:"USER_ID"` ControllerIP string `json:"CONTROLLER_IP"` Config map[string]interface{} `json:"CONFIG"` } diff --git a/server/controller/recorder/updater/sub_domain.go b/server/controller/recorder/updater/sub_domain.go index 59c9f2e42cd..d2b9f1e2df8 100644 --- a/server/controller/recorder/updater/sub_domain.go +++ b/server/controller/recorder/updater/sub_domain.go @@ -73,6 +73,7 @@ func (d *SubDomain) getDiffBaseByCloudItem(cloudItem *cloudmodel.SubDomain) (dif func (d *SubDomain) generateDBItemToAdd(cloudItem *cloudmodel.SubDomain) (*mysql.SubDomain, bool) { dbItem := &mysql.SubDomain{ + TeamID: cloudItem.TeamID, Name: cloudItem.Name, DisplayName: cloudItem.DisplayName, ClusterID: cloudItem.ClusterID, diff --git a/server/controller/trisolaris/kubernetes/kubernetes.go b/server/controller/trisolaris/kubernetes/kubernetes.go index d84287272c0..c11848c26fa 100644 --- a/server/controller/trisolaris/kubernetes/kubernetes.go +++ b/server/controller/trisolaris/kubernetes/kubernetes.go @@ -27,10 +27,12 @@ import ( "context" + "github.com/deepflowio/deepflow/server/controller/common" . "github.com/deepflowio/deepflow/server/controller/common" "github.com/deepflowio/deepflow/server/controller/db/mysql" models "github.com/deepflowio/deepflow/server/controller/db/mysql" mysqlcommon "github.com/deepflowio/deepflow/server/controller/db/mysql/common" + "github.com/deepflowio/deepflow/server/controller/http/service" resourceservice "github.com/deepflowio/deepflow/server/controller/http/service/resource" "github.com/deepflowio/deepflow/server/controller/model" "github.com/deepflowio/deepflow/server/controller/trisolaris/config" @@ -183,6 +185,7 @@ func (k *KubernetesInfo) createDomain(teamUID, clusterID, clusterName string) (d } teamID := DEFAULT_TEAM_ID + orgID := DEFAULT_ORG_ID if teamUID != "" { var team *mysql.Team if err := k.db.Where("short_lcuuid = ?", teamUID).First(&team).Error; err != nil { @@ -190,6 +193,7 @@ func (k *KubernetesInfo) createDomain(teamUID, clusterID, clusterName string) (d return "", err } teamID = team.ID + orgID = team.ORGID } domainConf := map[string]interface{}{ "controller_ip": k.cfg.NodeIP, @@ -215,7 +219,13 @@ func (k *KubernetesInfo) createDomain(teamUID, clusterID, clusterName string) (d // icon id value only for enterprise edition IconID: DomainTypeToIconID[KUBERNETES], } - domain, err := resourceservice.CreateDomain(&mysql.DB{k.db, k.GetORGID(), mysqlcommon.ORGIDToDatabaseName(k.GetORGID())}, domainCreate, nil) + + userInfo := service.UserInfo{ + ID: common.DEFAULT_USER_ID, + Type: common.DEFAULT_USER_TYPE, + ORGID: orgID, + } + domain, err := resourceservice.CreateDomain(&userInfo, &mysql.DB{k.db, k.GetORGID(), mysqlcommon.ORGIDToDatabaseName(k.GetORGID())}, domainCreate, nil) if err != nil { log.Errorf(k.Logf("create domain failed: %s", err.Error())) return "", err