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

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

commit d6a83d61860d79b11b3d43602f068d7de0985bbe
Author: Pochatkin Mikhail <[email protected]>
AuthorDate: Wed Oct 8 11:29:02 2025 +0300

    IGNITE-26363 Node configuration validation on restart
---
 .../storage/DistributedConfigurationStorage.java   | 15 ++--
 .../storage/LocalFileConfigurationStorage.java     | 91 ++++++++++++++--------
 ...Storage.java => VaultConfigurationStorage.java} | 20 ++---
 .../storage/ConfigurationStorageTest.java          |  2 +-
 .../storage/LocalFileConfigurationStorageTest.java | 38 +++++++--
 ...est.java => VaultConfigurationStorageTest.java} |  6 +-
 modules/configuration/build.gradle                 |  4 +
 .../configuration/ItNodeConfigurationTest.java     | 12 +++
 .../configuration/ConfigurationChanger.java        | 72 +++++++----------
 .../configuration/ConfigurationRegistry.java       |  1 -
 .../configuration/ConfigurationUpdateListener.java | 23 ++++++
 .../storage/ConfigurationStorage.java              |  8 +-
 .../storage/ConfigurationStorageListener.java      |  2 +-
 .../storage/{Data.java => ReadEntry.java}          | 17 +++-
 .../internal/configuration/storage/WriteEntry.java | 12 +++
 .../configuration/storage/WriteEntryImpl.java      | 61 +++++++++++++++
 .../configuration/ConfigurationChangerTest.java    |  4 +-
 .../configuration/LocalFileConfigurationTest.java  |  5 ++
 .../configuration/RenamedConfigurationTest.java    |  8 +-
 .../configuration/TestSubConfigurationSchema.java  |  2 +
 .../deprecation/DeprecatedConfigurationTest.java   | 20 ++---
 .../configuration/tree/NamedListNodeTest.java      | 16 ++--
 .../storage/TestConfigurationStorage.java          | 12 +--
 modules/distribution-zones/build.gradle            |  1 +
 ...niteDistributionZoneManagerNodeRestartTest.java |  3 +-
 .../rebalance/ItRebalanceDistributedTest.java      |  3 +-
 modules/partition-replicator/build.gradle          |  1 +
 .../partition/replicator/fixtures/Node.java        |  3 +-
 modules/runner/build.gradle                        |  2 +
 .../configuration/generator/DefaultsGenerator.java | 11 ++-
 .../ItDistributedConfigurationStorageTest.java     |  4 +-
 .../runner/app/ItIgniteNodeRestartTest.java        |  3 +-
 .../org/apache/ignite/internal/app/IgniteImpl.java |  1 +
 33 files changed, 335 insertions(+), 148 deletions(-)

diff --git 
a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/DistributedConfigurationStorage.java
 
b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/DistributedConfigurationStorage.java
index 90c4b5d5c83..2fa676a2c0e 100644
--- 
a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/DistributedConfigurationStorage.java
+++ 
b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/DistributedConfigurationStorage.java
@@ -176,14 +176,14 @@ public class DistributedConfigurationStorage implements 
ConfigurationStorage {
     }
 
     @Override
