You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sk...@apache.org on 2021/08/11 12:45:31 UTC

[ignite-3] branch main updated: IGNITE-14956 Implemented and checked scenarios for startup configuration. Fixes #256

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

sk0x50 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 4bd3d27  IGNITE-14956 Implemented and checked scenarios for startup configuration. Fixes #256
4bd3d27 is described below

commit 4bd3d27b45eb3dbdd30101fa661f009f831ff670
Author: Vladislav Pyatkov <vl...@gmail.com>
AuthorDate: Wed Aug 11 15:44:43 2021 +0300

    IGNITE-14956 Implemented and checked scenarios for startup configuration. Fixes #256
    
    Signed-off-by: Slava Koptilin <sl...@gmail.com>
---
 .../main/java/org/apache/ignite/app/Ignition.java  |  19 +-
 .../org/apache/ignite/app/IgnitionManager.java     |  21 ++-
 .../calcite/exec/rel/AbstractExecutionTest.java    |   5 +-
 .../apache/ignite/internal/util/IgniteUtils.java   |  43 +++++
 .../internal/testframework/IgniteAbstractTest.java |  47 +++++
 .../runner/app/ITIgniteNodeRestartTest.java        | 201 +++++++++++++++++++++
 .../org/apache/ignite/internal/app/IgniteImpl.java |  30 ++-
 .../apache/ignite/internal/app/IgnitionImpl.java   |  39 ++--
 .../ignite/internal/table/TableManagerTest.java    |   2 +-
 .../apache/ignite/internal/vault/VaultManager.java |  10 -
 10 files changed, 379 insertions(+), 38 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/app/Ignition.java b/modules/api/src/main/java/org/apache/ignite/app/Ignition.java
