github.com/polarismesh/polaris@v1.17.8/store/boltdb/group.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package boltdb 19 20 import ( 21 "errors" 22 "fmt" 23 "sort" 24 "strings" 25 "time" 26 27 bolt "go.etcd.io/bbolt" 28 "go.uber.org/zap" 29 30 "github.com/polarismesh/polaris/common/model" 31 "github.com/polarismesh/polaris/common/utils" 32 "github.com/polarismesh/polaris/store" 33 ) 34 35 var ( 36 // ErrorMultipleGroupFound is returned when multiple groups are found. 37 ErrorMultipleGroupFound error = errors.New("multiple group found") 38 // ErrorGroupNotFound is returned when a group is not found. 39 ErrorGroupNotFound error = errors.New("usergroup not found") 40 ) 41 42 const ( 43 tblGroup string = "group" 44 45 GroupFieldID string = "ID" 46 GroupFieldName string = "Name" 47 GroupFieldOwner string = "Owner" 48 GroupFieldToken string = "Token" 49 GroupFieldTokenEnable string = "TokenEnable" 50 GroupFieldValid string = "Valid" 51 GroupFieldComment string = "Comment" 52 GroupFieldCreateTime string = "CreateTime" 53 GroupFieldModifyTime string = "ModifyTime" 54 GroupFieldUserIds string = "UserIds" 55 ) 56 57 type groupForStore struct { 58 ID string 59 Name string 60 Owner string 61 Token string 62 TokenEnable bool 63 Valid bool 64 Comment string 65 CreateTime time.Time 66 ModifyTime time.Time 67 UserIds map[string]string 68 } 69 70 // groupStore 71 type groupStore struct { 72 handler BoltHandler 73 } 74 75 // AddGroup add a group 76 func (gs *groupStore) AddGroup(group *model.UserGroupDetail) error { 77 if group.ID == "" || group.Name == "" || group.Token == "" { 78 return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf( 79 "add usergroup missing some params, groupId is %s, name is %s", group.ID, group.Name)) 80 } 81 82 proxy, err := gs.handler.StartTx() 83 if err != nil { 84 return err 85 } 86 tx := proxy.GetDelegateTx().(*bolt.Tx) 87 88 defer func() { 89 _ = tx.Rollback() 90 }() 91 92 if err := gs.cleanInValidGroup(tx, group.Name, group.Owner); err != nil { 93 log.Error("[Store][Group] clean invalid usergroup", zap.Error(err), 94 zap.String("name", group.Name), zap.String("owner", group.Owner)) 95 return err 96 } 97 98 return gs.addGroup(tx, group) 99 } 100 101 // addGroup to boltdb 102 func (gs *groupStore) addGroup(tx *bolt.Tx, group *model.UserGroupDetail) error { 103 104 group.Valid = true 105 group.CreateTime = time.Now() 106 group.ModifyTime = group.CreateTime 107 108 data := convertForGroupStore(group) 109 110 if err := saveValue(tx, tblGroup, data.ID, data); err != nil { 111 log.Error("[Store][Group] save usergroup", zap.Error(err), 112 zap.String("name", group.Name), zap.String("owner", group.Owner)) 113 114 return err 115 } 116 117 if err := createDefaultStrategy(tx, model.PrincipalGroup, data.ID, data.Name, 118 data.Owner); err != nil { 119 log.Error("[Store][Group] add usergroup default strategy", zap.Error(err), 120 zap.String("name", group.Name), zap.String("owner", group.Owner)) 121 122 return err 123 } 124 125 if err := tx.Commit(); err != nil { 126 log.Error("[Store][Group] add usergroup tx commit", zap.Error(err), 127 zap.String("name", group.Name), zap.String("owner", group.Owner)) 128 return err 129 } 130 131 return nil 132 } 133 134 // UpdateGroup update a group 135 func (gs *groupStore) UpdateGroup(group *model.ModifyUserGroup) error { 136 if group.ID == "" { 137 return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf( 138 "update usergroup missing some params, groupId is %s", group.ID)) 139 } 140 141 return gs.updateGroup(group) 142 } 143 144 func (gs *groupStore) updateGroup(group *model.ModifyUserGroup) error { 145 proxy, err := gs.handler.StartTx() 146 if err != nil { 147 return err 148 } 149 tx := proxy.GetDelegateTx().(*bolt.Tx) 150 151 defer func() { 152 _ = tx.Rollback() 153 }() 154 155 values := make(map[string]interface{}) 156 157 if err := loadValues(tx, tblGroup, []string{group.ID}, &groupForStore{}, values); err != nil { 158 log.Error("[Store][Group] get usergroup by id", zap.Error(err), zap.String("id", group.ID)) 159 } 160 161 if len(values) == 0 { 162 return ErrorGroupNotFound 163 } 164 165 if len(values) > 1 { 166 return ErrorMultipleGroupFound 167 } 168 169 var ret *model.UserGroupDetail 170 for _, v := range values { 171 ret = convertForGroupDetail(v.(*groupForStore)) 172 break 173 } 174 175 ret.Comment = group.Comment 176 ret.Token = group.Token 177 ret.TokenEnable = group.TokenEnable 178 ret.ModifyTime = time.Now() 179 180 updateGroupRelation(ret, group) 181 182 if err := saveValue(tx, tblGroup, ret.ID, convertForGroupStore(ret)); err != nil { 183 log.Error("[Store][Group] update usergroup", zap.Error(err), zap.String("id", ret.ID)) 184 return err 185 } 186 187 if err := tx.Commit(); err != nil { 188 log.Error("[Store][Group] update usergroup tx commit", 189 zap.Error(err), zap.String("id", ret.ID)) 190 return err 191 } 192 return nil 193 } 194 195 // updateGroupRelation 更新用户组的关联关系数据 196 func updateGroupRelation(group *model.UserGroupDetail, modify *model.ModifyUserGroup) { 197 for i := range modify.AddUserIds { 198 group.UserIds[modify.AddUserIds[i]] = struct{}{} 199 } 200 201 for i := range modify.RemoveUserIds { 202 delete(group.UserIds, modify.RemoveUserIds[i]) 203 } 204 } 205 206 // DeleteGroup 删除用户组 207 func (gs *groupStore) DeleteGroup(group *model.UserGroupDetail) error { 208 if group.ID == "" { 209 return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf( 210 "delete usergroup missing some params, groupId is %s", group.ID)) 211 } 212 213 return gs.deleteGroup(group) 214 } 215 216 func (gs *groupStore) deleteGroup(group *model.UserGroupDetail) error { 217 proxy, err := gs.handler.StartTx() 218 if err != nil { 219 return err 220 } 221 tx := proxy.GetDelegateTx().(*bolt.Tx) 222 223 defer func() { 224 _ = tx.Rollback() 225 }() 226 227 properties := make(map[string]interface{}) 228 properties[GroupFieldValid] = false 229 properties[GroupFieldModifyTime] = time.Now() 230 231 if err := updateValue(tx, tblGroup, group.ID, properties); err != nil { 232 log.Error("[Store][Group] remove usergroup", zap.Error(err), zap.String("id", group.ID)) 233 return err 234 } 235 236 if err := cleanLinkStrategy(tx, model.PrincipalGroup, group.ID, group.Owner); err != nil { 237 log.Error("[Store][Group] clean usergroup default strategy", 238 zap.Error(err), zap.String("id", group.ID)) 239 return err 240 } 241 242 if err := tx.Commit(); err != nil { 243 log.Error("[Store][Group] delete usergroupr tx commit", 244 zap.Error(err), zap.String("id", group.ID)) 245 return err 246 } 247 248 return nil 249 } 250 251 // GetGroup get a group 252 func (gs *groupStore) GetGroup(groupID string) (*model.UserGroupDetail, error) { 253 if groupID == "" { 254 return nil, store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf( 255 "get usergroup missing some params, groupID is %s", groupID)) 256 } 257 258 values, err := gs.handler.LoadValues(tblGroup, []string{groupID}, &groupForStore{}) 259 if err != nil { 260 log.Error("[Store][Group] get usergroup by id", zap.Error(err), zap.String("id", groupID)) 261 return nil, err 262 } 263 264 if len(values) == 0 { 265 return nil, nil 266 } 267 268 if len(values) > 1 { 269 return nil, ErrorMultipleGroupFound 270 } 271 272 var ret *model.UserGroupDetail 273 for _, v := range values { 274 ret = convertForGroupDetail(v.(*groupForStore)) 275 break 276 } 277 278 if ret.Valid { 279 return ret, nil 280 } 281 282 return nil, nil 283 } 284 285 // GetGroupByName get a group by name 286 func (gs *groupStore) GetGroupByName(name, owner string) (*model.UserGroup, error) { 287 if name == "" || owner == "" { 288 return nil, store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf( 289 "get usergroup missing some params, name=%s, owner=%s", name, owner)) 290 } 291 292 fields := []string{GroupFieldName, GroupFieldOwner, GroupFieldValid} 293 values, err := gs.handler.LoadValuesByFilter(tblGroup, fields, &groupForStore{}, 294 func(m map[string]interface{}) bool { 295 valid, ok := m[GroupFieldValid].(bool) 296 if ok && !valid { 297 return false 298 } 299 300 saveName := m[GroupFieldName] 301 saveOwner := m[GroupFieldOwner] 302 303 return saveName == name && saveOwner == owner 304 }) 305 306 if err != nil { 307 return nil, err 308 } 309 310 if len(values) == 0 { 311 return nil, nil 312 } 313 314 if len(values) > 1 { 315 return nil, ErrorMultipleGroupFound 316 } 317 var ret *model.UserGroupDetail 318 for _, v := range values { 319 ret = convertForGroupDetail(v.(*groupForStore)) 320 break 321 } 322 return ret.UserGroup, nil 323 } 324 325 // GetGroups get groups 326 func (gs *groupStore) GetGroups(filters map[string]string, offset uint32, 327 limit uint32) (uint32, []*model.UserGroup, error) { 328 329 // 如果本次请求参数携带了 user_id,那么就是查询这个用户所关联的所有用户组 330 if _, ok := filters["user_id"]; ok { 331 return gs.listGroupByUser(filters, offset, limit) 332 } 333 // 正常查询用户组信息 334 return gs.listSimpleGroups(filters, offset, limit) 335 } 336 337 // listSimpleGroups Normal user group query 338 func (gs *groupStore) listSimpleGroups(filters map[string]string, offset uint32, limit uint32) (uint32, 339 []*model.UserGroup, error) { 340 fields := []string{GroupFieldID, GroupFieldOwner, GroupFieldName, GroupFieldValid} 341 values, err := gs.handler.LoadValuesByFilter(tblGroup, fields, &groupForStore{}, 342 func(m map[string]interface{}) bool { 343 valid, ok := m[GroupFieldValid].(bool) 344 if ok && !valid { 345 return false 346 } 347 348 saveId, _ := m[GroupFieldID].(string) 349 saveName, _ := m[GroupFieldName].(string) 350 saveOwner, _ := m[GroupFieldOwner].(string) 351 352 if sId, ok := filters["id"]; ok && sId != saveId { 353 return false 354 } 355 if sName, ok := filters["name"]; ok { 356 if utils.IsPrefixWildName(sName) { 357 sName = sName[:len(sName)-1] 358 } 359 if !strings.Contains(saveName, sName) { 360 return false 361 } 362 } 363 364 if sOwner, ok := filters["owner"]; ok && sOwner != saveOwner { 365 return false 366 } 367 368 return true 369 }) 370 371 if err != nil { 372 return 0, nil, err 373 } 374 375 total := uint32(len(values)) 376 377 return total, doGroupPage(values, offset, limit), nil 378 } 379 380 // listGroupByUser 查询某个用户下所关联的用户组信息 381 func (gs *groupStore) listGroupByUser(filters map[string]string, offset uint32, 382 limit uint32) (uint32, []*model.UserGroup, error) { 383 384 var ( 385 userID = filters["user_id"] 386 owner, existOwner = filters["owner"] 387 fields = []string{GroupFieldUserIds, GroupFieldOwner, GroupFieldValid} 388 ) 389 390 values, err := gs.handler.LoadValuesByFilter(tblGroup, fields, &groupForStore{}, 391 func(m map[string]interface{}) bool { 392 valid, ok := m[GroupFieldValid].(bool) 393 if ok && !valid { 394 return false 395 } 396 saveOwner := m[GroupFieldOwner] 397 if existOwner && saveOwner != owner { 398 return false 399 } 400 401 if sName, ok := filters["name"]; ok { 402 saveName, _ := m[GroupFieldName].(string) 403 if utils.IsPrefixWildName(sName) { 404 sName = sName[:len(sName)-1] 405 } 406 if !strings.Contains(saveName, sName) { 407 return false 408 } 409 } 410 411 saveVal, ok := m[GroupFieldUserIds] 412 if !ok { 413 return false 414 } 415 416 saveUserIds := saveVal.(map[string]string) 417 _, exist := saveUserIds[userID] 418 return exist 419 }) 420 421 if err != nil { 422 return 0, nil, err 423 } 424 425 total := uint32(len(values)) 426 427 return total, doGroupPage(values, offset, limit), nil 428 } 429 430 func doGroupPage(ret map[string]interface{}, offset uint32, limit uint32) []*model.UserGroup { 431 432 groups := make([]*model.UserGroup, 0, len(ret)) 433 434 beginIndex := offset 435 endIndex := beginIndex + limit 436 totalCount := uint32(len(ret)) 437 438 if totalCount == 0 { 439 return groups 440 } 441 if beginIndex >= endIndex { 442 return groups 443 } 444 if beginIndex >= totalCount { 445 return groups 446 } 447 if endIndex > totalCount { 448 endIndex = totalCount 449 } 450 for k := range ret { 451 groups = append(groups, convertForGroupDetail(ret[k].(*groupForStore)).UserGroup) 452 } 453 454 sort.Slice(groups, func(i, j int) bool { 455 return groups[i].ModifyTime.After(groups[j].ModifyTime) 456 }) 457 458 return groups[beginIndex:endIndex] 459 } 460 461 // GetGroupsForCache 查询用户分组数据,主要用于Cache更新 462 func (gs *groupStore) GetGroupsForCache(mtime time.Time, firstUpdate bool) ([]*model.UserGroupDetail, error) { 463 ret, err := gs.handler.LoadValuesByFilter(tblGroup, []string{GroupFieldModifyTime}, &groupForStore{}, 464 func(m map[string]interface{}) bool { 465 mt := m[GroupFieldModifyTime].(time.Time) 466 isAfter := mt.After(mtime) 467 return isAfter 468 }) 469 if err != nil { 470 return nil, err 471 } 472 473 groups := make([]*model.UserGroupDetail, 0, len(ret)) 474 475 for k := range ret { 476 val := ret[k] 477 groups = append(groups, convertForGroupDetail(val.(*groupForStore))) 478 } 479 480 return groups, nil 481 } 482 483 // cleanInValidGroup 清理无效的用户组数据 484 func (gs *groupStore) cleanInValidGroup(tx *bolt.Tx, name, owner string) error { 485 log.Infof("[Store][User] clean usergroup(%s)", name) 486 487 fields := []string{GroupFieldName, GroupFieldValid, GroupFieldOwner} 488 489 values := make(map[string]interface{}) 490 491 err := loadValuesByFilter(tx, tblGroup, fields, &groupForStore{}, 492 func(m map[string]interface{}) bool { 493 valid, ok := m[GroupFieldValid].(bool) 494 // 如果数据是 valid 的,则不能被清理 495 if ok && valid { 496 return false 497 } 498 499 saveName := m[GroupFieldName] 500 saveOwner := m[GroupFieldOwner] 501 502 return saveName == name && saveOwner == owner 503 }, values) 504 505 if err != nil { 506 return err 507 } 508 509 if len(values) == 0 { 510 return nil 511 } 512 513 keys := make([]string, 0, len(values)) 514 for k := range values { 515 keys = append(keys, k) 516 } 517 518 return deleteValues(tx, tblGroup, keys) 519 } 520 521 func convertForGroupStore(group *model.UserGroupDetail) *groupForStore { 522 523 userIds := make(map[string]string, len(group.UserIds)) 524 525 for id := range group.UserIds { 526 userIds[id] = "" 527 } 528 529 return &groupForStore{ 530 ID: group.ID, 531 Name: group.Name, 532 Owner: group.Owner, 533 Token: group.Token, 534 TokenEnable: group.TokenEnable, 535 Valid: group.Valid, 536 Comment: group.Comment, 537 CreateTime: group.CreateTime, 538 ModifyTime: group.ModifyTime, 539 UserIds: userIds, 540 } 541 } 542 543 func convertForGroupDetail(group *groupForStore) *model.UserGroupDetail { 544 userIds := make(map[string]struct{}, len(group.UserIds)) 545 for id := range group.UserIds { 546 userIds[id] = struct{}{} 547 } 548 549 return &model.UserGroupDetail{ 550 UserGroup: &model.UserGroup{ 551 ID: group.ID, 552 Name: group.Name, 553 Owner: group.Owner, 554 Token: group.Token, 555 TokenEnable: group.TokenEnable, 556 Valid: group.Valid, 557 Comment: group.Comment, 558 CreateTime: group.CreateTime, 559 ModifyTime: group.ModifyTime, 560 }, 561 UserIds: userIds, 562 } 563 }