Преглед на файлове

fix(go): roles and groups migration;

Vishal Dalwadi преди 3 месеца
родител
ревизия
3c8730c10e
променени са 6 файла, в които са добавени 185 реда и са изтрити 24 реда
  1. 1 1
      logic/user_mgmt.go
  2. 1 0
      logic/users.go
  3. 3 3
      migrate/migrate.go
  4. 1 1
      pro/initialize.go
  5. 137 5
      pro/logic/migrate.go
  6. 42 14
      pro/logic/user_mgmt.go

+ 1 - 1
logic/user_mgmt.go

@@ -50,7 +50,7 @@ var MigrateUserRoleAndGroups = func(u models.User) {
 
 }
 
-var MigrateGroups = func() {}
+var MigrateToUUIDs = func() {}
 
 var UpdateUserGwAccess = func(currentUser, changeUser models.User) {}
 

+ 1 - 0
logic/users.go

@@ -199,6 +199,7 @@ func ListUserInvites() ([]models.UserInvite, error) {
 func DeleteUserInvite(email string) error {
 	return database.DeleteRecord(database.USER_INVITES_TABLE_NAME, email)
 }
+
 func ValidateAndApproveUserInvite(email, code string) error {
 	in, err := GetUserInvite(email)
 	if err != nil {

+ 3 - 3
migrate/migrate.go

@@ -29,7 +29,7 @@ func Run() {
 	assignSuperAdmin()
 	createDefaultTagsAndPolicies()
 	removeOldUserGrps()
-	syncGroups()
+	migrateToUUIDs()
 	syncUsers()
 	updateHosts()
 	updateNodes()
@@ -394,8 +394,8 @@ func MigrateEmqx() {
 
 }
 
-func syncGroups() {
-	logic.MigrateGroups()
+func migrateToUUIDs() {
+	logic.MigrateToUUIDs()
 }
 
 func syncUsers() {

+ 1 - 1
pro/initialize.go

@@ -136,7 +136,7 @@ func InitPro() {
 	logic.UpdateUserGwAccess = proLogic.UpdateUserGwAccess
 	logic.CreateDefaultUserPolicies = proLogic.CreateDefaultUserPolicies
 	logic.MigrateUserRoleAndGroups = proLogic.MigrateUserRoleAndGroups
-	logic.MigrateGroups = proLogic.MigrateGroups
+	logic.MigrateToUUIDs = proLogic.MigrateToUUIDs
 	logic.IntialiseGroups = proLogic.UserGroupsInit
 	logic.AddGlobalNetRolesToAdmins = proLogic.AddGlobalNetRolesToAdmins
 	logic.GetUserGroupsInNetwork = proLogic.GetUserGroupsInNetwork

+ 137 - 5
pro/logic/migrate.go

@@ -9,13 +9,51 @@ import (
 	"github.com/gravitl/netmaker/models"
 )
 
-func MigrateGroups() {
+func MigrateToUUIDs() {
+	roles, err := ListNetworkRoles()
+	if err != nil {
+		return
+	}
+
+	rolesMapping := make(map[models.UserRoleID]models.UserRoleID)
+
+	for _, role := range roles {
+		if role.Default {
+			continue
+		}
+
+		_, err := uuid.Parse(string(role.ID))
+		if err == nil {
+			// role id is already an uuid, so no need to update
+			continue
+		}
+
+		oldRoleID := role.ID
+		role.ID = models.UserRoleID(uuid.NewString())
+		rolesMapping[oldRoleID] = role.ID
+
+		roleBytes, err := json.Marshal(role)
+		if err != nil {
+			continue
+		}
+
+		err = database.Insert(role.ID.String(), string(roleBytes), database.USER_PERMISSIONS_TABLE_NAME)
+		if err != nil {
+			continue
+		}
+
+		err = database.DeleteRecord(database.USER_PERMISSIONS_TABLE_NAME, oldRoleID.String())
+		if err != nil {
+			continue
+		}
+	}
+
 	groups, err := ListUserGroups()
 	if err != nil {
 		return
 	}
 
-	groupMapping := make(map[models.UserGroupID]models.UserGroupID)
+	groupsMapping := make(map[models.UserGroupID]models.UserGroupID)
 
 	for _, group := range groups {
 		if group.Default {
@@ -30,7 +68,22 @@ func MigrateGroups() {
 
 		oldGroupID := group.ID
 		group.ID = models.UserGroupID(uuid.NewString())
-		groupMapping[oldGroupID] = group.ID
+		groupsMapping[oldGroupID] = group.ID
+
+		var groupPermissions = make(map[models.NetworkID]map[models.UserRoleID]struct{})
+		for networkID, networkRoles := range group.NetworkRoles {
+			groupPermissions[networkID] = make(map[models.UserRoleID]struct{})
+			for roleID := range networkRoles {
+				newRoleID, ok := rolesMapping[roleID]
+				if !ok {
+					groupPermissions[networkID][roleID] = struct{}{}
+				} else {
+					groupPermissions[networkID][newRoleID] = struct{}{}
+				}
+			}
+		}
+
+		group.NetworkRoles = groupPermissions
 
 		groupBytes, err := json.Marshal(group)
 		if err != nil {
@@ -48,6 +101,11 @@ func MigrateGroups() {
 		}
 	}
 
+	// if no changes were made, there are no references to be updated.
+	if len(rolesMapping) == 0 && len(groupsMapping) == 0 {
+		return
+	}
+
 	users, err := logic.GetUsersDB()
 	if err != nil {
 		return
@@ -56,7 +114,7 @@ func MigrateGroups() {
 	for _, user := range users {
 		userGroups := make(map[models.UserGroupID]struct{})
 		for groupID := range user.UserGroups {
-			newGroupID, ok := groupMapping[groupID]
+			newGroupID, ok := groupsMapping[groupID]
 			if !ok {
 				userGroups[groupID] = struct{}{}
 			} else {
@@ -65,7 +123,81 @@ func MigrateGroups() {
 		}
 
 		user.UserGroups = userGroups
-		logic.UpsertUser(user)
+		err = logic.UpsertUser(user)
+		if err != nil {
+			continue
+		}
+	}
+
+	for _, acl := range logic.ListAcls() {
+		srcList := make([]models.AclPolicyTag, len(acl.Src))
+		for i, src := range acl.Src {
+			if src.ID == models.UserGroupAclID {
+				newGroupID, ok := groupsMapping[models.UserGroupID(src.Value)]
+				if ok {
+					src.Value = newGroupID.String()
+				}
+			}
+
+			srcList[i] = src
+		}
+
+		dstList := make([]models.AclPolicyTag, len(acl.Dst))
+		for i, dst := range acl.Dst {
+			if dst.ID == models.UserGroupAclID {
+				newGroupID, ok := groupsMapping[models.UserGroupID(dst.Value)]
+				if ok {
+					dst.Value = newGroupID.String()
+				}
+			}
+
+			dstList[i] = dst
+		}
+
+		err = logic.UpsertAcl(acl)
+		if err != nil {
+			continue
+		}
+	}
+
+	invites, err := logic.ListUserInvites()
+	if err != nil {
+		return
+	}
+
+	for _, invite := range invites {
+		userGroups := make(map[models.UserGroupID]struct{})
+		for groupID := range invite.UserGroups {
+			newGroupID, ok := groupsMapping[groupID]
+			if !ok {
+				invite.UserGroups[groupID] = struct{}{}
+			} else {
+				invite.UserGroups[newGroupID] = struct{}{}
+			}
+		}
+
+		invite.UserGroups = userGroups
+
+		userPermissions := make(map[models.NetworkID]map[models.UserRoleID]struct{})
+
+		for networkID, networkRoles := range invite.NetworkRoles {
+			userPermissions[networkID] = make(map[models.UserRoleID]struct{})
+			for roleID := range networkRoles {
+				newRoleID, ok := rolesMapping[roleID]
+				if !ok {
+					userPermissions[networkID][roleID] = struct{}{}
+				} else {
+					userPermissions[networkID][newRoleID] = struct{}{}
+				}
+			}
+		}
+
+		invite.NetworkRoles = userPermissions
+
+		err = logic.InsertUserInvite(invite)
+		if err != nil {
+			continue
+		}
 	}
 }
 

+ 42 - 14
pro/logic/user_mgmt.go

@@ -18,6 +18,8 @@ import (
 var (
 	globalNetworksAdminGroupID = models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin))
 	globalNetworksUserGroupID  = models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkUser))
+	globalNetworksAdminRoleID  = models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin))
+	globalNetworksUserRoleID   = models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser))
 )
 
 var ServiceUserPermissionTemplate = models.UserRolePermissionTemplate{
@@ -34,7 +36,7 @@ var PlatformUserUserPermissionTemplate = models.UserRolePermissionTemplate{
 }
 
 var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{
-	ID:         models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)),
+	ID:         globalNetworksAdminRoleID,
 	Name:       "Network Admins",
 	MetaData:   "can manage configuration of all networks",
 	Default:    true,
@@ -43,7 +45,7 @@ var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{
 }
 
 var NetworkUserAllPermissionTemplate = models.UserRolePermissionTemplate{
-	ID:         models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)),
+	ID:         globalNetworksUserRoleID,
 	Name:       "Network Users",
 	MetaData:   "Can connect to nodes in your networks via Netmaker Desktop App.",
 	Default:    true,
@@ -123,7 +125,7 @@ func UserGroupsInit() {
 		MetaData: "can manage configuration of all networks",
 		NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{
 			models.AllNetworks: {
-				models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)): {},
+				globalNetworksAdminRoleID: {},
 			},
 		},
 	}
@@ -133,7 +135,7 @@ func UserGroupsInit() {
 		Default: true,
 		NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{
 			models.AllNetworks: {
-				models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)): {},
+				globalNetworksUserRoleID: {},
 			},
 		},
 		MetaData: "Provides read-only dashboard access to platform users and allows connection to network nodes via the Netmaker Desktop App.",
@@ -149,7 +151,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) {
 		return
 	}
 	var NetworkAdminPermissionTemplate = models.UserRolePermissionTemplate{
-		ID:                 models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)),
+		ID:                 GetDefaultNetworkAdminRoleID(netID),
 		Name:               fmt.Sprintf("%s Admin", netID),
 		MetaData:           fmt.Sprintf("can manage your network `%s` configuration.", netID),
 		Default:            true,
@@ -159,7 +161,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) {
 	}
 
 	var NetworkUserPermissionTemplate = models.UserRolePermissionTemplate{
-		ID:                  models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)),
+		ID:                  GetDefaultNetworkUserRoleID(netID),
 		Name:                fmt.Sprintf("%s User", netID),
 		MetaData:            fmt.Sprintf("Can connect to nodes in your network `%s` via Netmaker Desktop App.", netID),
 		Default:             true,