index e0e6a41..0fe1ec6 100644
--- a/modules/api/src/main/java/org/apache/ignite/app/Ignition.java
+++ b/modules/api/src/main/java/org/apache/ignite/app/Ignition.java
@@ -40,8 +40,23 @@ public interface Ignition {
     /**
      * Starts an Ignite node with an optional bootstrap configuration from an input stream with HOCON configs.
      *
-     * @param name Name of the node. Must not be {@code null}.
-     * @param config Input stream from the node configuration in HOCON format. Can be {@code null}.
+     * @param name    Name of the node. Must not be {@code null}.
+     * @param config  Optional node configuration based on
+     *                {@link org.apache.ignite.configuration.schemas.runner.NodeConfigurationSchema} and
+     *                {@link org.apache.ignite.configuration.schemas.network.NetworkConfigurationSchema}.
+     *                Following rules are used for applying the configuration properties:
+     *                <ol>
+     *                  <li>Specified property overrides existing one or just applies itself if it wasn't
+     *                      previously specified.</li>
+     *                  <li>All non-specified properties either use previous value or use default one from
+     *                      corresponding configuration schema.</li>
+     *                </ol>
+     *                So that, in case of initial node start (first start ever) specified configuration, supplemented
+     *                with defaults, is used. If no configuration was provided defaults are used for all
+     *                configuration properties. In case of node restart, specified properties override existing
+     *                ones, non specified properties that also weren't specified previously use default values.
+     *                Please pay attention that previously specified properties are searched in the
+     *                {@code workDir} specified by the user.
      * @param workDir Work directory for the started node. Must not be {@code null}.
      * @return Started Ignite node.
      */
diff --git a/modules/api/src/main/java/org/apache/ignite/app/IgnitionManager.java b/modules/api/src/main/java/org/apache/ignite/app/IgnitionManager.java
index 1b4c066..b35fe74 100644
--- a/modules/api/src/main/java/org/apache/ignite/app/IgnitionManager.java
+++ b/modules/api/src/main/java/org/apache/ignite/app/IgnitionManager.java
@@ -38,9 +38,24 @@ public class IgnitionManager {
     /**
      * Starts an Ignite node with an optional bootstrap configuration from a HOCON file.
      *
-     * @param nodeName Name of the node. Must not be {@code null}.
-     * @param configStr Node configuration in the HOCON format. Can be {@code null}.
-     * @param workDir Work directory for the started node. Must not be {@code null}.
+     * @param nodeName  Name of the node. Must not be {@code null}.
+     * @param configStr Optional node configuration based on
+     *                  {@link org.apache.ignite.configuration.schemas.runner.NodeConfigurationSchema} and
+     *                  {@link org.apache.ignite.configuration.schemas.network.NetworkConfigurationSchema}.
+     *                  Following rules are used for applying the configuration properties:
+     *                  <ol>
+     *                      <li>Specified property overrides existing one or just applies itself if it wasn't
+     *                          previously specified.</li>
+     *                      <li>All non-specified properties either use previous value or use default one from
+     *                          corresponding configuration schema.</li>
+     *                  </ol>
+     *                  So that, in case of initial node start (first start ever) specified configuration, supplemented
+     *                  with defaults, is used. If no configuration was provided defaults are used for all
+     *                  configuration properties. In case of node restart, specified properties override existing
+     *                  ones, non specified properties that also weren't specified previously use default values.
+     *                  Please pay attention that previously specified properties are searched in the
+     *                  {@code workDir} specified by the user.
+     * @param workDir   Work directory for the started node. Must not be {@code null}.
      * @return Started Ignite node.
      * @throws IgniteException If error occurs while reading node configuration.
      */
diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/AbstractExecutionTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/AbstractExecutionTest.java
index 0b0f46f..00c7848 100644
--- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/AbstractExecutionTest.java
+++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/rel/AbstractExecutionTest.java
@@ -21,7 +21,6 @@ import java.util.Iterator;
 import java.util.UUID;
 import java.util.function.Function;
 import java.util.stream.Collectors;
-
 import com.google.common.collect.ImmutableMap;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
@@ -50,7 +49,7 @@ public class AbstractExecutionTest extends IgniteAbstractTest {
 
     /** */
     @BeforeEach
-    public void setup() {
+    public void beforeTest() {
         taskExecutor = new QueryTaskExecutorImpl(
             new StripedThreadPoolExecutor(
                 4,
@@ -64,7 +63,7 @@ public class AbstractExecutionTest extends IgniteAbstractTest {
 
     /** */
     @AfterEach
-    public void tearDown() {
+    public void afterTest() {
         taskExecutor.tearDown();
 
         if (lastE != null)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index f5ea3c3..50ca746 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -24,6 +24,8 @@ import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
@@ -34,6 +36,7 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
+import org.apache.ignite.lang.IgniteLogger;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -43,6 +46,9 @@ public class IgniteUtils {
     /** Byte bit-mask. */
     private static final int MASK = 0xf;
 
+    /** The moment will be used as a start monotonic time. */
+    private static final long BEGINNING_OF_TIME = System.nanoTime();
+
     /** Version of the JDK. */
     private static final String jdkVer = System.getProperty("java.specification.version");
 
@@ -51,6 +57,14 @@ public class IgniteUtils {
 
     private static final boolean assertionsEnabled;
 
+    /**
+     * Gets the current monotonic time in milliseconds.
+     * This is the amount of milliseconds which passed from an arbitrary moment in the past.
+     */
+    public static long monotonicMs() {
+        return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - BEGINNING_OF_TIME);
+    }
+
     /** Primitive class map. */
     private static final Map<String, Class<?>> primitiveMap = Map.of(
         "byte", byte.class,
@@ -487,4 +501,33 @@ public class IgniteUtils {
     public static void closeAll(AutoCloseable... closeables) throws Exception {
         closeAll(Arrays.asList(closeables));
     }
+
+    /**
+     * Short date format pattern for log messages in "quiet" mode.
+     * Only time is included since we don't expect "quiet" mode to be used
+     * for longer runs.
+     */
+    private static final DateTimeFormatter SHORT_DATE_FMT = DateTimeFormatter.ofPattern("HH:mm:ss");
+
+    /**
+     * Prints stack trace of the current thread to provided logger.
+     *
+     * @param log Logger.
+     * @param msg Message to print with the stack.
+     *
+     * @deprecated Calls to this method should never be committed to master.
+     */
+    public static void dumpStack(IgniteLogger log, String msg) {
+        String reason = "Dumping stack.";
+
+        var err = new Exception(msg);
+
+        if (log != null)
+            log.error(reason, err);
+        else {
+            System.err.println("[" + LocalDateTime.now().format(SHORT_DATE_FMT) + "] (err) " + reason);
+
+            err.printStackTrace(System.err);
+        }
+    }
 }
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/testframework/IgniteAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/testframework/IgniteAbstractTest.java
index 50c10de..9b3ef58 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/testframework/IgniteAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/testframework/IgniteAbstractTest.java
@@ -17,20 +17,34 @@
 
 package org.apache.ignite.internal.testframework;
 
+import java.lang.reflect.Method;
+import java.nio.file.Path;
 import org.apache.ignite.internal.tostring.S;
 import org.apache.ignite.internal.tostring.SensitiveDataLoggingPolicy;
 import org.apache.ignite.lang.IgniteLogger;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.extension.ExtendWith;
 
+import static org.apache.ignite.internal.util.IgniteUtils.monotonicMs;
 import static org.apache.ignite.lang.IgniteSystemProperties.IGNITE_SENSITIVE_DATA_LOGGING;
 import static org.apache.ignite.lang.IgniteSystemProperties.getString;
 
 /**
  * Ignite base test class.
  */
+@ExtendWith({SystemPropertiesExtension.class, WorkDirectoryExtension.class})
 public abstract class IgniteAbstractTest {
     /** Logger. */
     protected static IgniteLogger log;
 
+    /** Tets start milliseconds. */
+    private long testStartMs;
+
+    /** Work directory. */
+    protected Path workDir;
+
     /** Init test env. */
     static {
         S.setSensitiveDataLoggingPolicySupplier(() ->
@@ -38,6 +52,39 @@ public abstract class IgniteAbstractTest {
     }
 
     /**
+     * Invokes before the test will start.
+     *
+     * @param testInfo Test information oject.
+     * @param workDir Work directory.
+     * @throws Exception If failed.
+     */
+    @BeforeEach
+    public void setup(TestInfo testInfo, @WorkDirectory Path workDir) throws Exception {
+        log.info(">>> Starting test: {}#{}, displayName: {}, workDir: {}",
+            testInfo.getTestClass().map(Class::getSimpleName).orElseGet(() -> "<null>"),
+            testInfo.getTestMethod().map(Method::getName).orElseGet(() -> "<null>"),
+            testInfo.getDisplayName(),
+            workDir.toAbsolutePath());
+
+        this.workDir = workDir;
+        this.testStartMs = monotonicMs();
+    }
+
+    /**
+     * Invokes after the test has finished.
+     *
+     * @param testInfo Test information oject.
+     * @throws Exception If failed.
+     */
+    @AfterEach
+    public void tearDown(TestInfo testInfo) throws Exception {
+        log.info(">>> Stopping test: {}#{}, displayName: {}, cost: {}ms.",
+            testInfo.getTestClass().map(Class::getSimpleName).orElseGet(() -> "<null>"),
+            testInfo.getTestMethod().map(Method::getName).orElseGet(() -> "<null>"),
+            testInfo.getDisplayName(), monotonicMs() - testStartMs);
+    }
+
+    /**
      * Constructor.
      */
     @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ITIgniteNodeRestartTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ITIgniteNodeRestartTest.java
new file mode 100644
index 0000000..c7ee37c
--- /dev/null
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ITIgniteNodeRestartTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.runner.app;
+
+import org.apache.ignite.app.Ignite;
+import org.apache.ignite.app.IgnitionManager;
+import org.apache.ignite.configuration.schemas.network.NetworkConfiguration;
+import org.apache.ignite.internal.app.IgniteImpl;
+import org.apache.ignite.internal.schema.configuration.SchemaConfigurationConverter;
+import org.apache.ignite.internal.testframework.IgniteAbstractTest;
+import org.apache.ignite.schema.ColumnType;
+import org.apache.ignite.schema.SchemaBuilders;
+import org.apache.ignite.schema.SchemaTable;
+import org.apache.ignite.table.Table;
+import org.apache.ignite.table.Tuple;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * These tests check node restart scenarios.
+ */
+public class ITIgniteNodeRestartTest extends IgniteAbstractTest {
+    /** Test node name. */
+    public static final String NODE_NAME = "TestNode";
+
+    /** Test table name. */
+    public static final String TABLE_NAME = "Table1";
+
+    /**
+     * Restarts empty node.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void emptyNodeTest() throws Exception {
+        IgniteImpl ignite = (IgniteImpl)IgnitionManager.start(NODE_NAME, null, workDir.resolve(NODE_NAME));
+
+        int nodePort = ignite.nodeConfiguration().getConfiguration(NetworkConfiguration.KEY).port().value();
+
+        assertEquals(47500, nodePort);
+
+        IgnitionManager.stop(ignite.name());
+
+        ignite = (IgniteImpl)IgnitionManager.start(NODE_NAME, null, workDir.resolve(NODE_NAME));
+
+        nodePort = ignite.nodeConfiguration().getConfiguration(NetworkConfiguration.KEY).port().value();
+
+        assertEquals(47500, nodePort);
+
+        IgnitionManager.stop(ignite.name());
+    }
+
+    /**
+     * Restarts a node with changing configuration.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void changeConfigurationOnStartTest() throws Exception {
+        IgniteImpl ignite = (IgniteImpl)IgnitionManager.start(NODE_NAME, null, workDir.resolve(NODE_NAME));
+
+        int nodePort = ignite.nodeConfiguration().getConfiguration(NetworkConfiguration.KEY).port().value();
+
+        assertEquals(47500, nodePort);
+
+        IgnitionManager.stop(ignite.name());
+
+        int newPort = 3322;
+
+        String updateCfg = "network.port=" + newPort;
+
+        ignite = (IgniteImpl)IgnitionManager.start(NODE_NAME, updateCfg, workDir.resolve(NODE_NAME));
+
+        nodePort = ignite.nodeConfiguration().getConfiguration(NetworkConfiguration.KEY).port().value();
+
+        assertEquals(newPort, nodePort);
+
+        IgnitionManager.stop(ignite.name());
+    }
+
+    /**
+     * Checks that the only one non-default property overwrites after another configuration is passed on the node
+     * restart.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void twoCustomPropertiesTest() throws Exception {
+        String startCfg = "network: {\n" +
+            "  port:3344,\n" +
+            "  netClusterNodes:[ \"localhost:3344\" ]\n" +
+            "}";
+
+        IgniteImpl ignite = (IgniteImpl)IgnitionManager.start(NODE_NAME, startCfg, workDir.resolve(NODE_NAME));
+
+        assertEquals(
+            3344,
+            ignite.nodeConfiguration().getConfiguration(NetworkConfiguration.KEY).port().value()
+        );
+
+        assertArrayEquals(
+            new String[] {"localhost:3344"},
+            ignite.nodeConfiguration().getConfiguration(NetworkConfiguration.KEY).netClusterNodes().value()
+        );
+
+        IgnitionManager.stop(ignite.name());
+
+        ignite = (IgniteImpl)IgnitionManager.start(
+            NODE_NAME,
+            "network.netClusterNodes=[ \"localhost:3344\", \"localhost:3343\" ]",
+            workDir.resolve(NODE_NAME)
+        );
+
+        assertEquals(
+            3344,
+            ignite.nodeConfiguration().getConfiguration(NetworkConfiguration.KEY).port().value()
+        );
+
+        assertArrayEquals(
+            new String[] {"localhost:3344", "localhost:3343"},
+            ignite.nodeConfiguration().getConfiguration(NetworkConfiguration.KEY).netClusterNodes().value()
+        );
+
+        IgnitionManager.stop(ignite.name());
+    }
+
+    /**
+     * Restarts the node which stores some data.
+     */
+    @Test
+    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15255")
+    public void nodeWithDataTest() {
+        Ignite ignite = IgnitionManager.start(NODE_NAME, "{\n" +
+            "  \"node\": {\n" +
+            "    \"metastorageNodes\":[ " + NODE_NAME + " ]\n" +
+            "  },\n" +
+            "  \"network\": {\n" +
+            "    \"port\":3344,\n" +
+            "    \"netClusterNodes\":[ \"localhost:3344\" ]\n" +
+            "  }\n" +
+            "}", workDir.resolve(NODE_NAME));
+
+        SchemaTable scmTbl1 = SchemaBuilders.tableBuilder("PUBLIC", TABLE_NAME).columns(
+            SchemaBuilders.column("id", ColumnType.INT32).asNonNull().build(),
+            SchemaBuilders.column("name", ColumnType.string()).asNullable().build()
+        ).withIndex(
+            SchemaBuilders.pkIndex()
+                .addIndexColumn("id").done()
+                .build()
+        ).build();
+
+        Table table = ignite.tables().getOrCreateTable(
+            scmTbl1.canonicalName(), tbl -> SchemaConfigurationConverter.convert(scmTbl1, tbl).changePartitions(10));
+
+        for (int i = 0; i < 100; i++) {
+            Tuple key = table.tupleBuilder()
+                .set("id", i)
+                .build();
+
+            Tuple vaul = table.tupleBuilder()
+                .set("name", "name " + i)
+                .build();
+
+            table.kvView().put(key, vaul);
+        }
+
+        IgnitionManager.stop(NODE_NAME);
+
+        ignite = IgnitionManager.start(NODE_NAME, null, workDir.resolve(NODE_NAME));
+
+        assertNotNull(ignite.tables().table(TABLE_NAME));
+
+        for (int i = 0; i < 100; i++) {
+            assertEquals("name " + i, table.kvView().get(table.tupleBuilder()
+                .set("id", i)
+                .build())
+                .stringValue("name"));
+        }
+
+        IgnitionManager.stop(NODE_NAME);
+    }
+}
diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index c73a0b7..26e31da 100644
--- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -19,6 +19,8 @@ package org.apache.ignite.internal.app;
 
 import org.apache.ignite.app.Ignite;
 import org.apache.ignite.app.IgnitionManager;
+import org.apache.ignite.internal.configuration.ConfigurationManager;
+import org.apache.ignite.internal.configuration.ConfigurationRegistry;
 import org.apache.ignite.internal.processors.query.calcite.SqlQueryProcessor;
 import org.apache.ignite.table.manager.IgniteTables;
 import org.apache.ignite.tx.IgniteTransactions;
@@ -35,19 +37,31 @@ public class IgniteImpl implements Ignite {
 
     private final SqlQueryProcessor qryEngine;
 
+    /** Configuration manager that handles node (local) configuration. */
+    private final ConfigurationManager nodeConfigurationMgr;
+
+    /** Configuration manager that handles cluster (distributed) configuration. */
+    private final ConfigurationManager clusterConfigurationMgr;
+
     /**
      * @param name Ignite node name.
      * @param tblMgr Table manager.
      * @param qryEngine Query processor.
+     * @param nodeConfigurationMgr Configuration manager that handles node (local) configuration.
+     * @param clusterConfigurationMgr Configuration manager that handles cluster (distributed) configuration.
      */
     IgniteImpl(
         String name,
         IgniteTables tblMgr,
-        SqlQueryProcessor qryEngine
+        SqlQueryProcessor qryEngine,
+        ConfigurationManager nodeConfigurationMgr,
+        ConfigurationManager clusterConfigurationMgr
     ) {
         this.name = name;
         this.distributedTblMgr = tblMgr;
         this.qryEngine = qryEngine;
+        this.nodeConfigurationMgr = nodeConfigurationMgr;
+        this.clusterConfigurationMgr = clusterConfigurationMgr;
     }
 
     /** {@inheritDoc} */
@@ -73,4 +87,18 @@ public class IgniteImpl implements Ignite {
     @Override public String name() {
         return name;
     }
+
+    /**
+     * @return Node configuration.
+     */
+    public ConfigurationRegistry nodeConfiguration() {
+        return nodeConfigurationMgr.configurationRegistry();
+    }
+
+    /**
+     * @return Cluster configuration.
+     */
+    public ConfigurationRegistry clusterConfiguration() {
+        return clusterConfigurationMgr.configurationRegistry();
+    }
 }
diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgnitionImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgnitionImpl.java
index fc559c8..d1fc7ee 100644
--- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgnitionImpl.java
+++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgnitionImpl.java
@@ -206,8 +206,6 @@ public class IgnitionImpl implements Ignition {
 
             vaultMgr.putName(nodeName).join();
 
-            boolean cfgBootstrappedFromPds = vaultMgr.bootstrapped();
-
             List<RootKey<?, ?>> rootKeys = Arrays.asList(
                 NetworkConfiguration.KEY,
                 NodeConfiguration.KEY,
@@ -218,27 +216,26 @@ public class IgnitionImpl implements Ignition {
             List<ConfigurationStorage> cfgStorages =
                 new ArrayList<>(Collections.singletonList(new LocalConfigurationStorage(vaultMgr)));
 
-            // Bootstrap local configuration manager.
-            ConfigurationManager locConfigurationMgr = doStartComponent(
+            // Bootstrap node configuration manager.
+            ConfigurationManager nodeConfigurationMgr = doStartComponent(
                 nodeName,
                 startedComponents,
                 new ConfigurationManager(rootKeys, cfgStorages)
             );
 
-            if (!cfgBootstrappedFromPds && cfgContent != null)
+            if (cfgContent != null) {
                 try {
-                    locConfigurationMgr.bootstrap(cfgContent, ConfigurationType.LOCAL);
+                    nodeConfigurationMgr.bootstrap(cfgContent, ConfigurationType.LOCAL);
                 }
                 catch (Exception e) {
                     LOG.warn("Unable to parse user-specific configuration, default configuration will be used: {}", e.getMessage());
                 }
-            else if (cfgContent != null)
-                LOG.warn("User specific configuration will be ignored, cause vault was bootstrapped with pds configuration");
+            }
             else
-                locConfigurationMgr.configurationRegistry().startStorageConfigurations(ConfigurationType.LOCAL);
+                nodeConfigurationMgr.configurationRegistry().startStorageConfigurations(ConfigurationType.LOCAL);
 
             NetworkView netConfigurationView =
-                locConfigurationMgr.configurationRegistry().getConfiguration(NetworkConfiguration.KEY).value();
+                nodeConfigurationMgr.configurationRegistry().getConfiguration(NetworkConfiguration.KEY).value();
 
             var serializationRegistry = new MessageSerializationRegistryImpl();
 
@@ -271,7 +268,7 @@ public class IgnitionImpl implements Ignition {
                 startedComponents,
                 new MetaStorageManager(
                     vaultMgr,
-                    locConfigurationMgr,
+                    nodeConfigurationMgr,
                     clusterNetSvc,
                     raftMgr
                 )
@@ -280,8 +277,8 @@ public class IgnitionImpl implements Ignition {
             // TODO IGNITE-14578 Bootstrap configuration manager with distributed configuration.
             cfgStorages.add(new DistributedConfigurationStorage(metaStorageMgr, vaultMgr));
 
-            // Start configuration manager.
-            ConfigurationManager configurationMgr = doStartComponent(
+            // Start cluster configuration manager.
+            ConfigurationManager clusterConfigurationMgr = doStartComponent(
                 nodeName,
                 startedComponents,
                 new ConfigurationManager(rootKeys, cfgStorages)
@@ -292,7 +289,7 @@ public class IgnitionImpl implements Ignition {
                 nodeName,
                 startedComponents,
                 new BaselineManager(
-                    configurationMgr,
+                    clusterConfigurationMgr,
                     metaStorageMgr,
                     clusterNetSvc
                 )
@@ -303,7 +300,7 @@ public class IgnitionImpl implements Ignition {
                 nodeName,
                 startedComponents,
                 new AffinityManager(
-                    configurationMgr,
+                    clusterConfigurationMgr,
                     metaStorageMgr,
                     baselineMgr
                 )
@@ -314,7 +311,7 @@ public class IgnitionImpl implements Ignition {
                 nodeName,
                 startedComponents,
                 new SchemaManager(
-                    configurationMgr,
+                    clusterConfigurationMgr,
                     metaStorageMgr,
                     vaultMgr
                 )
@@ -325,7 +322,7 @@ public class IgnitionImpl implements Ignition {
                 nodeName,
                 startedComponents,
                 new TableManager(
-                    configurationMgr,
+                    clusterConfigurationMgr,
                     metaStorageMgr,
                     schemaMgr,
                     affinityMgr,
@@ -368,7 +365,13 @@ public class IgnitionImpl implements Ignition {
 
             ackSuccessStart();
 
-            return new IgniteImpl(nodeName, distributedTblMgr, qryProc);
+            return new IgniteImpl(
+                nodeName,
+                distributedTblMgr,
+                qryProc,
+                nodeConfigurationMgr,
+                clusterConfigurationMgr
+            );
         }
         catch (Exception e) {
             String errMsg = "Unable to start node=[" + nodeName + "].";
diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/TableManagerTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/TableManagerTest.java
index 0676f11..6d9165a 100644
--- a/modules/table/src/test/java/org/apache/ignite/internal/table/TableManagerTest.java
+++ b/modules/table/src/test/java/org/apache/ignite/internal/table/TableManagerTest.java
@@ -223,7 +223,7 @@ public class TableManagerTest {
     /**
      * Tests a table which was defined before start through bootstrap configuration.
      */
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-14578")
+    @Disabled("https://issues.apache.org/jira/browse/IGNITE-15255")
     @Test
     public void testStaticTableConfigured() {
         TableManager tableManager = new TableManager(cfrMgr, mm, sm, am, rm, workDir);
diff --git a/modules/vault/src/main/java/org/apache/ignite/internal/vault/VaultManager.java b/modules/vault/src/main/java/org/apache/ignite/internal/vault/VaultManager.java
index 5102d92..f55c11d 100644
--- a/modules/vault/src/main/java/org/apache/ignite/internal/vault/VaultManager.java
+++ b/modules/vault/src/main/java/org/apache/ignite/internal/vault/VaultManager.java
@@ -57,16 +57,6 @@ public class VaultManager implements IgniteComponent {
     }
 
     /**
-     * @return {@code true} if VaultService beneath given VaultManager was bootstrapped with data
-     * either from PDS or from user initial bootstrap configuration.
-     *
-     * TODO: https://issues.apache.org/jira/browse/IGNITE-14956
-     */
-    public boolean bootstrapped() {
-        return false;
-    }
-
-    /**
      * See {@link VaultService#get}
      *
      * @param key Key. Couldn't be {@code null}.