LCOV - code coverage report
Current view: top level - pgm/init - BaseInit.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 104 203 51.2 %
Date: 2022-11-19 15:00:39 Functions: 18 42 42.9 %

          Line data    Source code
       1             : // Copyright (C) 2013 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.pgm.init;
      16             : 
      17             : import static com.google.inject.Scopes.SINGLETON;
      18             : import static com.google.inject.Stage.PRODUCTION;
      19             : 
      20             : import com.google.common.base.MoreObjects;
      21             : import com.google.common.base.Strings;
      22             : import com.google.common.flogger.FluentLogger;
      23             : import com.google.gerrit.common.Die;
      24             : import com.google.gerrit.common.IoUtil;
      25             : import com.google.gerrit.common.Nullable;
      26             : import com.google.gerrit.exceptions.StorageException;
      27             : import com.google.gerrit.index.IndexType;
      28             : import com.google.gerrit.metrics.DisabledMetricMaker;
      29             : import com.google.gerrit.metrics.MetricMaker;
      30             : import com.google.gerrit.pgm.init.api.ConsoleUI;
      31             : import com.google.gerrit.pgm.init.api.InitFlags;
      32             : import com.google.gerrit.pgm.init.api.InstallAllPlugins;
      33             : import com.google.gerrit.pgm.init.api.InstallPlugins;
      34             : import com.google.gerrit.pgm.init.api.LibraryDownload;
      35             : import com.google.gerrit.pgm.init.index.IndexManagerOnInit;
      36             : import com.google.gerrit.pgm.init.index.IndexModuleOnInit;
      37             : import com.google.gerrit.pgm.init.index.lucene.LuceneIndexModuleOnInit;
      38             : import com.google.gerrit.pgm.util.SiteProgram;
      39             : import com.google.gerrit.server.config.GerritServerConfigModule;
      40             : import com.google.gerrit.server.config.SitePath;
      41             : import com.google.gerrit.server.config.SitePaths;
      42             : import com.google.gerrit.server.git.GitRepositoryManager;
      43             : import com.google.gerrit.server.index.IndexModule;
      44             : import com.google.gerrit.server.plugins.JarScanner;
      45             : import com.google.gerrit.server.schema.NoteDbSchemaUpdater;
      46             : import com.google.gerrit.server.schema.UpdateUI;
      47             : import com.google.gerrit.server.securestore.SecureStore;
      48             : import com.google.gerrit.server.securestore.SecureStoreClassName;
      49             : import com.google.gerrit.server.securestore.SecureStoreProvider;
      50             : import com.google.inject.AbstractModule;
      51             : import com.google.inject.CreationException;
      52             : import com.google.inject.Guice;
      53             : import com.google.inject.Inject;
      54             : import com.google.inject.Injector;
      55             : import com.google.inject.Module;
      56             : import com.google.inject.TypeLiteral;
      57             : import com.google.inject.spi.Message;
      58             : import com.google.inject.util.Providers;
      59             : import java.io.FileNotFoundException;
      60             : import java.io.IOException;
      61             : import java.lang.reflect.InvocationTargetException;
      62             : import java.nio.file.FileVisitResult;
      63             : import java.nio.file.Files;
      64             : import java.nio.file.Path;
      65             : import java.nio.file.Paths;
      66             : import java.nio.file.SimpleFileVisitor;
      67             : import java.nio.file.attribute.BasicFileAttributes;
      68             : import java.util.ArrayList;
      69             : import java.util.Collections;
      70             : import java.util.List;
      71             : import java.util.Set;
      72             : 
      73             : /** Initialize a new Gerrit installation. */
      74             : public class BaseInit extends SiteProgram {
      75          15 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      76             : 
      77             :   private final boolean standalone;
      78             :   protected final PluginsDistribution pluginsDistribution;
      79             :   private final List<String> pluginsToInstall;
      80             : 
      81             :   private Injector sysInjector;
      82             : 
      83          15 :   protected BaseInit(PluginsDistribution pluginsDistribution, List<String> pluginsToInstall) {
      84          15 :     this.standalone = true;
      85          15 :     this.pluginsDistribution = pluginsDistribution;
      86          15 :     this.pluginsToInstall = pluginsToInstall;
      87          15 :   }
      88             : 
      89             :   public BaseInit(
      90             :       Path sitePath,
      91             :       boolean standalone,
      92             :       PluginsDistribution pluginsDistribution,
      93             :       List<String> pluginsToInstall) {
      94           0 :     super(sitePath);
      95           0 :     this.standalone = standalone;
      96           0 :     this.pluginsDistribution = pluginsDistribution;
      97           0 :     this.pluginsToInstall = pluginsToInstall;
      98           0 :   }
      99             : 
     100             :   @Override
     101             :   public int run() throws Exception {
     102          15 :     final SiteInit init = createSiteInit();
     103          15 :     if (beforeInit(init)) {
     104           0 :       return 0;
     105             :     }
     106             : 
     107          15 :     init.flags.autoStart = getAutoStart() && init.site.isNew;
     108          15 :     init.flags.dev = isDev() && init.site.isNew;
     109          15 :     init.flags.skipPlugins = skipPlugins();
     110          15 :     init.flags.deleteCaches = getDeleteCaches();
     111          15 :     init.flags.isNew = init.site.isNew;
     112             : 
     113             :     final SiteRun run;
     114             :     try {
     115          15 :       init.initializer.run();
     116          15 :       init.flags.deleteOnFailure = false;
     117             : 
     118          15 :       Injector sysInjector = createSysInjector(init);
     119          15 :       IndexManagerOnInit indexManager = sysInjector.getInstance(IndexManagerOnInit.class);
     120             :       try {
     121          15 :         indexManager.start();
     122          15 :         run = createSiteRun(init);
     123             :         try {
     124          15 :           run.upgradeSchema();
     125           0 :         } catch (StorageException e) {
     126           0 :           String msg = "Couldn't upgrade schema. Expected if slave and read-only database";
     127           0 :           System.err.println(msg);
     128           0 :           logger.atSevere().withCause(e).log("%s", msg);
     129          15 :         }
     130             : 
     131          15 :         init.initializer.postRun(sysInjector);
     132             :       } finally {
     133          15 :         indexManager.stop();
     134             :       }
     135           0 :     } catch (Exception | Error failure) {
     136           0 :       if (init.flags.deleteOnFailure) {
     137           0 :         recursiveDelete(getSitePath());
     138             :       }
     139           0 :       throw failure;
     140          15 :     }
     141             : 
     142          15 :     System.err.println("Initialized " + getSitePath().toRealPath().normalize());
     143          15 :     afterInit(run);
     144          15 :     return 0;
     145             :   }
     146             : 
     147             :   protected boolean skipPlugins() {
     148           0 :     return false;
     149             :   }
     150             : 
     151             :   protected String getSecureStoreLib() {
     152           0 :     return null;
     153             :   }
     154             : 
     155             :   protected boolean skipAllDownloads() {
     156           0 :     return false;
     157             :   }
     158             : 
     159             :   protected List<String> getSkippedDownloads() {
     160           0 :     return Collections.emptyList();
     161             :   }
     162             : 
     163             :   /**
     164             :    * Invoked before site init is called.
     165             :    *
     166             :    * @param init initializer instance.
     167             :    */
     168             :   protected boolean beforeInit(SiteInit init) throws Exception {
     169           0 :     return false;
     170             :   }
     171             : 
     172             :   /**
     173             :    * Invoked after site init is called.
     174             :    *
     175             :    * @param run completed run instance.
     176             :    */
     177           0 :   protected void afterInit(SiteRun run) throws Exception {}
     178             : 
     179             :   @Nullable
     180             :   protected List<String> getInstallPlugins() {
     181             :     try {
     182           0 :       if (pluginsToInstall != null && pluginsToInstall.isEmpty()) {
     183           0 :         return Collections.emptyList();
     184             :       }
     185           0 :       List<String> names = pluginsDistribution.listPluginNames();
     186           0 :       if (pluginsToInstall != null) {
     187           0 :         names.removeIf(n -> !pluginsToInstall.contains(n));
     188             :       }
     189           0 :       return names;
     190           0 :     } catch (FileNotFoundException e) {
     191           0 :       logger.atWarning().log(
     192             :           "Couldn't find distribution archive location. No plugin will be installed");
     193           0 :       return null;
     194             :     }
     195             :   }
     196             : 
     197             :   protected boolean installAllPlugins() {
     198           0 :     return false;
     199             :   }
     200             : 
     201             :   protected boolean getAutoStart() {
     202           0 :     return false;
     203             :   }
     204             : 
     205             :   public static class SiteInit {
     206             :     public final SitePaths site;
     207             :     final InitFlags flags;
     208             :     final ConsoleUI ui;
     209             :     final SitePathInitializer initializer;
     210             : 
     211             :     @Inject
     212             :     SiteInit(
     213             :         final SitePaths site,
     214             :         final InitFlags flags,
     215             :         final ConsoleUI ui,
     216          15 :         final SitePathInitializer initializer) {
     217          15 :       this.site = site;
     218          15 :       this.flags = flags;
     219          15 :       this.ui = ui;
     220          15 :       this.initializer = initializer;
     221          15 :     }
     222             :   }
     223             : 
     224             :   private SiteInit createSiteInit() {
     225          15 :     final ConsoleUI ui = getConsoleUI();
     226          15 :     final Path sitePath = getSitePath();
     227          15 :     final List<Module> m = new ArrayList<>();
     228          15 :     final SecureStoreInitData secureStoreInitData = discoverSecureStoreClass();
     229          15 :     final String currentSecureStoreClassName = getConfiguredSecureStoreClass();
     230             : 
     231          15 :     if (secureStoreInitData != null
     232             :         && currentSecureStoreClassName != null
     233           0 :         && !currentSecureStoreClassName.equals(secureStoreInitData.className)) {
     234           0 :       String err =
     235           0 :           String.format(
     236             :               "Different secure store was previously configured: %s. "
     237             :                   + "Use SwitchSecureStore program to switch between implementations.",
     238             :               currentSecureStoreClassName);
     239           0 :       throw die(err);
     240             :     }
     241             : 
     242          15 :     m.add(new GerritServerConfigModule());
     243          15 :     m.add(new InitModule(standalone));
     244          15 :     m.add(
     245          15 :         new AbstractModule() {
     246             :           @Override
     247             :           protected void configure() {
     248          15 :             bind(ConsoleUI.class).toInstance(ui);
     249          15 :             bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
     250          15 :             List<String> plugins = MoreObjects.firstNonNull(getInstallPlugins(), new ArrayList<>());
     251          15 :             bind(new TypeLiteral<List<String>>() {})
     252          15 :                 .annotatedWith(InstallPlugins.class)
     253          15 :                 .toInstance(plugins);
     254          15 :             bind(new TypeLiteral<Boolean>() {})
     255          15 :                 .annotatedWith(InstallAllPlugins.class)
     256          15 :                 .toInstance(installAllPlugins());
     257          15 :             bind(PluginsDistribution.class).toInstance(pluginsDistribution);
     258             : 
     259             :             String secureStoreClassName;
     260          15 :             if (secureStoreInitData != null) {
     261           0 :               secureStoreClassName = secureStoreInitData.className;
     262             :             } else {
     263          15 :               secureStoreClassName = currentSecureStoreClassName;
     264             :             }
     265          15 :             if (secureStoreClassName != null) {
     266          15 :               ui.message("Using secure store: %s\n", secureStoreClassName);
     267             :             }
     268          15 :             bind(SecureStoreInitData.class).toProvider(Providers.of(secureStoreInitData));
     269          15 :             bind(String.class)
     270          15 :                 .annotatedWith(SecureStoreClassName.class)
     271          15 :                 .toProvider(Providers.of(secureStoreClassName));
     272          15 :             bind(SecureStore.class).toProvider(SecureStoreProvider.class).in(SINGLETON);
     273          15 :             bind(new TypeLiteral<List<String>>() {})
     274          15 :                 .annotatedWith(LibraryDownload.class)
     275          15 :                 .toInstance(getSkippedDownloads());
     276          15 :             bind(Boolean.class).annotatedWith(LibraryDownload.class).toInstance(skipAllDownloads());
     277             : 
     278          15 :             bind(MetricMaker.class).to(DisabledMetricMaker.class);
     279          15 :           }
     280             :         });
     281             : 
     282             :     try {
     283          15 :       return Guice.createInjector(PRODUCTION, m).getInstance(SiteInit.class);
     284           0 :     } catch (CreationException ce) {
     285           0 :       final Message first = ce.getErrorMessages().iterator().next();
     286           0 :       Throwable why = first.getCause();
     287             : 
     288           0 :       if (why instanceof Die) {
     289           0 :         throw (Die) why;
     290             :       }
     291             : 
     292           0 :       final StringBuilder buf = new StringBuilder(ce.getMessage());
     293           0 :       while (why != null) {
     294           0 :         buf.append("\n");
     295           0 :         buf.append(why.getMessage());
     296           0 :         why = why.getCause();
     297           0 :         if (why != null) {
     298           0 :           buf.append("\n  caused by ");
     299             :         }
     300             :       }
     301           0 :       throw die(buf.toString(), new RuntimeException("InitInjector failed", ce));
     302             :     }
     303             :   }
     304             : 
     305             :   protected ConsoleUI getConsoleUI() {
     306           0 :     return ConsoleUI.getInstance(false);
     307             :   }
     308             : 
     309             :   @Nullable
     310             :   private SecureStoreInitData discoverSecureStoreClass() {
     311          15 :     String secureStore = getSecureStoreLib();
     312          15 :     if (Strings.isNullOrEmpty(secureStore)) {
     313          15 :       return null;
     314             :     }
     315             : 
     316           0 :     Path secureStoreLib = Paths.get(secureStore);
     317           0 :     if (!Files.exists(secureStoreLib)) {
     318           0 :       throw new InvalidSecureStoreException(String.format("File %s doesn't exist", secureStore));
     319             :     }
     320           0 :     try (JarScanner scanner = new JarScanner(secureStoreLib)) {
     321           0 :       List<String> secureStores = scanner.findSubClassesOf(SecureStore.class);
     322           0 :       if (secureStores.isEmpty()) {
     323           0 :         throw new InvalidSecureStoreException(
     324           0 :             String.format(
     325             :                 "Cannot find class implementing %s interface in %s",
     326           0 :                 SecureStore.class.getName(), secureStore));
     327             :       }
     328           0 :       if (secureStores.size() > 1) {
     329           0 :         throw new InvalidSecureStoreException(
     330           0 :             String.format(
     331             :                 "%s has more that one implementation of %s interface",
     332           0 :                 secureStore, SecureStore.class.getName()));
     333             :       }
     334           0 :       IoUtil.loadJARs(secureStoreLib);
     335           0 :       return new SecureStoreInitData(secureStoreLib, secureStores.get(0));
     336           0 :     } catch (IOException e) {
     337           0 :       throw new InvalidSecureStoreException(String.format("%s is not a valid jar", secureStore), e);
     338             :     }
     339             :   }
     340             : 
     341             :   public static class SiteRun {
     342             :     public final ConsoleUI ui;
     343             :     public final SitePaths site;
     344             :     public final InitFlags flags;
     345             :     final NoteDbSchemaUpdater noteDbSchemaUpdater;
     346             :     final GitRepositoryManager repositoryManager;
     347             : 
     348             :     @Inject
     349             :     SiteRun(
     350             :         ConsoleUI ui,
     351             :         SitePaths site,
     352             :         InitFlags flags,
     353             :         NoteDbSchemaUpdater noteDbSchemaUpdater,
     354          15 :         GitRepositoryManager repositoryManager) {
     355          15 :       this.ui = ui;
     356          15 :       this.site = site;
     357          15 :       this.flags = flags;
     358          15 :       this.noteDbSchemaUpdater = noteDbSchemaUpdater;
     359          15 :       this.repositoryManager = repositoryManager;
     360          15 :     }
     361             : 
     362             :     void upgradeSchema() {
     363          15 :       noteDbSchemaUpdater.update(new UpdateUIImpl(ui));
     364          15 :     }
     365             : 
     366             :     private static class UpdateUIImpl implements UpdateUI {
     367             :       private final ConsoleUI consoleUi;
     368             : 
     369          15 :       UpdateUIImpl(ConsoleUI consoleUi) {
     370          15 :         this.consoleUi = consoleUi;
     371          15 :       }
     372             : 
     373             :       @Override
     374             :       public void message(String message) {
     375           0 :         System.err.println(message);
     376           0 :         System.err.flush();
     377           0 :       }
     378             : 
     379             :       @Override
     380             :       public boolean yesno(boolean defaultValue, String message) {
     381           0 :         return consoleUi.yesno(defaultValue, message);
     382             :       }
     383             : 
     384             :       @Override
     385             :       public void waitForUser() {
     386           0 :         consoleUi.waitForUser();
     387           0 :       }
     388             : 
     389             :       @Override
     390             :       public String readString(String defaultValue, Set<String> allowedValues, String message) {
     391           0 :         return consoleUi.readString(defaultValue, allowedValues, message);
     392             :       }
     393             : 
     394             :       @Override
     395             :       public boolean isBatch() {
     396           0 :         return consoleUi.isBatch();
     397             :       }
     398             :     }
     399             :   }
     400             : 
     401             :   private SiteRun createSiteRun(SiteInit init) {
     402          15 :     return createSysInjector(init).getInstance(SiteRun.class);
     403             :   }
     404             : 
     405             :   private Injector createSysInjector(SiteInit init) {
     406          15 :     if (sysInjector == null) {
     407          15 :       final List<Module> modules = new ArrayList<>();
     408          15 :       modules.add(
     409          15 :           new AbstractModule() {
     410             :             @Override
     411             :             protected void configure() {
     412          15 :               bind(ConsoleUI.class).toInstance(init.ui);
     413          15 :               bind(InitFlags.class).toInstance(init.flags);
     414          15 :             }
     415             :           });
     416          15 :       Injector dbInjector = createDbInjector();
     417             : 
     418          15 :       IndexType indexType = IndexModule.getIndexType(dbInjector);
     419          15 :       if (indexType.isLucene()) {
     420           1 :         modules.add(new LuceneIndexModuleOnInit());
     421          15 :       } else if (indexType.isFake()) {
     422             :         try {
     423          15 :           Class<?> clazz = Class.forName("com.google.gerrit.index.testing.FakeIndexModuleOnInit");
     424          15 :           Module indexOnInitModule = (Module) clazz.getDeclaredConstructor().newInstance();
     425          15 :           modules.add(indexOnInitModule);
     426           0 :         } catch (InstantiationException
     427             :             | IllegalAccessException
     428             :             | ClassNotFoundException
     429             :             | NoSuchMethodException
     430             :             | InvocationTargetException e) {
     431           0 :           throw new IllegalStateException("unable to create fake index", e);
     432          15 :         }
     433          15 :         modules.add(new IndexModuleOnInit());
     434             :       } else {
     435           0 :         throw new IllegalStateException("unsupported index.type = " + indexType);
     436             :       }
     437          15 :       sysInjector = dbInjector.createChildInjector(modules);
     438             :     }
     439          15 :     return sysInjector;
     440             :   }
     441             : 
     442             :   private static void recursiveDelete(Path path) {
     443           0 :     final String msg = "warn: Cannot remove ";
     444             :     try {
     445           0 :       Files.walkFileTree(
     446             :           path,
     447           0 :           new SimpleFileVisitor<Path>() {
     448             :             @Override
     449             :             public FileVisitResult visitFile(Path f, BasicFileAttributes attrs) throws IOException {
     450             :               try {
     451           0 :                 Files.delete(f);
     452           0 :               } catch (IOException e) {
     453           0 :                 System.err.println(msg + f);
     454           0 :               }
     455           0 :               return FileVisitResult.CONTINUE;
     456             :             }
     457             : 
     458             :             @Override
     459             :             public FileVisitResult postVisitDirectory(Path dir, IOException err) {
     460             :               try {
     461             :                 // Previously warned if err was not null; if dir is not empty as a
     462             :                 // result, will cause an error that will be logged below.
     463           0 :                 Files.delete(dir);
     464           0 :               } catch (IOException e) {
     465           0 :                 System.err.println(msg + dir);
     466           0 :               }
     467           0 :               return FileVisitResult.CONTINUE;
     468             :             }
     469             : 
     470             :             @Override
     471             :             public FileVisitResult visitFileFailed(Path f, IOException e) {
     472           0 :               System.err.println(msg + f);
     473           0 :               return FileVisitResult.CONTINUE;
     474             :             }
     475             :           });
     476           0 :     } catch (IOException e) {
     477           0 :       System.err.println(msg + path);
     478           0 :     }
     479           0 :   }
     480             : 
     481             :   protected boolean isDev() {
     482           0 :     return false;
     483             :   }
     484             : 
     485             :   protected boolean getDeleteCaches() {
     486           0 :     return false;
     487             :   }
     488             : }

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