-    public CompletableFuture<Data> readDataOnRecovery() throws 
StorageException {
-        CompletableFuture<Data> future = 
metaStorageMgr.recoveryFinishedFuture()
+    public CompletableFuture<ReadEntry> readDataOnRecovery() throws 
StorageException {
+        CompletableFuture<ReadEntry> future = 
metaStorageMgr.recoveryFinishedFuture()
                 .thenApplyAsync(revisions -> 
readDataOnRecovery0(revisions.revision()), threadPool);
 
         return registerFuture(future);
     }
 
-    private Data readDataOnRecovery0(long metaStorageRevision) {
+    private ReadEntry readDataOnRecovery0(long metaStorageRevision) {
         Map<String, Serializable> data = new HashMap<>();
         long cfgRevision = 0;
 
@@ -221,12 +221,13 @@ public class DistributedConfigurationStorage implements 
ConfigurationStorage {
 
         changeId = cfgRevision;
 
-        return new Data(data, cfgRevision);
+        return new ReadEntry(data, cfgRevision);
     }
 
     /** {@inheritDoc} */
     @Override
-    public CompletableFuture<Boolean> write(Map<String, ? extends 
Serializable> newValues, long curChangeId) {
+    public CompletableFuture<Boolean> write(WriteEntry writeEntry) {
+        long curChangeId = writeEntry.version();
         assert curChangeId <= changeId;
         assert lsnr != null : "Configuration listener must be initialized 
before write.";
 
@@ -239,7 +240,7 @@ public class DistributedConfigurationStorage implements 
ConfigurationStorage {
 
         var operations = new ArrayList<Operation>();
 
-        for (Map.Entry<String, ? extends Serializable> entry : 
newValues.entrySet()) {
+        for (Map.Entry<String, ? extends Serializable> entry : 
writeEntry.newValues().entrySet()) {
             ByteArray key = new ByteArray(DISTRIBUTED_PREFIX + entry.getKey());
 
             if (entry.getValue() != null) {
@@ -297,7 +298,7 @@ public class DistributedConfigurationStorage implements 
ConfigurationStorage {
 
             changeId = newChangeId;
 
-            return lsnr.onEntriesChanged(new Data(data, newChangeId));
+            return lsnr.onEntriesChanged(new ReadEntry(data, newChangeId));
         });
     }
 
diff --git 
a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java
 
b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java
index 003c39e0caa..93d7657cd8d 100644
--- 
a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java
+++ 
b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorage.java
@@ -24,7 +24,6 @@ import static 
org.apache.ignite.internal.configuration.util.ConfigurationFlatten
 import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.fillFromPrefixMap;
 import static 
org.apache.ignite.internal.configuration.util.ConfigurationUtil.toPrefixMap;
 import static 
org.apache.ignite.internal.util.CompletableFutures.falseCompletedFuture;
-import static 
org.apache.ignite.internal.util.CompletableFutures.trueCompletedFuture;
 
 import com.typesafe.config.Config;
 import com.typesafe.config.ConfigException.Parse;
@@ -71,7 +70,10 @@ import org.apache.ignite.internal.future.InFlightFutures;
 import org.apache.ignite.internal.logger.IgniteLogger;
 import org.apache.ignite.internal.logger.Loggers;
 import org.apache.ignite.internal.thread.IgniteThreadFactory;
+import org.apache.ignite.internal.util.CompletableFutures;
 import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.vault.VaultManager;
+import org.apache.ignite.internal.vault.VaultService;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.TestOnly;
 
@@ -108,6 +110,8 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
     /** Tracks all running futures. */
     private final InFlightFutures futureTracker = new InFlightFutures();
 
+    private final VaultConfigurationStorage vaultStorage;
+
     /** Last revision for configuration. */
     private long lastRevision = 0L;
 
@@ -119,8 +123,13 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
      * @param module Configuration module, which provides configuration 
patches.
      */
     @TestOnly
-    public LocalFileConfigurationStorage(Path configPath, 
ConfigurationTreeGenerator generator, @Nullable ConfigurationModule module) {
-        this("test", configPath, generator, module);
+    public LocalFileConfigurationStorage(
+            Path configPath,
+            ConfigurationTreeGenerator generator,
+            VaultService vaultService,
+            @Nullable ConfigurationModule module
+    ) {
+        this("test", configPath, generator, new VaultManager(vaultService), 
module);
     }
 
     /**
@@ -131,11 +140,23 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
      * @param module Configuration module, which provides configuration 
patches.
      */
     public LocalFileConfigurationStorage(
-            String nodeName, Path configPath, ConfigurationTreeGenerator 
generator, @Nullable ConfigurationModule module) {
+            String nodeName,
+            Path configPath,
+            ConfigurationTreeGenerator generator,
+            VaultManager vaultManager,
+            @Nullable ConfigurationModule module
+    ) {
         this.configPath = configPath;
         this.generator = generator;
         this.tempConfigPath = 
configPath.resolveSibling(configPath.getFileName() + ".tmp");
         this.module = module;
+        this.vaultStorage = new VaultConfigurationStorage(nodeName, 
vaultManager);
+        vaultStorage.registerConfigurationListener(new 
ConfigurationStorageListener() {
+            @Override
+            public CompletableFuture<Void> onEntriesChanged(ReadEntry 
changedEntries) {
+                return CompletableFutures.nullCompletedFuture();
+            }
+        });
 
         notificationsThreadPool = Executors.newFixedThreadPool(
                 2, IgniteThreadFactory.create(nodeName, "cfg-file", LOG)
@@ -145,29 +166,31 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
     }
 
     @Override
-    public CompletableFuture<Data> readDataOnRecovery() {
+    public CompletableFuture<ReadEntry> readDataOnRecovery() {
         lock.writeLock().lock();
         try {
-            // Here we don't use ConfigurationDynamicDefaultsPatcher because 
it works only on Hocon string representation level.
-            // But it's not applicable here because we need to produce map 
presentation with same ids in names lists.
-            // Each tree walk for string to map mapping produce different ids 
by design.
-            String hocon = readHoconFromFile();
-            SuperRoot superRoot = convertToSuperRoot(hocon);
-
-            Map<String, Serializable> transformedHocon = 
transformToMap(superRoot);
-
-            transformedHocon.forEach((key, value) -> {
-                if (value != null) { // Filter defaults.
-                    latest.put(key, value);
+            return vaultStorage.readDataOnRecovery().thenApply(data -> {
+                // Here we don't use ConfigurationDynamicDefaultsPatcher 
because it works only on Hocon string representation level.
+                // But it's not applicable here because we need to produce map 
presentation with same ids in names lists.
+                // Each tree walk for string to map mapping produce different 
ids by design.
+                String hocon = readHoconFromFile();
+                SuperRoot superRoot = convertToSuperRoot(hocon);
+
+                Map<String, Serializable> transformedHocon = 
transformToMap(superRoot);
+
+                transformedHocon.forEach((key, value) -> {
+                    if (value != null) { // Filter defaults.
+                        latest.put(key, value);
+                    }
+                });
+
+                if (module != null) {
+                    module.patchConfigurationWithDynamicDefaults(new 
SuperRootChangeImpl(superRoot));
+                    transformedHocon = transformToMap(superRoot);
                 }
-            });
 
-            if (module != null) {
-                module.patchConfigurationWithDynamicDefaults(new 
SuperRootChangeImpl(superRoot));
-                transformedHocon = transformToMap(superRoot);
-            }
-
-            return completedFuture(new Data(transformedHocon, lastRevision));
+                return new ReadEntry(transformedHocon, lastRevision, 
data.values());
+            });
         } finally {
             lock.writeLock().unlock();
         }
@@ -241,18 +264,25 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
     }
 
     @Override
-    public CompletableFuture<Boolean> write(Map<String, ? extends 
Serializable> newValues, long ver) {
+    public CompletableFuture<Boolean> write(WriteEntry writeEntry) {
         lock.writeLock().lock();
         try {
+            long ver = writeEntry.version();
             if (ver != lastRevision) {
                 return falseCompletedFuture();
             }
 
-            mergeAndSave(newValues);
+            return vaultStorage.write(writeEntry).thenApply(success -> {
+                if (!success) {
+                    return false;
+                }
 
-            sendNotificationAsync(new Data(newValues, lastRevision));
+                Map<String, ? extends Serializable> newValues = 
writeEntry.valuesWithFilteredDefaults();
+                mergeAndSave(newValues);
+                sendNotificationAsync(new ReadEntry(newValues, lastRevision));
 
-            return trueCompletedFuture();
+                return true;
+            });
         } finally {
             lock.writeLock().unlock();
         }
@@ -303,11 +333,6 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
         IgniteUtils.shutdownAndAwaitTermination(notificationsThreadPool, 10, 
TimeUnit.SECONDS);
     }
 
-    @Override
-    public boolean supportDefaults() {
-        return false;
-    }
-
     private void saveConfigFile() {
         if (!Files.isWritable(configPath)) {
             NodeConfigWriteException e = new NodeConfigWriteException(
@@ -394,7 +419,7 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
         }
     }
 
-    private void sendNotificationAsync(Data data) {
+    private void sendNotificationAsync(ReadEntry data) {
         CompletableFuture<Void> future = CompletableFuture.runAsync(
                 () -> lsnrRef.get().onEntriesChanged(data),
                 notificationsThreadPool
diff --git 
a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java
 
b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorage.java
similarity index 91%
rename from 
modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java
rename to 
modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorage.java
index edc73d925fc..0b89d4323ed 100644
--- 
a/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java
+++ 
b/modules/configuration-storage/src/main/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorage.java
@@ -46,7 +46,7 @@ import org.apache.ignite.internal.vault.VaultManager;
 /**
  * Local configuration storage.
  */
-public class LocalConfigurationStorage implements ConfigurationStorage {
+public class VaultConfigurationStorage implements ConfigurationStorage {
     /** Prefix that we add to configuration keys to distinguish them in the 
Vault. */
     private static final String LOC_PREFIX = "loc-cfg.";
 
@@ -54,7 +54,7 @@ public class LocalConfigurationStorage implements 
ConfigurationStorage {
     private static final ByteArray VERSION_KEY = new ByteArray(LOC_PREFIX + 
"$version");
 
     /** Logger. */
-    private static final IgniteLogger LOG = 
Loggers.forClass(LocalConfigurationStorage.class);
+    private static final IgniteLogger LOG = 
Loggers.forClass(VaultConfigurationStorage.class);
 
     /** Vault manager. */
     private final VaultManager vaultMgr;
@@ -89,7 +89,7 @@ public class LocalConfigurationStorage implements 
ConfigurationStorage {
      *
      * @param vaultMgr Vault manager.
      */
-    public LocalConfigurationStorage(String nodeName, VaultManager vaultMgr) {
+    public VaultConfigurationStorage(String nodeName, VaultManager vaultMgr) {
         this.vaultMgr = vaultMgr;
         this.threadPool = Executors.newFixedThreadPool(4, 
IgniteThreadFactory.create(nodeName, "loc-cfg", LOG));
     }
@@ -108,7 +108,7 @@ public class LocalConfigurationStorage implements 
ConfigurationStorage {
 
         var rangeEnd = new ByteArray(incrementLastChar(LOC_PREFIX + prefix));
 
-        return readAll(rangeStart, rangeEnd).thenApply(Data::values);
+        return readAll(rangeStart, rangeEnd).thenApply(ReadEntry::values);
     }
 
     /** {@inheritDoc} */
@@ -127,14 +127,14 @@ public class LocalConfigurationStorage implements 
ConfigurationStorage {
 
     /** {@inheritDoc} */
     @Override
-    public CompletableFuture<Data> readDataOnRecovery() {
+    public CompletableFuture<ReadEntry> readDataOnRecovery() {
         return readAll(LOC_KEYS_START_RANGE, LOC_KEYS_END_RANGE);
     }
 
     /**
      * Retrieves all data, which keys lie in between {@code [rangeStart, 
rangeEnd)}.
      */
-    private CompletableFuture<Data> readAll(ByteArray rangeStart, ByteArray 
rangeEnd) {
+    private CompletableFuture<ReadEntry> readAll(ByteArray rangeStart, 
ByteArray rangeEnd) {
         return registerFuture(supplyAsync(() -> {
             var data = new HashMap<String, Serializable>();
 
@@ -156,14 +156,16 @@ public class LocalConfigurationStorage implements 
ConfigurationStorage {
                 throw new StorageException("Exception when closing a Vault 
cursor", e);
             }
 
-            return new Data(data, version);
+            return new ReadEntry(data, version);
         }, threadPool));
     }
 
     /** {@inheritDoc} */
     @Override
-    public CompletableFuture<Boolean> write(Map<String, ? extends 
Serializable> newValues, long sentVersion) {
+    public CompletableFuture<Boolean> write(WriteEntry writeEntry) {
         synchronized (writeSerializationLock) {
+            long sentVersion = writeEntry.version();
+            Map<String, ? extends Serializable> newValues = 
writeEntry.newValues();
             CompletableFuture<Boolean> writeFuture = 
registerFuture(writeSerializationFuture
                     .thenCompose(v -> lastRevision())
                     .thenComposeAsync(version -> {
@@ -192,7 +194,7 @@ public class LocalConfigurationStorage implements 
ConfigurationStorage {
                             ));
                         }
 
-                        Data entries = new Data(newValues, version + 1);
+                        ReadEntry entries = new ReadEntry(newValues, version + 
1);
 
                         vaultMgr.putAll(data);
 
diff --git 
a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageTest.java
 
b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageTest.java
index 27005298691..b95bd9350dc 100644
--- 
a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageTest.java
+++ 
b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageTest.java
@@ -57,7 +57,7 @@ public abstract class ConfigurationStorageTest {
     public void testReadAllLatest() {
         var data = Map.of("foo1", "bar1", "foo2", "bar2");
 
-        assertThat(storage.write(data, 0), willBe(equalTo(true)));
+        assertThat(storage.write(new WriteEntryImpl(data, 0)), 
willBe(equalTo(true)));
 
         // test that reading without a prefix retrieves all data
         CompletableFuture<Map<String, ? extends Serializable>> latestData = 
storage.readAllLatest("");
diff --git 
a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorageTest.java
 
b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorageTest.java
index 6d46b528df8..b1b6bea8a04 100644
--- 
a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorageTest.java
+++ 
b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalFileConfigurationStorageTest.java
@@ -46,6 +46,7 @@ import java.nio.file.Path;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import org.apache.ignite.configuration.ConfigurationChangeException;
 import org.apache.ignite.configuration.KeyIgnorer;
 import org.apache.ignite.configuration.annotation.Config;
 import org.apache.ignite.configuration.annotation.ConfigValue;
@@ -58,6 +59,7 @@ import 
org.apache.ignite.configuration.annotation.PolymorphicId;
 import org.apache.ignite.configuration.annotation.PublicName;
 import org.apache.ignite.configuration.annotation.Value;
 import 
org.apache.ignite.configuration.validation.ConfigurationValidationException;
+import org.apache.ignite.configuration.validation.Immutable;
 import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator;
 import org.apache.ignite.internal.configuration.TestConfigurationChanger;
 import org.apache.ignite.internal.configuration.hocon.HoconConverter;
@@ -65,6 +67,7 @@ import 
org.apache.ignite.internal.configuration.tree.ConfigurationSource;
 import 
org.apache.ignite.internal.configuration.validation.ConfigurationValidatorImpl;
 import org.apache.ignite.internal.testframework.WorkDirectory;
 import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
+import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService;
 import org.hamcrest.Matchers;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
@@ -110,7 +113,7 @@ public class LocalFileConfigurationStorageTest {
     @BeforeEach
     void before() {
         LocalFileConfigurationModule module = new 
LocalFileConfigurationModule();
-        storage = new LocalFileConfigurationStorage(getConfigFile(), 
treeGenerator, module);
+        storage = new LocalFileConfigurationStorage(getConfigFile(), 
treeGenerator, new InMemoryVaultService(), module);
 
         changer = new TestConfigurationChanger(
                 List.of(TopConfiguration.KEY),
@@ -478,7 +481,7 @@ public class LocalFileConfigurationStorageTest {
         ConfigParseOptions parseOptions = 
ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON).setAllowMissing(false);
         assertDoesNotThrow(() -> ConfigFactory.parseFile(configFile.toFile(), 
parseOptions));
 
-        LocalFileConfigurationStorage storage = new 
LocalFileConfigurationStorage(configFile, treeGenerator, null);
+        LocalFileConfigurationStorage storage = new 
LocalFileConfigurationStorage(configFile, treeGenerator, new 
InMemoryVaultService(), null);
 
         // And storage reads the file successfully
         assertDoesNotThrow(storage::readDataOnRecovery);
@@ -507,7 +510,7 @@ public class LocalFileConfigurationStorageTest {
 
         // And storage detects duplicates
         assertThrows(
-                ConfigurationValidationException.class,
+                ConfigurationChangeException.class,
                 changer::start,
                 "Validation did not pass for keys: [top.inner.boolVal, 
Duplicated key]"
         );
@@ -551,8 +554,29 @@ public class LocalFileConfigurationStorageTest {
 
         assertFalse(Files.isWritable(configFile));
 
-        var storage = new LocalFileConfigurationStorage(configFile, 
treeGenerator, new LocalFileConfigurationModule());
-        assertThat(storage.write(Map.of(), storage.localRevision().get() + 1), 
willCompleteSuccessfully());
+        var storage = new LocalFileConfigurationStorage(
+                configFile,
+                treeGenerator,
+                new InMemoryVaultService(),
+                new LocalFileConfigurationModule()
+        );
+        assertThat(storage.write(new WriteEntryImpl(Map.of(), 
storage.localRevision().get() + 1)), willCompleteSuccessfully());
+    }
+
+    @Test
+    void test() throws Exception {
+        Path configFile = tmpDir.resolve(CONFIG_NAME + "test");
+        File file = configFile.toFile();
+
+        assertFalse(Files.isWritable(configFile));
+
+        var storage = new LocalFileConfigurationStorage(
+                configFile,
+                treeGenerator,
+                new InMemoryVaultService(),
+                new LocalFileConfigurationModule()
+        );
+        assertThat(storage.write(new WriteEntryImpl(Map.of(), 
storage.localRevision().get() + 1)), willCompleteSuccessfully());
     }
 
     @Test
@@ -604,6 +628,10 @@ public class LocalFileConfigurationStorageTest {
 
         @NamedConfigValue
         public PolyNamedListConfigurationSchema polyNamedList;
+
+        @Immutable
+        @Value(hasDefault = true)
+        public int immutable = 0;
     }
 
 
diff --git 
a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorageTest.java
 
b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorageTest.java
similarity index 91%
rename from 
modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorageTest.java
rename to 
modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorageTest.java
index e68e597ac21..4fbcabf04ed 100644
--- 
a/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorageTest.java
+++ 
b/modules/configuration-storage/src/test/java/org/apache/ignite/internal/configuration/storage/VaultConfigurationStorageTest.java
@@ -27,9 +27,9 @@ import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 
 /**
- * Tests for the {@link LocalConfigurationStorage}.
+ * Tests for the {@link VaultConfigurationStorage}.
  */
-public class LocalConfigurationStorageTest extends ConfigurationStorageTest {
+public class VaultConfigurationStorageTest extends ConfigurationStorageTest {
     private final VaultManager vaultManager = new VaultManager(new 
InMemoryVaultService());
 
     /**
@@ -51,6 +51,6 @@ public class LocalConfigurationStorageTest extends 
ConfigurationStorageTest {
     /** {@inheritDoc} */
     @Override
     public ConfigurationStorage getStorage() {
-        return new LocalConfigurationStorage("test-node-name", vaultManager);
+        return new VaultConfigurationStorage("test-node-name", vaultManager);
     }
 }
diff --git a/modules/configuration/build.gradle 
b/modules/configuration/build.gradle
index f0f77c6676c..47c931a0195 100644
--- a/modules/configuration/build.gradle
+++ b/modules/configuration/build.gradle
@@ -19,6 +19,7 @@ apply from: "$rootDir/buildscripts/java-core.gradle"
 apply from: "$rootDir/buildscripts/publishing.gradle"
 apply from: "$rootDir/buildscripts/java-junit5.gradle"
 apply from: "$rootDir/buildscripts/java-test-fixtures.gradle"
+apply from: "$rootDir/buildscripts/java-integration-test.gradle"
 
 description = 'ignite-configuration'
 
@@ -39,4 +40,7 @@ dependencies {
     testFixturesImplementation project(':ignite-core')
     testFixturesImplementation testFixtures(project(':ignite-core'))
     testFixturesImplementation libs.typesafe.config
+
+    integrationTestImplementation testFixtures(project(':ignite-core'))
+    integrationTestImplementation testFixtures(project(':ignite-runner'))
 }
diff --git 
a/modules/configuration/src/integrationTest/java/org/apache/ignite/internal/configuration/ItNodeConfigurationTest.java
 
b/modules/configuration/src/integrationTest/java/org/apache/ignite/internal/configuration/ItNodeConfigurationTest.java
new file mode 100644
index 00000000000..0ba2414c47b
--- /dev/null
+++ 
b/modules/configuration/src/integrationTest/java/org/apache/ignite/internal/configuration/ItNodeConfigurationTest.java
@@ -0,0 +1,12 @@
+package org.apache.ignite.internal.configuration;
+
+import org.apache.ignite.internal.ClusterPerClassIntegrationTest;
+import org.junit.jupiter.api.Test;
+
+public class ItNodeConfigurationTest extends ClusterPerClassIntegrationTest {
+
+    @Test
+    public void test() {
+
+    }
+}
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
index e368a00ff29..6f38f2d5663 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationChanger.java
@@ -48,7 +48,6 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NavigableMap;
 import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.RandomAccess;
 import java.util.StringJoiner;
 import java.util.TreeMap;
@@ -69,7 +68,8 @@ import 
org.apache.ignite.configuration.validation.ValidationIssue;
 import org.apache.ignite.internal.configuration.direct.KeyPathNode;
 import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
 import 
org.apache.ignite.internal.configuration.storage.ConfigurationStorageListener;
-import org.apache.ignite.internal.configuration.storage.Data;
+import org.apache.ignite.internal.configuration.storage.ReadEntry;
+import org.apache.ignite.internal.configuration.storage.WriteEntryImpl;
 import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
 import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor;
 import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode;
@@ -134,25 +134,6 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
     /** Keys that were deleted from the configuration, but were present in the 
storage. Will be deleted on startup. */
     private Collection<String> ignoredKeys;
 
-    /**
-     * Closure interface to be used by the configuration changer. An instance 
of this closure is passed into the constructor and invoked
-     * every time when there's an update from any of the storages.
-     */
-    public interface ConfigurationUpdateListener {
-        /**
-         * Invoked every time when the configuration is updated.
-         *
-         * @param oldRoot Old roots values. All these roots always belong to a 
single storage.
-         * @param newRoot New values for the same roots as in {@code oldRoot}.
-         * @param storageRevision Configuration revision of the storage.
-         * @param notificationNumber Configuration listener notification 
number.
-         * @return Future that must signify when processing is completed. 
Exceptional completion is not expected.
-         */
-        CompletableFuture<Void> onConfigurationUpdated(
-                @Nullable SuperRoot oldRoot, SuperRoot newRoot, long 
storageRevision, long notificationNumber
-        );
-    }
-
     /**
      * Immutable data container to store version and all roots associated with 
the specific storage.
      */
@@ -280,7 +261,7 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
      * Start component.
      */
     public void start() {
-        Data data;
+        ReadEntry data;
 
         try {
             data = storage.readDataOnRecovery().get();
@@ -292,7 +273,8 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
             throw new ConfigurationChangeException("Failed to initialize 
configuration: " + e.getMessage(), e);
         }
 
-        var storageValues = new HashMap<String, Serializable>(data.values());
+        Map<String, ? extends Serializable> values = data.values();
+        var storageValues = new HashMap<String, Serializable>(values);
 
         ignoredKeys = ignoreDeleted(storageValues, keyIgnorer);
 
@@ -324,15 +306,36 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
             initialConfiguration.descend(superRoot);
         }
 
-        // Validate the restored configuration.
-        validateConfiguration(superRoot);
+        Map<String, ? extends Serializable> invariant = data.invariant();
+        if (!invariant.isEmpty()) {
+            SuperRoot invariantRoot = new SuperRoot(rootCreator());
+            Map<String, ?> invariantPrefixMap = toPrefixMap(invariant);
+
+            for (RootKey<?, ?, ?> rootKey : rootKeys.values()) {
+                Map<String, ?> rootPrefixMap = (Map<String, ?>) 
invariantPrefixMap.get(rootKey.key());
+
+                InnerNode rootNode = createRootNode(rootKey);
+
+                if (rootPrefixMap != null) {
+                    fillFromPrefixMap(rootNode, rootPrefixMap);
+                }
+
+                invariantRoot.addRoot(rootKey, rootNode);
+            }
+
+            // Validate the restored configuration.
+            validateConfiguration(invariantRoot, superRoot);
+        } else {
+            validateConfiguration(superRoot);
+        }
+
         // We store two configuration roots, one with the defaults set and 
another one without them.
         // The root WITH the defaults is used when we calculate who to notify 
of a configuration change or
         // when we provide the configuration outside.
         // The root WITHOUT the defaults is used to calculate which properties 
to write to the underlying storage,
         // in other words it allows us to persist the defaults from the code.
         // After the storage listener fires for the first time both roots are 
supposed to become equal.
-        storageRoots = new StorageRoots(superRootNoDefaults, superRoot, 
data.changeId(), new TreeMap<>(data.values()));
+        storageRoots = new StorageRoots(superRootNoDefaults, superRoot, 
data.changeId(), new TreeMap<>(values));
 
         storage.registerConfigurationListener(configurationStorageListener());
 
@@ -676,17 +679,11 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
 
             validateConfiguration(curRoots, changes);
 
-            // In some cases some storages may not want to persist 
configuration defaults.
-            // Need to filter it from change map before write to storage.
-            if (!storage.supportDefaults()) {
-                removeDefaultValues(allChanges);
-            }
-
             // "allChanges" map can be empty here in case the given update 
matches the current state of the local configuration. We
             // still try to write the empty update, because local 
configuration can be obsolete. If this is the case, then the CAS will
             // fail and the update will be recalculated and there is a chance 
that the new local configuration will produce a non-empty
             // update.
-            return storage.write(allChanges, localRoots.changeId)
+            return storage.write(new WriteEntryImpl(allChanges, 
defaultsMap.get(), localRoots.changeId))
                     .thenCompose(casWroteSuccessfully -> {
                         if (casWroteSuccessfully) {
                             return localRoots.changeFuture;
@@ -798,15 +795,6 @@ public abstract class ConfigurationChanger implements 
DynamicConfigurationChange
         allChanges.entrySet().removeIf(entry -> entry.getValue() == null && 
!localRoots.storageData.containsKey(entry.getKey()));
     }
 
-    private void removeDefaultValues(Map<String, Serializable> allChanges) {
-        defaultsMap.get().forEach((key, defaultValue) -> {
-            Serializable change = allChanges.get(key);
-            if (Objects.deepEquals(change, defaultValue)) {
-                allChanges.put(key, null);
-            }
-        });
-    }
-
     private Map<String, Serializable> createDefaultsMap() {
         SuperRoot superRoot = new SuperRoot(rootCreator());
         for (RootKey<?, ?, ?> rootKey : rootKeys.values()) {
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationRegistry.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationRegistry.java
index c5a17433a52..445f34f6532 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationRegistry.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationRegistry.java
@@ -33,7 +33,6 @@ import org.apache.ignite.configuration.ConfigurationTree;
 import org.apache.ignite.configuration.KeyIgnorer;
 import org.apache.ignite.configuration.RootKey;
 import org.apache.ignite.configuration.SuperRootChange;
-import 
org.apache.ignite.internal.configuration.ConfigurationChanger.ConfigurationUpdateListener;
 import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
 import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
 import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor;
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationUpdateListener.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationUpdateListener.java
new file mode 100644
index 00000000000..bb6a72117cd
--- /dev/null
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/ConfigurationUpdateListener.java
@@ -0,0 +1,23 @@
+package org.apache.ignite.internal.configuration;
+
+import java.util.concurrent.CompletableFuture;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Closure interface to be used by the configuration changer. An instance of 
this closure is passed into the constructor and invoked every
+ * time when there's an update from any of the storages.
+ */
+public interface ConfigurationUpdateListener {
+    /**
+     * Invoked every time when the configuration is updated.
+     *
+     * @param oldRoot Old roots values. All these roots always belong to a 
single storage.
+     * @param newRoot New values for the same roots as in {@code oldRoot}.
+     * @param storageRevision Configuration revision of the storage.
+     * @param notificationNumber Configuration listener notification number.
+     * @return Future that must signify when processing is completed. 
Exceptional completion is not expected.
+     */
+    CompletableFuture<Void> onConfigurationUpdated(
+            @Nullable SuperRoot oldRoot, SuperRoot newRoot, long 
storageRevision, long notificationNumber
+    );
+}
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorage.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorage.java
index b2a8da48b69..ff1ac34b000 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorage.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorage.java
@@ -32,7 +32,7 @@ public interface ConfigurationStorage extends 
ManuallyCloseable {
      *
      * @return Future that resolves into extracted values and version or a 
{@link StorageException} if the data could not be read.
      */
-    CompletableFuture<Data> readDataOnRecovery();
+    CompletableFuture<ReadEntry> readDataOnRecovery();
 
     /**
      * Retrieves the most recent values which keys start with the given 
prefix, regardless of the current storage version.
@@ -58,7 +58,7 @@ public interface ConfigurationStorage extends 
ManuallyCloseable {
      * @return Future that gives you {@code true} if successfully written, 
{@code false} if version of the storage is different from the
      *      passed argument and {@link StorageException} if failed to write 
data.
      */
-    CompletableFuture<Boolean> write(Map<String, ? extends Serializable> 
newValues, long ver);
+    CompletableFuture<Boolean> write(WriteEntry writeEntry);
 
     /**
      * Add listener to the storage that notifies of data changes.
@@ -82,10 +82,6 @@ public interface ConfigurationStorage extends 
ManuallyCloseable {
     /** Returns a future that will be completed with the latest revision of 
the configuration storage. */
     CompletableFuture<Long> localRevision();
 
-    default boolean supportDefaults() {
-        return true;
-    }
-
     /**
      * Closes the storage.
      */
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageListener.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageListener.java
index 928050e9c1f..42716ba3fc1 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageListener.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ConfigurationStorageListener.java
@@ -30,5 +30,5 @@ public interface ConfigurationStorageListener {
      * @param changedEntries Changed entries, key-value pairs and new version 
of the storage.
      * @return Completable future that signifies the completion of all custom 
user listeners execution.
      */
-    CompletableFuture<Void> onEntriesChanged(Data changedEntries);
+    CompletableFuture<Void> onEntriesChanged(ReadEntry changedEntries);
 }
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/Data.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ReadEntry.java
similarity index 74%
rename from 
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/Data.java
rename to 
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ReadEntry.java
index 685e7e19b6e..5debc55e7b0 100644
--- 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/Data.java
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/ReadEntry.java
@@ -24,10 +24,12 @@ import java.util.Map;
 /**
  * Represents data in configuration storage.
  */
-public class Data {
+public class ReadEntry {
     /** Values. */
     private final Map<String, ? extends Serializable> values;
 
+    private final Map<String, ? extends Serializable> invariant;
+
     /** Configuration storage version. */
     private final long changeId;
 
@@ -37,9 +39,16 @@ public class Data {
      * @param values   Values.
      * @param changeId Version.
      */
-    public Data(Map<String, ? extends Serializable> values, long changeId) {
+    public ReadEntry(Map<String, ? extends Serializable> values, long 
changeId) {
         this.values = Collections.unmodifiableMap(values);
         this.changeId = changeId;
+        this.invariant = Collections.emptyMap();
+    }
+
+    public ReadEntry(Map<String, ? extends Serializable> values, long 
changeId, Map<String, ? extends Serializable> invariant) {
+        this.values = values;
+        this.changeId = changeId;
+        this.invariant = invariant;
     }
 
     /** Get values. */
@@ -47,6 +56,10 @@ public class Data {
         return values;
     }
 
+    public Map<String, ? extends Serializable> invariant() {
+        return invariant;
+    }
+
     /**
      * Get version.
      *
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntry.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntry.java
new file mode 100644
index 00000000000..901a7512cf3
--- /dev/null
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntry.java
@@ -0,0 +1,12 @@
+package org.apache.ignite.internal.configuration.storage;
+
+import java.io.Serializable;
+import java.util.Map;
+
+public interface WriteEntry {
+    Map<String, ? extends Serializable> newValues();
+
+    Map<String, ? extends Serializable> valuesWithFilteredDefaults();
+
+    long version();
+}
diff --git 
a/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntryImpl.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntryImpl.java
new file mode 100644
index 00000000000..dbb3a9990df
--- /dev/null
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/WriteEntryImpl.java
@@ -0,0 +1,61 @@
+package org.apache.ignite.internal.configuration.storage;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.ignite.internal.util.Lazy;
+
+public class WriteEntryImpl implements WriteEntry {
+    private final Map<String, ? extends Serializable> defaults;
+
+    private final Map<String, ? extends Serializable> allChanges;
+
+    private final Lazy<Map<String, ? extends Serializable>> filtered = new 
Lazy<>(this::filteredDefaults);
+
+    private final long version;
+
+    public WriteEntryImpl(
+            Map<String, ? extends Serializable> changes,
+            long version
+    ) {
+        this(changes, Map.of(), version);
+    }
+
+    public WriteEntryImpl(
+            Map<String, ? extends Serializable> allChanges,
+            Map<String, ? extends Serializable> defaults,
+            long version
+    ) {
+        this.defaults = defaults;
+        this.allChanges = allChanges;
+        this.version = version;
+    }
+
+    @Override
+    public Map<String, ? extends Serializable> newValues() {
+        return Collections.unmodifiableMap(allChanges);
+    }
+
+    @Override
+    public Map<String, ? extends Serializable> valuesWithFilteredDefaults() {
+        return filtered.get();
+    }
+
+    @Override
+    public long version() {
+        return version;
+    }
+
+    private Map<String, ? extends Serializable> filteredDefaults() {
+        Map<String, ? extends Serializable> result = new HashMap<>(allChanges);
+        defaults.forEach((key, defaultValue) -> {
+            Serializable change = result.get(key);
+            if (Objects.deepEquals(change, defaultValue)) {
+                result.put(key, null);
+            }
+        });
+        return result;
+    }
+}
diff --git 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/ConfigurationChangerTest.java
 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/ConfigurationChangerTest.java
index 41f00cfe175..fe5ecd93867 100644
--- 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/ConfigurationChangerTest.java
+++ 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/ConfigurationChangerTest.java
@@ -62,7 +62,7 @@ import org.apache.ignite.configuration.validation.Validator;
 import org.apache.ignite.internal.configuration.direct.KeyPathNode;
 import org.apache.ignite.internal.configuration.hocon.HoconConverter;
 import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
-import org.apache.ignite.internal.configuration.storage.Data;
+import org.apache.ignite.internal.configuration.storage.ReadEntry;
 import 
org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
 import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
 import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode;
@@ -274,7 +274,7 @@ public class ConfigurationChangerTest {
 
         storage.fail(false);
 
-        CompletableFuture<Map<String, ? extends Serializable>> dataFuture = 
storage.readDataOnRecovery().thenApply(Data::values);
+        CompletableFuture<Map<String, ? extends Serializable>> dataFuture = 
storage.readDataOnRecovery().thenApply(ReadEntry::values);
 
         assertThat(dataFuture, willCompleteSuccessfully());
 
diff --git 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/LocalFileConfigurationTest.java
 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/LocalFileConfigurationTest.java
new file mode 100644
index 00000000000..88e0dad3457
--- /dev/null
+++ 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/LocalFileConfigurationTest.java
@@ -0,0 +1,5 @@
+package org.apache.ignite.internal.configuration;
+
+public class LocalFileConfigurationTest {
+    private final
+}
diff --git 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/RenamedConfigurationTest.java
 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/RenamedConfigurationTest.java
index 6ec3abb5884..140c6668ac5 100644
--- 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/RenamedConfigurationTest.java
+++ 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/RenamedConfigurationTest.java
@@ -48,7 +48,7 @@ import 
org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
 import org.apache.ignite.configuration.annotation.PolymorphicId;
 import org.apache.ignite.configuration.annotation.PublicName;
 import org.apache.ignite.configuration.annotation.Value;
-import org.apache.ignite.internal.configuration.storage.Data;
+import org.apache.ignite.internal.configuration.storage.ReadEntry;
 import 
org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
 import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
 import 
org.apache.ignite.internal.configuration.validation.TestConfigurationValidator;
@@ -272,7 +272,7 @@ class RenamedConfigurationTest extends 
BaseIgniteAbstractTest {
      */
     @SafeVarargs
     private void validateStorageContent(Map.Entry<String, Serializable> 
...values) {
-        CompletableFuture<Data> dataFuture = storage.readDataOnRecovery();
+        CompletableFuture<ReadEntry> dataFuture = storage.readDataOnRecovery();
         assertThat(dataFuture, willCompleteSuccessfully());
 
         RenamedTestNewView node = 
registry.getConfiguration(RenamedTestNewConfiguration.KEY).value();
@@ -318,8 +318,8 @@ class RenamedConfigurationTest extends 
BaseIgniteAbstractTest {
         storage.close();
     }
 
-    private Data getData() {
-        CompletableFuture<Data> dataFuture = storage.readDataOnRecovery();
+    private ReadEntry getData() {
+        CompletableFuture<ReadEntry> dataFuture = storage.readDataOnRecovery();
 
         assertThat(dataFuture, willCompleteSuccessfully());
 
diff --git 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/TestSubConfigurationSchema.java
 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/TestSubConfigurationSchema.java
index 5f2287a24e5..6d5cd9a3dc5 100644
--- 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/TestSubConfigurationSchema.java
+++ 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/TestSubConfigurationSchema.java
@@ -35,4 +35,6 @@ public class TestSubConfigurationSchema {
 
     @Value(hasDefault = true)
     public int testInt;
+
+
 }
diff --git 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/deprecation/DeprecatedConfigurationTest.java
 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/deprecation/DeprecatedConfigurationTest.java
index 4f0e9c63b08..8f793a93b68 100644
--- 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/deprecation/DeprecatedConfigurationTest.java
+++ 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/deprecation/DeprecatedConfigurationTest.java
@@ -49,7 +49,7 @@ import org.apache.ignite.internal.configuration.SuperRoot;
 import org.apache.ignite.internal.configuration.SuperRootChangeImpl;
 import org.apache.ignite.internal.configuration.TestConfigurationChanger;
 import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
-import org.apache.ignite.internal.configuration.storage.Data;
+import org.apache.ignite.internal.configuration.storage.ReadEntry;
 import 
org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
 import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
 import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode;
@@ -197,7 +197,7 @@ public class DeprecatedConfigurationTest extends 
BaseIgniteAbstractTest {
                     lastWriteCapture.getValue()
             );
 
-            Data data = getData();
+            ReadEntry data = getData();
 
             assertEquals(1, data.changeId());
             assertEquals(
@@ -227,7 +227,7 @@ public class DeprecatedConfigurationTest extends 
BaseIgniteAbstractTest {
             );
 
             // Check that deprecated value is not present in the storage 
anymore.
-            Data data = getData();
+            ReadEntry data = getData();
             assertEquals(2, data.changeId());
             assertEquals(
                     Map.of("root.child.my-int-cfg", 99),
@@ -315,7 +315,7 @@ public class DeprecatedConfigurationTest extends 
BaseIgniteAbstractTest {
             );
 
             // Check that deprecated value is not present in the storage 
anymore.
-            Data data = getData();
+            ReadEntry data = getData();
 
             assertEquals(2, data.changeId());
             assertEquals(
@@ -370,7 +370,7 @@ public class DeprecatedConfigurationTest extends 
BaseIgniteAbstractTest {
             );
 
             // Check storage state.
-            Data data = getData();
+            ReadEntry data = getData();
 
             assertEquals(2, data.changeId());
             assertEquals(
@@ -403,7 +403,7 @@ public class DeprecatedConfigurationTest extends 
BaseIgniteAbstractTest {
             );
 
             // Check that deprecated value is not present in the storage 
anymore.
-            Data data = getData();
+            ReadEntry data = getData();
 
             assertEquals(3, data.changeId());
             assertEquals(
@@ -467,7 +467,7 @@ public class DeprecatedConfigurationTest extends 
BaseIgniteAbstractTest {
             );
 
             // Check storage state.
-            Data data = getData();
+            ReadEntry data = getData();
 
             assertEquals(2, data.changeId());
             assertEquals(
@@ -502,7 +502,7 @@ public class DeprecatedConfigurationTest extends 
BaseIgniteAbstractTest {
             );
 
             // Check that deprecated value is not present in the storage 
anymore.
-            Data data = getData();
+            ReadEntry data = getData();
 
             assertEquals(3, data.changeId());
             assertEquals(
@@ -557,8 +557,8 @@ public class DeprecatedConfigurationTest extends 
BaseIgniteAbstractTest {
         assertThat(changeFuture, willCompleteSuccessfully());
     }
 
-    private Data getData() {
-        CompletableFuture<Data> dataFuture = storage.readDataOnRecovery();
+    private ReadEntry getData() {
+        CompletableFuture<ReadEntry> dataFuture = storage.readDataOnRecovery();
 
         assertThat(dataFuture, willCompleteSuccessfully());
 
diff --git 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/tree/NamedListNodeTest.java
 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/tree/NamedListNodeTest.java
index 7c334618a5f..aaed6127bcf 100644
--- 
a/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/tree/NamedListNodeTest.java
+++ 
b/modules/configuration/src/test/java/org/apache/ignite/internal/configuration/tree/NamedListNodeTest.java
@@ -39,7 +39,7 @@ import 
org.apache.ignite.configuration.annotation.NamedConfigValue;
 import org.apache.ignite.configuration.annotation.Value;
 import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator;
 import org.apache.ignite.internal.configuration.TestConfigurationChanger;
-import org.apache.ignite.internal.configuration.storage.Data;
+import org.apache.ignite.internal.configuration.storage.ReadEntry;
 import 
org.apache.ignite.internal.configuration.storage.TestConfigurationStorage;
 import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
 import 
org.apache.ignite.internal.configuration.validation.TestConfigurationValidator;
@@ -140,7 +140,7 @@ public class NamedListNodeTest {
         UUID x0Id = ((NamedListNode<?>) a.second().value()).internalId("X");
         UUID z0Id = ((NamedListNode<?>) 
a.second().get("X").third().value()).internalId("Z0");
 
-        CompletableFuture<Map<String, ? extends Serializable>> storageValues = 
storage.readDataOnRecovery().thenApply(Data::values);
+        CompletableFuture<Map<String, ? extends Serializable>> storageValues = 
storage.readDataOnRecovery().thenApply(ReadEntry::values);
 
         assertThat(
                 storageValues,
@@ -164,7 +164,7 @@ public class NamedListNodeTest {
 
         UUID z5Id = ((NamedListNode<?>) 
a.second().get("X").third().value()).internalId("Z5");
 
-        storageValues = storage.readDataOnRecovery().thenApply(Data::values);
+        storageValues = 
storage.readDataOnRecovery().thenApply(ReadEntry::values);
 
         assertThat(
                 storageValues,
@@ -190,7 +190,7 @@ public class NamedListNodeTest {
 
         UUID z2Id = ((NamedListNode<?>) 
a.second().get("X").third().value()).internalId("Z2");
 
-        storageValues = storage.readDataOnRecovery().thenApply(Data::values);
+        storageValues = 
storage.readDataOnRecovery().thenApply(ReadEntry::values);
 
         assertThat(
                 storageValues,
@@ -220,7 +220,7 @@ public class NamedListNodeTest {
 
         UUID z3Id = ((NamedListNode<?>) 
a.second().get("X").third().value()).internalId("Z3");
 
-        storageValues = storage.readDataOnRecovery().thenApply(Data::values);
+        storageValues = 
storage.readDataOnRecovery().thenApply(ReadEntry::values);
 
         assertThat(
                 storageValues,
@@ -252,7 +252,7 @@ public class NamedListNodeTest {
         // Delete keys from the middle. Indexes of Z3 should be updated to 1.
         x.third().change(xb -> xb.delete("Z2").delete("Z5")).get();
 
-        storageValues = storage.readDataOnRecovery().thenApply(Data::values);
+        storageValues = 
storage.readDataOnRecovery().thenApply(ReadEntry::values);
 
         assertThat(
                 storageValues,
@@ -276,7 +276,7 @@ public class NamedListNodeTest {
         // Delete keys from the middle. Indexes of Z3 should be updated to 1.
         x.third().change(xb -> xb.rename("Z0", "Z1")).get();
 
-        storageValues = storage.readDataOnRecovery().thenApply(Data::values);
+        storageValues = 
storage.readDataOnRecovery().thenApply(ReadEntry::values);
 
         assertThat(
                 storageValues,
@@ -300,7 +300,7 @@ public class NamedListNodeTest {
         // Delete values on several layers simultaneously. Storage must be 
empty after that.
         a.second().change(b -> b.delete("X")).get();
 
-        assertThat(storage.readDataOnRecovery().thenApply(Data::values), 
willBe(anEmptyMap()));
+        assertThat(storage.readDataOnRecovery().thenApply(ReadEntry::values), 
willBe(anEmptyMap()));
     }
 
     /** Tests exceptions described in methods signatures. */
diff --git 
a/modules/configuration/src/testFixtures/java/org/apache/ignite/internal/configuration/storage/TestConfigurationStorage.java
 
b/modules/configuration/src/testFixtures/java/org/apache/ignite/internal/configuration/storage/TestConfigurationStorage.java
index 7bd50a019a9..bf4a2a5a372 100644
--- 
a/modules/configuration/src/testFixtures/java/org/apache/ignite/internal/configuration/storage/TestConfigurationStorage.java
+++ 
b/modules/configuration/src/testFixtures/java/org/apache/ignite/internal/configuration/storage/TestConfigurationStorage.java
@@ -108,32 +108,32 @@ public class TestConfigurationStorage implements 
ConfigurationStorage {
 
     /** {@inheritDoc} */
     @Override
-    public CompletableFuture<Data> readDataOnRecovery() {
+    public CompletableFuture<ReadEntry> readDataOnRecovery() {
         return supplyAsync(() -> {
             synchronized (this) {
                 if (fail) {
                     throw new StorageException("Failed to read data");
                 }
 
-                return new Data(new HashMap<>(map), version);
+                return new ReadEntry(new HashMap<>(map), version);
             }
         });
     }
 
     /** {@inheritDoc} */
     @Override
-    public CompletableFuture<Boolean> write(Map<String, ? extends 
Serializable> newValues, long sentVersion) {
+    public CompletableFuture<Boolean> write(WriteEntry writeEntry) {
         return supplyAsync(() -> {
             synchronized (this) {
                 if (fail) {
                     throw new StorageException("Failed to write data");
                 }
 
-                if (sentVersion != version) {
+                if (writeEntry.version() != version) {
                     return false;
                 }
 
-                for (Map.Entry<String, ? extends Serializable> entry : 
newValues.entrySet()) {
+                for (Map.Entry<String, ? extends Serializable> entry : 
writeEntry.newValues().entrySet()) {
                     if (entry.getValue() != null) {
                         map.put(entry.getKey(), entry.getValue());
                     } else {
@@ -143,7 +143,7 @@ public class TestConfigurationStorage implements 
ConfigurationStorage {
 
                 version++;
 
-                var data = new Data(newValues, version);
+                var data = new ReadEntry(writeEntry.newValues(), version);
 
                 listeners.forEach(listener -> 
listener.onEntriesChanged(data).join());
 
diff --git a/modules/distribution-zones/build.gradle 
b/modules/distribution-zones/build.gradle
index 1d6bc17185e..7f4aa5535ea 100644
--- a/modules/distribution-zones/build.gradle
+++ b/modules/distribution-zones/build.gradle
@@ -129,6 +129,7 @@ dependencies {
     integrationTestImplementation testFixtures(project(':ignite-transactions'))
     integrationTestImplementation testFixtures(project(':ignite-sql-engine'))
     integrationTestImplementation 
testFixtures(project(':ignite-configuration-system'))
+    integrationTestImplementation testFixtures(project(':ignite-vault'))
 
 }
 
diff --git 
a/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/distributionzones/ItIgniteDistributionZoneManagerNodeRestartTest.java
 
b/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/distributionzones/ItIgniteDistributionZoneManagerNodeRestartTest.java
index 3673a1138f9..84e7cf7019a 100644
--- 
a/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/distributionzones/ItIgniteDistributionZoneManagerNodeRestartTest.java
+++ 
b/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/distributionzones/ItIgniteDistributionZoneManagerNodeRestartTest.java
@@ -130,6 +130,7 @@ import 
org.apache.ignite.internal.testframework.ExecutorServiceExtension;
 import org.apache.ignite.internal.testframework.InjectExecutorService;
 import org.apache.ignite.internal.testframework.TestIgnitionManager;
 import org.apache.ignite.internal.vault.VaultManager;
+import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService;
 import org.apache.ignite.internal.version.DefaultIgniteProductVersionSource;
 import org.apache.ignite.internal.worker.fixtures.NoOpCriticalWorkerRegistry;
 import org.apache.ignite.network.NetworkAddress;
@@ -218,7 +219,7 @@ public class ItIgniteDistributionZoneManagerNodeRestartTest 
extends BaseIgniteRe
 
         var nodeCfgMgr = new ConfigurationManager(
                 modules.local().rootKeys(),
-                new LocalFileConfigurationStorage(configFile, 
localConfigurationGenerator, modules.local()),
+                new LocalFileConfigurationStorage(configFile, 
localConfigurationGenerator, new InMemoryVaultService(), modules.local()),
                 localConfigurationGenerator,
                 
ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, 
modules.local().validators())
         );
diff --git 
a/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/rebalance/ItRebalanceDistributedTest.java
 
b/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/rebalance/ItRebalanceDistributedTest.java
index 80f853be282..91ff99d20ea 100644
--- 
a/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/rebalance/ItRebalanceDistributedTest.java
+++ 
b/modules/distribution-zones/src/integrationTest/java/org/apache/ignite/internal/rebalance/ItRebalanceDistributedTest.java
@@ -270,6 +270,7 @@ import 
org.apache.ignite.internal.tx.storage.state.rocksdb.TxStateRocksDbSharedS
 import org.apache.ignite.internal.tx.storage.state.test.TestTxStateStorage;
 import org.apache.ignite.internal.tx.test.TestLocalRwTxCounter;
 import org.apache.ignite.internal.vault.VaultManager;
+import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService;
 import org.apache.ignite.internal.vault.persistence.PersistentVaultService;
 import org.apache.ignite.network.NetworkAddress;
 import 
org.apache.ignite.raft.jraft.rpc.CliRequests.ChangePeersAndLearnersAsyncRequest;
@@ -1296,7 +1297,7 @@ public class ItRebalanceDistributedTest extends 
BaseIgniteAbstractTest {
 
             nodeCfgMgr = new ConfigurationManager(
                     List.of(NodeConfiguration.KEY),
-                    new LocalFileConfigurationStorage(configPath, 
nodeCfgGenerator, null),
+                    new LocalFileConfigurationStorage(configPath, 
nodeCfgGenerator, new InMemoryVaultService(), null),
                     nodeCfgGenerator,
                     new TestConfigurationValidator()
             );
diff --git a/modules/partition-replicator/build.gradle 
b/modules/partition-replicator/build.gradle
index 5d725fa9611..8fd2503557f 100644
--- a/modules/partition-replicator/build.gradle
+++ b/modules/partition-replicator/build.gradle
@@ -71,6 +71,7 @@ dependencies {
     integrationTestImplementation testFixtures(project(':ignite-storage-api'))
     integrationTestImplementation testFixtures(project(':ignite-table'))
     integrationTestImplementation testFixtures(project(':ignite-transactions'))
+    integrationTestImplementation testFixtures(project(':ignite-vault'))
 
     integrationTestImplementation project(':ignite-raft')
     integrationTestImplementation project(':ignite-raft-api')
diff --git 
a/modules/partition-replicator/src/integrationTest/java/org/apache/ignite/internal/partition/replicator/fixtures/Node.java
 
b/modules/partition-replicator/src/integrationTest/java/org/apache/ignite/internal/partition/replicator/fixtures/Node.java
index e8c616a44dd..359e8296f40 100644
--- 
a/modules/partition-replicator/src/integrationTest/java/org/apache/ignite/internal/partition/replicator/fixtures/Node.java
+++ 
b/modules/partition-replicator/src/integrationTest/java/org/apache/ignite/internal/partition/replicator/fixtures/Node.java
@@ -195,6 +195,7 @@ import 
org.apache.ignite.internal.tx.storage.state.TxStateStorage;
 import 
org.apache.ignite.internal.tx.storage.state.rocksdb.TxStateRocksDbSharedStorage;
 import org.apache.ignite.internal.tx.test.TestLocalRwTxCounter;
 import org.apache.ignite.internal.vault.VaultManager;
+import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService;
 import org.apache.ignite.network.NetworkAddress;
 import org.apache.ignite.raft.jraft.rpc.impl.RaftGroupEventsClientListener;
 import org.apache.ignite.sql.IgniteSql;
@@ -370,7 +371,7 @@ public class Node {
 
         nodeCfgMgr = new ConfigurationManager(
                 List.of(NodeConfiguration.KEY),
-                new LocalFileConfigurationStorage(configPath, 
nodeCfgGenerator, null),
+                new LocalFileConfigurationStorage(configPath, 
nodeCfgGenerator, new InMemoryVaultService(), null),
                 nodeCfgGenerator,
                 new TestConfigurationValidator()
         );
diff --git a/modules/runner/build.gradle b/modules/runner/build.gradle
index b7edce5679a..0c88a8226f9 100644
--- a/modules/runner/build.gradle
+++ b/modules/runner/build.gradle
@@ -109,6 +109,8 @@ dependencies {
     testAnnotationProcessor 
project(':ignite-configuration-annotation-processor')
     testAnnotationProcessor libs.auto.service
 
+    defaultsGeneratorImplementation testFixtures(project(':ignite-vault'))
+
     testImplementation project(':ignite-cluster-management')
     testImplementation project(':ignite-configuration')
     testImplementation project(':ignite-core')
diff --git 
a/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java
 
b/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java
index 332e5575254..a3bfbec4c56 100644
--- 
a/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java
+++ 
b/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java
@@ -28,7 +28,7 @@ import org.apache.ignite.configuration.KeyIgnorer;
 import org.apache.ignite.configuration.RootKey;
 import org.apache.ignite.configuration.annotation.ConfigurationType;
 import org.apache.ignite.internal.configuration.ConfigurationChanger;
-import 
org.apache.ignite.internal.configuration.ConfigurationChanger.ConfigurationUpdateListener;
+import org.apache.ignite.internal.configuration.ConfigurationUpdateListener;
 import org.apache.ignite.internal.configuration.ConfigurationModules;
 import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator;
 import org.apache.ignite.internal.configuration.ServiceLoaderModulesProvider;
@@ -37,6 +37,8 @@ import 
org.apache.ignite.internal.configuration.storage.LocalFileConfigurationSt
 import org.apache.ignite.internal.configuration.tree.InnerNode;
 import 
org.apache.ignite.internal.configuration.validation.ConfigurationValidator;
 import 
org.apache.ignite.internal.configuration.validation.ConfigurationValidatorImpl;
+import org.apache.ignite.internal.vault.VaultManager;
+import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -89,7 +91,12 @@ public class DefaultsGenerator {
         );
 
         ConfigurationStorage storage = new LocalFileConfigurationStorage(
-                "defaultGen", configPath, localConfigurationGenerator, 
modules.local());
+                "defaultGen",
+                configPath,
+                localConfigurationGenerator,
+                new VaultManager(new InMemoryVaultService()),
+                modules.local()
+        );
 
         ConfigurationValidator configurationValidator =
                 
ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, 
modules.local().validators());
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItDistributedConfigurationStorageTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItDistributedConfigurationStorageTest.java
index 765daea938c..24c6bff6587 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItDistributedConfigurationStorageTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/configuration/storage/ItDistributedConfigurationStorageTest.java
@@ -341,9 +341,9 @@ public class ItDistributedConfigurationStorageTest extends 
BaseIgniteAbstractTes
 
             node2.waitWatches();
 
-            CompletableFuture<Data> storageData = 
node2.cfgStorage.readDataOnRecovery();
+            CompletableFuture<ReadEntry> storageData = 
node2.cfgStorage.readDataOnRecovery();
 
-            assertThat(storageData.thenApply(Data::values), 
willBe(equalTo(data)));
+            assertThat(storageData.thenApply(ReadEntry::values), 
willBe(equalTo(data)));
         } finally {
             node2.stop();
         }
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
index 6f3454d6d65..b3ea7d3f894 100644
--- 
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
@@ -236,6 +236,7 @@ import 
org.apache.ignite.internal.tx.test.TestLocalRwTxCounter;
 import org.apache.ignite.internal.util.ByteUtils;
 import org.apache.ignite.internal.util.Cursor;
 import org.apache.ignite.internal.vault.VaultManager;
+import org.apache.ignite.internal.vault.inmemory.InMemoryVaultService;
 import org.apache.ignite.internal.version.DefaultIgniteProductVersionSource;
 import org.apache.ignite.internal.worker.CriticalWorkerWatchdog;
 import 
org.apache.ignite.internal.worker.configuration.CriticalWorkersConfiguration;
@@ -373,7 +374,7 @@ public class ItIgniteNodeRestartTest extends 
BaseIgniteRestartTest {
 
         var nodeCfgMgr = new ConfigurationManager(
                 modules.local().rootKeys(),
-                new LocalFileConfigurationStorage(configFile, 
localConfigurationGenerator, modules.local()),
+                new LocalFileConfigurationStorage(configFile, 
localConfigurationGenerator, new InMemoryVaultService(), modules.local()),
                 localConfigurationGenerator,
                 
ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, 
modules.local().validators())
         );
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 f318532845d..db5c74b21e6 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
@@ -557,6 +557,7 @@ public class IgniteImpl implements Ignite {
                 name,
                 configPath,
                 localConfigurationGenerator,
+                vaultMgr,
                 modules.local()
         );
 

Reply via email to