You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vk...@apache.org on 2020/12/23 18:31:09 UTC

[ignite-3] branch main updated: IGNITE-13782 Add reinit support for corrupted installation (#11)

This is an automated email from the ASF dual-hosted git repository.

vkulichenko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new fad5da0  IGNITE-13782 Add reinit support for corrupted installation (#11)
fad5da0 is described below

commit fad5da092fabca218843682195e7cf8cab7947d6
Author: Kirill Gusakov <kg...@gmail.com>
AuthorDate: Wed Dec 23 21:30:59 2020 +0300

    IGNITE-13782 Add reinit support for corrupted installation (#11)
---
 modules/cli-demo/cli/pom.xml                       |  6 ++
 .../apache/ignite/cli/CliPathsConfigLoader.java    | 25 +++---
 .../java/org/apache/ignite/cli/IgnitePaths.java    | 24 ++++++
 .../cli/builtins/init/InitIgniteCommand.java       | 65 +++++----------
 .../ignite/cli/builtins/module/ModuleStorage.java  |  7 +-
 .../cli/builtins/init/InitIgniteCommandTest.java   | 93 ++++++++++++++++++++++
 .../cli/src/test/resources/builtin_modules.conf    | 13 +++
 .../cli/src/test/resources/logback-test.xml        | 14 ++++
 .../cli/src/test/resources/version.properties      | 18 +++++
 9 files changed, 208 insertions(+), 57 deletions(-)

diff --git a/modules/cli-demo/cli/pom.xml b/modules/cli-demo/cli/pom.xml
index 59b458e..90b92ca 100644
--- a/modules/cli-demo/cli/pom.xml
+++ b/modules/cli-demo/cli/pom.xml
@@ -83,6 +83,12 @@
             <version>3.3.3</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>io.micronaut.test</groupId>
+            <artifactId>micronaut-test-junit5</artifactId>
+            <version>2.1.1</version>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>io.micronaut</groupId>
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/CliPathsConfigLoader.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/CliPathsConfigLoader.java
index 794086a..7db5bb5 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/CliPathsConfigLoader.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/CliPathsConfigLoader.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.cli;
 
-import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -42,28 +41,30 @@ public class CliPathsConfigLoader {
     }
 
     public Optional<IgnitePaths> loadIgnitePathsConfig() {
-        return searchConfigPathsFile()
-            .map(f -> CliPathsConfigLoader.readConfigFile(f, version));
+        if (configFilePath().toFile().exists())
+            return Optional.of(CliPathsConfigLoader.readConfigFile(configFilePath(), version));
+
+        return Optional.empty();
     }
 
     public IgnitePaths loadIgnitePathsOrThrowError() {
         Optional<IgnitePaths> ignitePaths = loadIgnitePathsConfig();
-        if (ignitePaths.isPresent())
+        if (ignitePaths.isPresent()) {
+            if (!ignitePaths.get().validateDirs())
+                throw new IgniteCLIException("Some required directories are absent. " +
+                    "Try to run 'init' command to fix the issue.");
             return ignitePaths.get();
+        }
         else
             throw new IgniteCLIException("To execute node module/node management commands you must run 'init' first");
     }
 
-    public Optional<File> searchConfigPathsFile() {
-        File homeDirCfg = pathResolver.osHomeDirectoryPath().resolve(".ignitecfg").toFile();
-        if (homeDirCfg.exists())
-            return Optional.of(homeDirCfg);
-
-        return Optional.empty();
+    public Path configFilePath() {
+        return pathResolver.osHomeDirectoryPath().resolve(".ignitecfg");
     }
 
-    private static IgnitePaths readConfigFile(File configFile, String version) {
-        try (InputStream inputStream = new FileInputStream(configFile)) {
+    private static IgnitePaths readConfigFile(Path configPath, String version) {
+        try (InputStream inputStream = new FileInputStream(configPath.toFile())) {
             Properties properties = new Properties();
             properties.load(inputStream);
             if ((properties.getProperty("bin") == null) || (properties.getProperty("work") == null))
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/IgnitePaths.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/IgnitePaths.java
index 4a5ac67..3a1c440 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/IgnitePaths.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/IgnitePaths.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.cli;
 
+import java.io.File;
 import java.nio.file.Path;
 
 public class IgnitePaths {
@@ -56,5 +57,28 @@ public class IgnitePaths {
         return serverConfigDir().resolve("default-config.xml");
     }
 
+    public void initOrRecover() {
+        File igniteWork = workDir.toFile();
+        if (!(igniteWork.exists() || igniteWork.mkdirs()))
+            throw new IgniteCLIException("Can't create working directory: " + workDir);
 
+        File igniteBin = libsDir().toFile();
+        if (!(igniteBin.exists() || igniteBin.mkdirs()))
+            throw new IgniteCLIException("Can't create a directory for ignite modules: " + libsDir());
+
+        File igniteBinCli = cliLibsDir().toFile();
+        if (!(igniteBinCli.exists() || igniteBinCli.mkdirs()))
+            throw new IgniteCLIException("Can't create a directory for cli modules: " + cliLibsDir());
+
+        File serverConfig = serverConfigDir().toFile();
+        if (!(serverConfig.exists() || serverConfig.mkdirs()))
+            throw new IgniteCLIException("Can't create a directory for server configs: " + serverConfigDir());
+    }
+
+    public boolean validateDirs() {
+        return workDir.toFile().exists() &&
+                libsDir().toFile().exists() &&
+                cliLibsDir().toFile().exists() &&
+                serverConfigDir().toFile().exists();
+    }
 }
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/init/InitIgniteCommand.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/init/InitIgniteCommand.java
index c3eef48..71d5a7e 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/init/InitIgniteCommand.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/init/InitIgniteCommand.java
@@ -55,59 +55,36 @@ public class InitIgniteCommand {
         moduleManager.setOut(out);
         Optional<IgnitePaths> ignitePathsOpt = cliPathsConfigLoader.loadIgnitePathsConfig();
         if (ignitePathsOpt.isEmpty()) {
-            out.println("Init ignite directories...");
-            IgnitePaths ignitePaths = initDirectories(out);
-            out.println("Download and install current ignite version...");
-            installIgnite(ignitePaths);
-            out.println("Init default Ignite configs");
-            initDefaultServerConfigs();
-            out.println();
-            out.println("Apache Ignite version " + cliVersionInfo.version + " sucessfully installed");
-        } else {
-            IgnitePaths cfg = ignitePathsOpt.get();
-            out.println("Apache Ignite was initialized earlier\n" +
-                "Configuration file: " + cliPathsConfigLoader.searchConfigPathsFile().get() + "\n" +
-                "Ignite binaries dir: " + cfg.binDir + "\n" +
-                "Ignite work dir: " + cfg.workDir);
+            File cfgFile = initConfigFile();
+            out.println("Configuration file initialized: " + cfgFile);
         }
+        IgnitePaths cfg = cliPathsConfigLoader.loadIgnitePathsConfig().get();
+        out.println("Init ignite directories...");
+        cfg.initOrRecover();
+        out.println("Download and install current ignite version...");
+        installIgnite(cfg);
+        out.println("Init default Ignite configs");
+        initDefaultServerConfigs(cfg.serverDefaultConfigFile());
+        out.println();
+        out.println("Apache Ignite version " + cliVersionInfo.version + " successfully installed");
+        out.println(
+            "Configuration file: " + cliPathsConfigLoader.configFilePath() + "\n" +
+            "Ignite binaries dir: " + cfg.binDir + "\n" +
+            "Ignite work dir: " + cfg.workDir);
     }
 
-    private void initDefaultServerConfigs() {
-        Path serverCfgFile = cliPathsConfigLoader.loadIgnitePathsOrThrowError().serverDefaultConfigFile();
+    private void initDefaultServerConfigs(Path serverCfgFile) {
         try {
-            Files.copy(InitIgniteCommand.class.getResourceAsStream("/default-config.xml"), serverCfgFile);
+            if (!serverCfgFile.toFile().exists())
+                Files.copy(
+                    InitIgniteCommand.class
+                        .getResourceAsStream("/default-config.xml"), serverCfgFile);
         }
         catch (IOException e) {
-            throw new IgniteCLIException("Can't create default config file for server");
+            throw new IgniteCLIException("Can't create default config file for server", e);
         }
     }
 
-    private IgnitePaths initDirectories(PrintWriter out) {
-        File cfgFile = initConfigFile();
-        out.println("Configuration file initialized: " + cfgFile);
-        IgnitePaths cfg = cliPathsConfigLoader.loadIgnitePathsOrThrowError();
-        out.println("Ignite binaries dir: " + cfg.binDir);
-        out.println("Ignite work dir: " + cfg.workDir);
-
-        File igniteWork = cfg.workDir.toFile();
-        if (!(igniteWork.exists() || igniteWork.mkdirs()))
-            throw new IgniteCLIException("Can't create working directory: " + cfg.workDir);
-
-        File igniteBin = cfg.libsDir().toFile();
-        if (!(igniteBin.exists() || igniteBin.mkdirs()))
-            throw new IgniteCLIException("Can't create a directory for ignite modules: " + cfg.libsDir());
-
-        File igniteBinCli = cfg.cliLibsDir().toFile();
-        if (!(igniteBinCli.exists() || igniteBinCli.mkdirs()))
-            throw new IgniteCLIException("Can't create a directory for cli modules: " + cfg.cliLibsDir());
-
-        File serverConfig = cfg.serverConfigDir().toFile();
-        if (!(serverConfig.exists() || serverConfig.mkdirs()))
-            throw new IgniteCLIException("Can't create a directory for server configs: " + cfg.serverConfigDir());
-
-        return cfg;
-    }
-
     private void installIgnite(IgnitePaths ignitePaths) {
         moduleManager.addModule("_server", ignitePaths, Collections.emptyList());
     }
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleStorage.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleStorage.java
index 1219327..920b84a 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleStorage.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleStorage.java
@@ -29,6 +29,7 @@ import com.fasterxml.jackson.annotation.JsonGetter;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.ignite.cli.CliPathsConfigLoader;
+import org.apache.ignite.cli.IgnitePaths;
 
 @Singleton
 public class ModuleStorage {
@@ -62,7 +63,11 @@ public class ModuleStorage {
     }
 
     public ModuleDefinitionsRegistry listInstalled() throws IOException {
-        if (!moduleFile().toFile().exists())
+        var moduleFileAvailable =
+            cliPathsConfigLoader.loadIgnitePathsConfig()
+                .map(p -> p.installedModulesFile().toFile().exists())
+                .orElse(false);
+        if (!moduleFileAvailable)
             return new ModuleDefinitionsRegistry(new ArrayList<>());
         else {
             ObjectMapper objectMapper = new ObjectMapper();
diff --git a/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java b/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java
new file mode 100644
index 0000000..c9e708e
--- /dev/null
+++ b/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java
@@ -0,0 +1,93 @@
+package org.apache.ignite.cli.builtins.init;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import javax.inject.Inject;
+import io.micronaut.test.annotation.MockBean;
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import org.apache.ignite.cli.CliPathsConfigLoader;
+import org.apache.ignite.cli.builtins.SystemPathResolver;
+import org.apache.ignite.cli.builtins.module.MavenArtifactResolver;
+import org.apache.ignite.cli.builtins.module.ResolveResult;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+@MicronautTest
+public class InitIgniteCommandTest {
+
+    @Inject SystemPathResolver pathResolver;
+    @Inject MavenArtifactResolver mavenArtifactResolver;
+    @Inject InitIgniteCommand initIgniteCommand;
+    @Inject CliPathsConfigLoader cliPathsConfigLoader;
+
+    @TempDir Path homeDir;
+    @TempDir Path currentDir;
+
+    @Test
+    void init() throws IOException {
+        when(pathResolver.osHomeDirectoryPath()).thenReturn(homeDir);
+        when(pathResolver.osCurrentDirPath()).thenReturn(currentDir);
+
+        when(mavenArtifactResolver.resolve(any(), any(), any(), any(), any()))
+            .thenReturn(new ResolveResult(Arrays.asList()));
+
+        var out = new ByteArrayOutputStream();
+        initIgniteCommand.init(new PrintWriter(System.out, true));
+
+        var ignitePaths = cliPathsConfigLoader.loadIgnitePathsConfig().get();
+        assertTrue(ignitePaths.validateDirs());
+    }
+
+    @Test
+    void reinit() throws IOException {
+        when(pathResolver.osHomeDirectoryPath()).thenReturn(homeDir);
+        when(pathResolver.osCurrentDirPath()).thenReturn(currentDir);
+
+        when(mavenArtifactResolver.resolve(any(), any(), any(), any(), any()))
+            .thenReturn(new ResolveResult(Collections.emptyList()));
+
+        var out = new PrintWriter(System.out, true);
+        initIgniteCommand.init(out);
+
+        var ignitePaths = cliPathsConfigLoader.loadIgnitePathsOrThrowError();
+        recursiveDirRemove(ignitePaths.binDir);
+
+        assertFalse(ignitePaths::validateDirs);
+
+        initIgniteCommand.init(out);
+        assertTrue(ignitePaths::validateDirs);
+    }
+
+    @MockBean(MavenArtifactResolver.class) MavenArtifactResolver mavenArtifactResolver() {
+        return mock(MavenArtifactResolver.class);
+    }
+
+    @MockBean(SystemPathResolver.class) SystemPathResolver systemPathResolver() {
+        return mock(SystemPathResolver.class);
+    }
+
+    private void recursiveDirRemove(Path dir) throws IOException {
+        Files.walk(dir)
+            .sorted(Comparator.reverseOrder())
+            .map(Path::toFile)
+            .forEach(File::delete);
+        dir.toFile().delete();
+
+    }
+}
diff --git a/modules/cli-demo/cli/src/test/resources/builtin_modules.conf b/modules/cli-demo/cli/src/test/resources/builtin_modules.conf
new file mode 100644
index 0000000..0cde1d2
--- /dev/null
+++ b/modules/cli-demo/cli/src/test/resources/builtin_modules.conf
@@ -0,0 +1,13 @@
+modules : {
+    _server: {
+        description: "Collection of base modules, which needed for start ignite server",
+        artifacts: ["mvn:org.apache.ignite:ignite-configuration-simplistic-ignite"],
+        cli-artifacts: []
+    },
+
+    ignite-demo-cli {
+        description: "Demo Ignite module with additional cli command 'snapshot'",
+        artifacts: ["mvn:org.apache.ignite:ignite-demo-module"],
+        cli-artifacts: ["mvn:org.apache.ignite:ignite-demo-module-cli"]
+    }
+}
\ No newline at end of file
diff --git a/modules/cli-demo/cli/src/test/resources/logback-test.xml b/modules/cli-demo/cli/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..6a1caa1
--- /dev/null
+++ b/modules/cli-demo/cli/src/test/resources/logback-test.xml
@@ -0,0 +1,14 @@
+<configuration>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <!-- encoders are assigned the type
+             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <root level="error">
+        <appender-ref ref="STDOUT" />
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/modules/cli-demo/cli/src/test/resources/version.properties b/modules/cli-demo/cli/src/test/resources/version.properties
new file mode 100644
index 0000000..0d488d3
--- /dev/null
+++ b/modules/cli-demo/cli/src/test/resources/version.properties
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+version=${project.version}