@@ -226,7 +228,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) {
 		Default: true,
 		NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{
 			netID: {
-				models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)): {},
+				GetDefaultNetworkAdminRoleID(netID): {},
 			},
 		},
 		MetaData: fmt.Sprintf("can manage your network `%s` configuration including adding and removing devices.", netID),
@@ -237,7 +239,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) {
 		Default: true,
 		NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{
 			netID: {
-				models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)): {},
+				GetDefaultNetworkUserRoleID(netID): {},
 			},
 		},
 		MetaData: fmt.Sprintf("Can connect to nodes in your network `%s` via Netmaker Desktop App. Platform users will have read-only access to the the dashboard.", netID),
@@ -402,14 +404,32 @@ func ValidateUpdateRoleReq(userRole *models.UserRolePermissionTemplate) error {
 
 // CreateRole - inserts new role into DB
 func CreateRole(r models.UserRolePermissionTemplate) error {
-	// check if role already exists
-	if r.ID.String() == "" {
-		return errors.New("role id cannot be empty")
+	// default roles are currently created directly in the db.
+	// this check is only to prevent future errors.
+	if r.Default && r.ID == "" {
+		return errors.New("role id cannot be empty for default role")
 	}
-	_, err := database.FetchRecord(database.USER_PERMISSIONS_TABLE_NAME, r.ID.String())
-	if err == nil {
-		return errors.New("role already exists")
+
+	if !r.Default {
+		r.ID = models.UserRoleID(uuid.NewString())
 	}
+
+	// check if the role already exists
+	if r.Name == "" {
+		return errors.New("role name cannot be empty")
+	}
+
+	roles, err := ListNetworkRoles()
+	if err != nil {
+		return err
+	}
+
+	for _, role := range roles {
+		if role.Name == r.Name {
+			return errors.New("role already exists")
+		}
+	}
+
 	d, err := json.Marshal(r)
 	if err != nil {
 		return err
@@ -585,6 +605,14 @@ func GetDefaultNetworkUserGroupID(networkID models.NetworkID) models.UserGroupID
 	return models.UserGroupID(fmt.Sprintf("%s-%s-grp", networkID, models.NetworkUser))
 }
 
+func GetDefaultNetworkAdminRoleID(networkID models.NetworkID) models.UserRoleID {
+	return models.UserRoleID(fmt.Sprintf("%s-%s", networkID, models.NetworkAdmin))
+}
+
+func GetDefaultNetworkUserRoleID(networkID models.NetworkID) models.UserRoleID {
+	return models.UserRoleID(fmt.Sprintf("%s-%s", networkID, models.NetworkUser))
+}
+
 // ListUserGroups - lists user groups
 func ListUserGroups() ([]models.UserGroup, error) {
 	data, err := database.FetchRecords(database.USER_GROUPS_TABLE_NAME)