Migrate AccountGroup owner Id to UUID
Only internal groups have an Id and future support for external groups will only have a UUID. This change is needed because existing LDAP groups have an Id and may be the owner of an internal group. In order to ease the future migration, allow internal groups to be owned by a UUID. Change-Id: I126e79667e17b2113007c1c300f5f40c0bb4f9c0
This commit is contained in:
		| @@ -40,7 +40,7 @@ public class GroupControl { | ||||
|       if (group == null) { | ||||
|         throw new NoSuchGroupException(groupId); | ||||
|       } | ||||
|       return new GroupControl(groupCache, user.get(), group); | ||||
|       return new GroupControl(user.get(), group); | ||||
|     } | ||||
|  | ||||
|     public GroupControl controlFor(final AccountGroup.UUID groupId) | ||||
| @@ -49,11 +49,11 @@ public class GroupControl { | ||||
|       if (group == null) { | ||||
|         throw new NoSuchGroupException(groupId); | ||||
|       } | ||||
|       return new GroupControl(groupCache, user.get(), group); | ||||
|       return new GroupControl(user.get(), group); | ||||
|     } | ||||
|  | ||||
|     public GroupControl controlFor(final AccountGroup group) { | ||||
|       return new GroupControl(groupCache, user.get(), group); | ||||
|       return new GroupControl(user.get(), group); | ||||
|     } | ||||
|  | ||||
|     public GroupControl validateFor(final AccountGroup.Id groupId) | ||||
| @@ -66,13 +66,11 @@ public class GroupControl { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private final GroupCache groupCache; | ||||
|   private final CurrentUser user; | ||||
|   private final AccountGroup group; | ||||
|   private Boolean isOwner; | ||||
|  | ||||
|   GroupControl(GroupCache g, CurrentUser who, AccountGroup gc) { | ||||
|     groupCache = g; | ||||
|   GroupControl(CurrentUser who, AccountGroup gc) { | ||||
|     user = who; | ||||
|     group = gc; | ||||
|   } | ||||
| @@ -94,8 +92,7 @@ public class GroupControl { | ||||
|  | ||||
|   public boolean isOwner() { | ||||
|     if (isOwner == null) { | ||||
|       AccountGroup g = groupCache.get(group.getOwnerGroupId()); | ||||
|       AccountGroup.UUID ownerUUID = g != null ? g.getGroupUUID() : null; | ||||
|       AccountGroup.UUID ownerUUID = group.getOwnerGroupUUID(); | ||||
|       isOwner = getCurrentUser().getEffectiveGroups().contains(ownerUUID) | ||||
|              || getCurrentUser().getCapabilities().canAdministrateServer(); | ||||
|     } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| package com.google.gerrit.server.account; | ||||
|  | ||||
| import com.google.gerrit.common.data.GroupDetail; | ||||
| import com.google.gerrit.common.data.GroupReference; | ||||
| import com.google.gerrit.common.errors.NoSuchGroupException; | ||||
| import com.google.gerrit.reviewdb.client.Account; | ||||
| import com.google.gerrit.reviewdb.client.AccountGroup; | ||||
| @@ -66,7 +67,10 @@ public class GroupDetailFactory implements Callable<GroupDetail> { | ||||
|     final AccountGroup group = control.getAccountGroup(); | ||||
|     final GroupDetail detail = new GroupDetail(); | ||||
|     detail.setGroup(group); | ||||
|     detail.setOwnerGroup(groupCache.get(group.getOwnerGroupId())); | ||||
|     AccountGroup ownerGroup = groupCache.get(group.getGroupUUID()); | ||||
|     if (ownerGroup != null) { | ||||
|       detail.setOwnerGroup(GroupReference.forGroup(ownerGroup)); | ||||
|     } | ||||
|     switch (group.getType()) { | ||||
|       case INTERNAL: | ||||
|         detail.setMembers(loadMembers()); | ||||
|   | ||||
| @@ -107,7 +107,10 @@ public class PerformCreateGroup { | ||||
|     final AccountGroup group = new AccountGroup(nameKey, groupId, uuid); | ||||
|     group.setVisibleToAll(visibleToAll); | ||||
|     if (ownerGroupId != null) { | ||||
|       group.setOwnerGroupId(ownerGroupId); | ||||
|       AccountGroup ownerGroup = groupCache.get(ownerGroupId); | ||||
|       if (ownerGroup != null) { | ||||
|         group.setOwnerGroupUUID(ownerGroup.getGroupUUID()); | ||||
|       } | ||||
|     } | ||||
|     if (groupDescription != null) { | ||||
|       group.setDescription(groupDescription); | ||||
|   | ||||
| @@ -161,7 +161,7 @@ public class SchemaCreator { | ||||
|     anonymous = | ||||
|         newGroup(c, "Anonymous Users", AccountGroup.ANONYMOUS_USERS); | ||||
|     anonymous.setDescription("Any user, signed-in or not"); | ||||
|     anonymous.setOwnerGroupId(admin.getId()); | ||||
|     anonymous.setOwnerGroupUUID(admin.getGroupUUID()); | ||||
|     anonymous.setType(AccountGroup.Type.SYSTEM); | ||||
|     c.accountGroups().insert(Collections.singleton(anonymous)); | ||||
|     c.accountGroupNames().insert( | ||||
| @@ -170,7 +170,7 @@ public class SchemaCreator { | ||||
|     registered = | ||||
|         newGroup(c, "Registered Users", AccountGroup.REGISTERED_USERS); | ||||
|     registered.setDescription("Any signed-in user"); | ||||
|     registered.setOwnerGroupId(admin.getId()); | ||||
|     registered.setOwnerGroupUUID(admin.getGroupUUID()); | ||||
|     registered.setType(AccountGroup.Type.SYSTEM); | ||||
|     c.accountGroups().insert(Collections.singleton(registered)); | ||||
|     c.accountGroupNames().insert( | ||||
| @@ -178,7 +178,7 @@ public class SchemaCreator { | ||||
|  | ||||
|     final AccountGroup batchUsers = newGroup(c, "Non-Interactive Users", null); | ||||
|     batchUsers.setDescription("Users who perform batch actions on Gerrit"); | ||||
|     batchUsers.setOwnerGroupId(admin.getId()); | ||||
|     batchUsers.setOwnerGroupUUID(admin.getGroupUUID()); | ||||
|     batchUsers.setType(AccountGroup.Type.INTERNAL); | ||||
|     c.accountGroups().insert(Collections.singleton(batchUsers)); | ||||
|     c.accountGroupNames().insert( | ||||
| @@ -186,7 +186,7 @@ public class SchemaCreator { | ||||
|  | ||||
|     owners = newGroup(c, "Project Owners", AccountGroup.PROJECT_OWNERS); | ||||
|     owners.setDescription("Any owner of the project"); | ||||
|     owners.setOwnerGroupId(admin.getId()); | ||||
|     owners.setOwnerGroupUUID(admin.getGroupUUID()); | ||||
|     owners.setType(AccountGroup.Type.SYSTEM); | ||||
|     c.accountGroups().insert(Collections.singleton(owners)); | ||||
|     c.accountGroupNames().insert( | ||||
|   | ||||
| @@ -32,7 +32,7 @@ import java.util.List; | ||||
| /** A version of the database schema. */ | ||||
| public abstract class SchemaVersion { | ||||
|   /** The current schema version. */ | ||||
|   public static final Class<Schema_66> C = Schema_66.class; | ||||
|   public static final Class<Schema_67> C = Schema_67.class; | ||||
|  | ||||
|   public static class Module extends AbstractModule { | ||||
|     @Override | ||||
|   | ||||
| @@ -101,15 +101,15 @@ public class Schema_65 extends SchemaVersion { | ||||
|       ui.message("Moved contributor agreements to project.config"); | ||||
|  | ||||
|       // Create the auto verify groups. | ||||
|       List<AccountGroup.Id> adminGroupIds = getAdministrateServerGroups(db, config); | ||||
|       List<AccountGroup.UUID> adminGroupUUIDs = getAdministrateServerGroups(db, config); | ||||
|       for (ContributorAgreement agreement : agreements.values()) { | ||||
|         if (agreement.getAutoVerify() != null) { | ||||
|           getOrCreateGroupForIndividuals(db, config, adminGroupIds, agreement); | ||||
|           getOrCreateGroupForIndividuals(db, config, adminGroupUUIDs, agreement); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // Scan AccountAgreement | ||||
|       long minTime = addAccountAgreements(db, config, adminGroupIds, agreements); | ||||
|       long minTime = addAccountAgreements(db, config, adminGroupUUIDs, agreements); | ||||
|  | ||||
|       ProjectConfig base = ProjectConfig.read(md, null); | ||||
|       for (ContributorAgreement agreement : agreements.values()) { | ||||
| @@ -257,14 +257,14 @@ public class Schema_65 extends SchemaVersion { | ||||
|   } | ||||
|  | ||||
|   private AccountGroup createGroup(ReviewDb db, String groupName, | ||||
|       AccountGroup.Id adminGroupId, String description) | ||||
|       AccountGroup.UUID adminGroupUUID, String description) | ||||
|           throws OrmException { | ||||
|     final AccountGroup.Id groupId = | ||||
|         new AccountGroup.Id(db.nextAccountGroupId()); | ||||
|     final AccountGroup.NameKey nameKey = new AccountGroup.NameKey(groupName); | ||||
|     final AccountGroup.UUID uuid = GroupUUID.make(groupName, serverUser); | ||||
|     final AccountGroup group = new AccountGroup(nameKey, groupId, uuid); | ||||
|     group.setOwnerGroupId(adminGroupId); | ||||
|     group.setOwnerGroupUUID(adminGroupUUID); | ||||
|     group.setDescription(description); | ||||
|     final AccountGroupName gn = new AccountGroupName(group); | ||||
|     // first insert the group name to validate that the group name hasn't | ||||
| @@ -274,21 +274,17 @@ public class Schema_65 extends SchemaVersion { | ||||
|     return group; | ||||
|   } | ||||
|  | ||||
|   private List<AccountGroup.Id> getAdministrateServerGroups( | ||||
|       ReviewDb db, ProjectConfig cfg) throws OrmException { | ||||
|   private List<AccountGroup.UUID> getAdministrateServerGroups( | ||||
|       ReviewDb db, ProjectConfig cfg) { | ||||
|     List<PermissionRule> rules = cfg.getAccessSection(AccessSection.GLOBAL_CAPABILITIES) | ||||
|        .getPermission(GlobalCapability.ADMINISTRATE_SERVER) | ||||
|        .getRules(); | ||||
|  | ||||
|     List<AccountGroup.Id> groups = | ||||
|     List<AccountGroup.UUID> groups = | ||||
|         Lists.newArrayListWithExpectedSize(rules.size()); | ||||
|     for (PermissionRule rule : rules) { | ||||
|       if (rule.getAction() == Action.ALLOW) { | ||||
|         groups.add(db.accountGroups() | ||||
|             .byUUID(rule.getGroup().getUUID()) | ||||
|             .toList() | ||||
|             .get(0) | ||||
|             .getId()); | ||||
|         groups.add(rule.getGroup().getUUID()); | ||||
|       } | ||||
|     } | ||||
|     if (groups.isEmpty()) { | ||||
| @@ -299,7 +295,7 @@ public class Schema_65 extends SchemaVersion { | ||||
|   } | ||||
|  | ||||
|   private GroupReference getOrCreateGroupForIndividuals(ReviewDb db, | ||||
|       ProjectConfig config, List<AccountGroup.Id> adminGroupIds, | ||||
|       ProjectConfig config, List<AccountGroup.UUID> adminGroupUUIDs, | ||||
|       ContributorAgreement agreement) | ||||
|           throws OrmException { | ||||
|     if (!agreement.getAccepted().isEmpty()) { | ||||
| @@ -317,12 +313,12 @@ public class Schema_65 extends SchemaVersion { | ||||
|             "account group name exists but account group does not: " + name); | ||||
|       } | ||||
|  | ||||
|       if (!adminGroupIds.contains(ag.getOwnerGroupId())) { | ||||
|       if (!adminGroupUUIDs.contains(ag.getOwnerGroupUUID())) { | ||||
|         throw new IllegalStateException( | ||||
|             "individual group exists with non admin owner group: " + name); | ||||
|       } | ||||
|     } else { | ||||
|       ag = createGroup(db, name, adminGroupIds.get(0), | ||||
|       ag = createGroup(db, name, adminGroupUUIDs.get(0), | ||||
|           String.format("Users who have accepted the %s CLA", agreement.getName())); | ||||
|     } | ||||
|     GroupReference group = config.resolve(ag); | ||||
| @@ -344,7 +340,7 @@ public class Schema_65 extends SchemaVersion { | ||||
|   } | ||||
|  | ||||
|   private long addAccountAgreements(ReviewDb db, ProjectConfig config, | ||||
|       List<AccountGroup.Id> adminGroupIds, | ||||
|       List<AccountGroup.UUID> adminGroupUUIDs, | ||||
|       Map<Integer, ContributorAgreement> agreements) | ||||
|           throws SQLException, OrmException { | ||||
|     Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); | ||||
| @@ -373,7 +369,7 @@ public class Schema_65 extends SchemaVersion { | ||||
|  | ||||
|           // Enter Agreement | ||||
|           GroupReference individualGroup = | ||||
|               getOrCreateGroupForIndividuals(db, config, adminGroupIds, agreement); | ||||
|               getOrCreateGroupForIndividuals(db, config, adminGroupUUIDs, agreement); | ||||
|           AccountGroup.Id groupId = db.accountGroups() | ||||
|               .byUUID(individualGroup.getUUID()) | ||||
|               .toList() | ||||
|   | ||||
| @@ -0,0 +1,95 @@ | ||||
| // Copyright (C) 2012 The Android Open Source Project | ||||
| // | ||||
| // 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 com.google.gerrit.server.schema; | ||||
|  | ||||
| import com.google.common.collect.Iterables; | ||||
| import com.google.common.collect.Lists; | ||||
| import com.google.common.collect.Maps; | ||||
| import com.google.common.collect.Sets; | ||||
| import com.google.gerrit.common.data.ContributorAgreement; | ||||
| import com.google.gerrit.reviewdb.client.AccountGroup; | ||||
| import com.google.gerrit.reviewdb.server.ReviewDb; | ||||
| import com.google.gwtorm.jdbc.JdbcSchema; | ||||
| import com.google.gwtorm.server.OrmException; | ||||
| import com.google.inject.Inject; | ||||
| import com.google.inject.Provider; | ||||
| import java.sql.ResultSet; | ||||
| import java.sql.SQLException; | ||||
| import java.sql.Statement; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Map.Entry; | ||||
| import java.util.Set; | ||||
|  | ||||
| public class Schema_67 extends SchemaVersion { | ||||
|  | ||||
|   @Inject | ||||
|   Schema_67(Provider<Schema_66> prior) { | ||||
|     super(prior); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   protected void migrateData(ReviewDb db, UpdateUI ui) | ||||
|       throws OrmException, SQLException { | ||||
|     ui.message("Update ownerGroupId to ownerGroupUUID"); | ||||
|  | ||||
|     // Scan all AccountGroup, and find the ones that need the owner_group_id | ||||
|     // migrated to owner_group_uuid. | ||||
|     Map<AccountGroup.Id, AccountGroup.Id> idMap = Maps.newHashMap(); | ||||
|     Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); | ||||
|     try { | ||||
|       ResultSet rs = stmt.executeQuery( | ||||
|           "SELECT group_id, owner_group_id FROM account_groups" | ||||
|           + " WHERE owner_group_uuid is NULL or owner_group_uuid =''"); | ||||
|       try { | ||||
|         Map<Integer, ContributorAgreement> agreements = Maps.newHashMap(); | ||||
|         while (rs.next()) { | ||||
|           AccountGroup.Id groupId = new AccountGroup.Id(rs.getInt(1)); | ||||
|           AccountGroup.Id ownerId = new AccountGroup.Id(rs.getInt(2)); | ||||
|           idMap.put(groupId, ownerId); | ||||
|         } | ||||
|       } finally { | ||||
|         rs.close(); | ||||
|       } | ||||
|     } finally { | ||||
|       stmt.close(); | ||||
|     } | ||||
|  | ||||
|     // Lookup up all groups by ID. | ||||
|     Set<AccountGroup.Id> all = | ||||
|         Sets.newHashSet(Iterables.concat(idMap.keySet(), idMap.values())); | ||||
|     Map<AccountGroup.Id, AccountGroup> groups = Maps.newHashMap(); | ||||
|     com.google.gwtorm.server.ResultSet<AccountGroup> rs = | ||||
|         db.accountGroups().get(all); | ||||
|     try { | ||||
|       for (AccountGroup group : rs) { | ||||
|         groups.put(group.getId(), group); | ||||
|       } | ||||
|     } finally { | ||||
|       rs.close(); | ||||
|     } | ||||
|  | ||||
|     // Update the ownerGroupUUID. | ||||
|     List<AccountGroup> toUpdate = Lists.newArrayListWithCapacity(idMap.size()); | ||||
|     for (Entry<AccountGroup.Id, AccountGroup.Id> entry : idMap.entrySet()) { | ||||
|       AccountGroup group = groups.get(entry.getKey()); | ||||
|       AccountGroup owner = groups.get(entry.getValue()); | ||||
|       group.setOwnerGroupUUID(owner.getGroupUUID()); | ||||
|       toUpdate.add(group); | ||||
|     } | ||||
|  | ||||
|     db.accountGroups().update(toUpdate); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Colby Ranger
					Colby Ranger