LCOV - code coverage report
Current view: top level - server/schema - SchemaCreatorImpl.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 79 79 100.0 %
Date: 2022-11-19 15:00:39 Functions: 12 13 92.3 %

          Line data    Source code
       1             : // Copyright (C) 2009 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.server.schema;
      16             : 
      17             : import com.google.common.collect.ImmutableSet;
      18             : import com.google.gerrit.common.Nullable;
      19             : import com.google.gerrit.entities.AccountGroup;
      20             : import com.google.gerrit.entities.GroupReference;
      21             : import com.google.gerrit.entities.InternalGroup;
      22             : import com.google.gerrit.exceptions.DuplicateKeyException;
      23             : import com.google.gerrit.git.RefUpdateUtil;
      24             : import com.google.gerrit.metrics.MetricMaker;
      25             : import com.google.gerrit.server.GerritPersonIdent;
      26             : import com.google.gerrit.server.account.GroupUuid;
      27             : import com.google.gerrit.server.account.ServiceUserClassifier;
      28             : import com.google.gerrit.server.config.AllProjectsName;
      29             : import com.google.gerrit.server.config.AllUsersName;
      30             : import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
      31             : import com.google.gerrit.server.git.GitRepositoryManager;
      32             : import com.google.gerrit.server.git.meta.MetaDataUpdate;
      33             : import com.google.gerrit.server.group.db.AuditLogFormatter;
      34             : import com.google.gerrit.server.group.db.GroupConfig;
      35             : import com.google.gerrit.server.group.db.GroupDelta;
      36             : import com.google.gerrit.server.group.db.GroupNameNotes;
      37             : import com.google.gerrit.server.group.db.InternalGroupCreation;
      38             : import com.google.gerrit.server.index.group.GroupIndex;
      39             : import com.google.gerrit.server.index.group.GroupIndexCollection;
      40             : import com.google.gerrit.server.notedb.Sequences;
      41             : import com.google.inject.Inject;
      42             : import java.io.IOException;
      43             : import org.eclipse.jgit.errors.ConfigInvalidException;
      44             : import org.eclipse.jgit.errors.RepositoryNotFoundException;
      45             : import org.eclipse.jgit.lib.BatchRefUpdate;
      46             : import org.eclipse.jgit.lib.Config;
      47             : import org.eclipse.jgit.lib.PersonIdent;
      48             : import org.eclipse.jgit.lib.Repository;
      49             : 
      50             : // TODO(dborowitz): The current NoteDb implementation mirrors the old ReviewDb code: this class is
      51             : // called to create the site early on in NoteDbSchemaUpdater#update. This logic is a little
      52             : // confusing and could stand to be reworked. Another smell is that this is an interface only for
      53             : // testing purposes.
      54             : public class SchemaCreatorImpl implements SchemaCreator {
      55             :   private final GitRepositoryManager repoManager;
      56             :   private final AllProjectsCreator allProjectsCreator;
      57             :   private final AllUsersCreator allUsersCreator;
      58             :   private final AllUsersName allUsersName;
      59             :   private final PersonIdent serverUser;
      60             :   private final GroupIndexCollection indexCollection;
      61             :   private final String serverId;
      62             : 
      63             :   private final Config config;
      64             :   private final MetricMaker metricMaker;
      65             :   private final AllProjectsName allProjectsName;
      66             : 
      67             :   @Inject
      68             :   public SchemaCreatorImpl(
      69             :       GitRepositoryManager repoManager,
      70             :       AllProjectsCreator ap,
      71             :       AllUsersCreator auc,
      72             :       AllUsersName allUsersName,
      73             :       @GerritPersonIdent PersonIdent au,
      74             :       GroupIndexCollection ic,
      75             :       String serverId,
      76             :       Config config,
      77             :       MetricMaker metricMaker,
      78         151 :       AllProjectsName apName) {
      79         151 :     this.repoManager = repoManager;
      80         151 :     allProjectsCreator = ap;
      81         151 :     allUsersCreator = auc;
      82         151 :     this.allUsersName = allUsersName;
      83         151 :     serverUser = au;
      84         151 :     indexCollection = ic;
      85         151 :     this.serverId = serverId;
      86             : 
      87         151 :     this.config = config;
      88         151 :     this.allProjectsName = apName;
      89         151 :     this.metricMaker = metricMaker;
      90         151 :   }
      91             : 
      92             :   @Override
      93             :   public void create() throws IOException, ConfigInvalidException {
      94         151 :     GroupReference admins = createGroupReference("Administrators");
      95         151 :     GroupReference serviceUsers = createGroupReference(ServiceUserClassifier.SERVICE_USERS);
      96             : 
      97             :     AllProjectsInput allProjectsInput =
      98         151 :         AllProjectsInput.builder()
      99         151 :             .administratorsGroup(admins)
     100         151 :             .serviceUsersGroup(serviceUsers)
     101         151 :             .build();
     102         151 :     allProjectsCreator.create(allProjectsInput);
     103             :     // We have to create the All-Users repository before we can use it to store the groups in it.
     104         151 :     allUsersCreator.setAdministrators(admins).create();
     105             : 
     106             :     // Don't rely on injection to construct Sequences, as the default GitReferenceUpdated has a
     107             :     // thick dependency stack which may not all be available at schema creation time.
     108         151 :     Sequences seqs =
     109             :         new Sequences(
     110             :             config,
     111             :             repoManager,
     112             :             GitReferenceUpdated.DISABLED,
     113             :             allProjectsName,
     114             :             allUsersName,
     115             :             metricMaker);
     116         151 :     try (Repository allUsersRepo = repoManager.openRepository(allUsersName)) {
     117         151 :       createAdminsGroup(seqs, allUsersRepo, admins);
     118         151 :       createBatchUsersGroup(seqs, allUsersRepo, serviceUsers, admins.getUUID());
     119             :     }
     120         151 :   }
     121             : 
     122             :   @Override
     123             :   public void ensureCreated() throws IOException, ConfigInvalidException {
     124             :     try {
     125           4 :       repoManager.openRepository(allProjectsName).close();
     126         138 :     } catch (RepositoryNotFoundException e) {
     127         138 :       create();
     128           4 :     }
     129         138 :   }
     130             : 
     131             :   private void createAdminsGroup(
     132             :       Sequences seqs, Repository allUsersRepo, GroupReference groupReference)
     133             :       throws IOException, ConfigInvalidException {
     134         151 :     InternalGroupCreation groupCreation = getGroupCreation(seqs, groupReference);
     135             :     GroupDelta groupDelta =
     136         151 :         GroupDelta.builder().setDescription("Gerrit Site Administrators").build();
     137             : 
     138         151 :     createGroup(allUsersRepo, groupCreation, groupDelta);
     139         151 :   }
     140             : 
     141             :   private void createBatchUsersGroup(
     142             :       Sequences seqs,
     143             :       Repository allUsersRepo,
     144             :       GroupReference groupReference,
     145             :       AccountGroup.UUID adminsGroupUuid)
     146             :       throws IOException, ConfigInvalidException {
     147         151 :     InternalGroupCreation groupCreation = getGroupCreation(seqs, groupReference);
     148             :     GroupDelta groupDelta =
     149         151 :         GroupDelta.builder()
     150         151 :             .setDescription("Users who perform batch actions on Gerrit")
     151         151 :             .setOwnerGroupUUID(adminsGroupUuid)
     152         151 :             .build();
     153             : 
     154         151 :     createGroup(allUsersRepo, groupCreation, groupDelta);
     155         151 :   }
     156             : 
     157             :   private void createGroup(
     158             :       Repository allUsersRepo, InternalGroupCreation groupCreation, GroupDelta groupDelta)
     159             :       throws ConfigInvalidException, IOException {
     160         151 :     InternalGroup createdGroup = createGroupInNoteDb(allUsersRepo, groupCreation, groupDelta);
     161         151 :     index(createdGroup);
     162         151 :   }
     163             : 
     164             :   private InternalGroup createGroupInNoteDb(
     165             :       Repository allUsersRepo, InternalGroupCreation groupCreation, GroupDelta groupDelta)
     166             :       throws ConfigInvalidException, IOException, DuplicateKeyException {
     167             :     // This method is only executed on a new server which doesn't have any accounts or groups.
     168             :     AuditLogFormatter auditLogFormatter =
     169         151 :         AuditLogFormatter.createBackedBy(ImmutableSet.of(), ImmutableSet.of(), serverId);
     170             : 
     171         151 :     GroupConfig groupConfig =
     172         151 :         GroupConfig.createForNewGroup(allUsersName, allUsersRepo, groupCreation);
     173         151 :     groupConfig.setGroupDelta(groupDelta, auditLogFormatter);
     174             : 
     175         151 :     AccountGroup.NameKey groupName = groupDelta.getName().orElseGet(groupCreation::getNameKey);
     176         151 :     GroupNameNotes groupNameNotes =
     177         151 :         GroupNameNotes.forNewGroup(
     178         151 :             allUsersName, allUsersRepo, groupCreation.getGroupUUID(), groupName);
     179             : 
     180         151 :     commit(allUsersRepo, groupConfig, groupNameNotes);
     181             : 
     182         151 :     return groupConfig
     183         151 :         .getLoadedGroup()
     184         151 :         .orElseThrow(() -> new IllegalStateException("Created group wasn't automatically loaded"));
     185             :   }
     186             : 
     187             :   private void commit(
     188             :       Repository allUsersRepo, GroupConfig groupConfig, GroupNameNotes groupNameNotes)
     189             :       throws IOException {
     190         151 :     BatchRefUpdate batchRefUpdate = allUsersRepo.getRefDatabase().newBatchUpdate();
     191         151 :     try (MetaDataUpdate metaDataUpdate = createMetaDataUpdate(allUsersRepo, batchRefUpdate)) {
     192         151 :       groupConfig.commit(metaDataUpdate);
     193             :     }
     194             :     // MetaDataUpdates unfortunately can't be reused. -> Create a new one.
     195         151 :     try (MetaDataUpdate metaDataUpdate = createMetaDataUpdate(allUsersRepo, batchRefUpdate)) {
     196         151 :       groupNameNotes.commit(metaDataUpdate);
     197             :     }
     198         151 :     RefUpdateUtil.executeChecked(batchRefUpdate, allUsersRepo);
     199         151 :   }
     200             : 
     201             :   private MetaDataUpdate createMetaDataUpdate(
     202             :       Repository allUsersRepo, @Nullable BatchRefUpdate batchRefUpdate) {
     203         151 :     MetaDataUpdate metaDataUpdate =
     204             :         new MetaDataUpdate(
     205             :             GitReferenceUpdated.DISABLED, allUsersName, allUsersRepo, batchRefUpdate);
     206         151 :     metaDataUpdate.getCommitBuilder().setAuthor(serverUser);
     207         151 :     metaDataUpdate.getCommitBuilder().setCommitter(serverUser);
     208         151 :     return metaDataUpdate;
     209             :   }
     210             : 
     211             :   private void index(InternalGroup group) {
     212         151 :     for (GroupIndex groupIndex : indexCollection.getWriteIndexes()) {
     213          30 :       groupIndex.replace(group);
     214          30 :     }
     215         151 :   }
     216             : 
     217             :   private GroupReference createGroupReference(String name) {
     218         151 :     AccountGroup.UUID groupUuid = GroupUuid.make(name, serverUser);
     219         151 :     return GroupReference.create(groupUuid, name);
     220             :   }
     221             : 
     222             :   private InternalGroupCreation getGroupCreation(Sequences seqs, GroupReference groupReference) {
     223         151 :     int next = seqs.nextGroupId();
     224         151 :     return InternalGroupCreation.builder()
     225         151 :         .setNameKey(AccountGroup.nameKey(groupReference.getName()))
     226         151 :         .setId(AccountGroup.id(next))
     227         151 :         .setGroupUUID(groupReference.getUUID())
     228         151 :         .build();
     229             :   }
     230             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750