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

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

commit e16e4e2a62b7aec52dd83921ac24e9404d4886d5
Author: Pochatkin Mikhail <[email protected]>
AuthorDate: Thu Aug 7 17:08:40 2025 +0300

    POC
---
 .../storage/LocalFileConfigurationStorage.java     | 23 ++++-----
 ...Storage.java => VaultConfigurationStorage.java} | 11 ++--
 .../storage/LocalConfigurationStorageTest.java     |  4 +-
 .../storage/LocalConfigurationStorage.java         | 14 ++++++
 .../configuration/NodeConfigurationController.java | 17 ++++++-
 .../main/java/org/apache/ignite/IgniteServer.java  | 21 ++++++--
 .../main/java/org/apache/ignite/NodeConfig.java    | 18 +++++++
 .../org/apache/ignite/internal/app/IgniteImpl.java | 26 +++++-----
 .../apache/ignite/internal/app/IgniteRunner.java   | 34 +++++++++++--
 .../ignite/internal/app/IgniteServerImpl.java      | 17 +++----
 .../internal/app/config/BootstrapNodeConfig.java   | 34 +++++++++++++
 .../app/config/ConfigurationStorageFactory.java    | 58 ++++++++++++++++++++++
 .../ignite/internal/app/config/FileNodeConfig.java | 42 ++++++++++++++++
 .../internal/app/config/NodeConfigFactory.java     | 34 +++++++++++++
 .../internal/app/config/NodeConfigVisitor.java     | 16 ++++++
 15 files changed, 320 insertions(+), 49 deletions(-)

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 72e80d74954..a4fc0197be2 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
@@ -79,7 +79,7 @@ import org.jetbrains.annotations.TestOnly;
 /**
  * Implementation of {@link ConfigurationStorage} based on local file 
configuration storage.
  */
-public class LocalFileConfigurationStorage implements ConfigurationStorage {
+public class LocalFileConfigurationStorage implements 
LocalConfigurationStorage {
     private static final IgniteLogger LOG = 
Loggers.forClass(LocalFileConfigurationStorage.class);
 
     /** Path to config file. */
@@ -132,7 +132,11 @@ 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,
+            @Nullable ConfigurationModule module
+    ) {
         this.configPath = configPath;
         this.generator = generator;
         this.tempConfigPath = 
configPath.resolveSibling(configPath.getFileName() + ".tmp");
@@ -299,16 +303,6 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
     }
 
     private void saveConfigFile() {
-        if (!Files.isWritable(configPath)) {
-            NodeConfigWriteException e = new NodeConfigWriteException(
-                    "The configuration file is read-only, so changes cannot be 
applied. "
-                            + "Check your system configuration. "
-                            + "If you are using containerization, such as 
Kubernetes, "
-                            + "the file can only be modified through native 
Kubernetes methods."
-            );
-            LOG.warn("The config file " + configPath + " is not writable", e);
-            throw e;
-        }
         try {
             Files.write(
                     tempConfigPath,
@@ -392,4 +386,9 @@ public class LocalFileConfigurationStorage implements 
ConfigurationStorage {
 
         futureTracker.registerFuture(future);
     }
+
+    @Override
+    public boolean userModificationsAllowed() {
+        return true;
+    }
 }
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 96%
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..a8afb8cdf21 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 LocalConfigurationStorage {
     /** 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,11 +89,16 @@ 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));
     }
 
+    @Override
+    public boolean userModificationsAllowed() {
+        return false;
+    }
+
     @Override
     public void close() {
         IgniteUtils.shutdownAndAwaitTermination(threadPool, 10, 
TimeUnit.SECONDS);
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/LocalConfigurationStorageTest.java
index e68e597ac21..688286684a3 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/LocalConfigurationStorageTest.java
@@ -27,7 +27,7 @@ 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 {
     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/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java
 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java
new file mode 100644
index 00000000000..3df7fc53c3a
--- /dev/null
+++ 
b/modules/configuration/src/main/java/org/apache/ignite/internal/configuration/storage/LocalConfigurationStorage.java
@@ -0,0 +1,14 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.internal.configuration.storage;
+
+public interface LocalConfigurationStorage extends ConfigurationStorage {
+    boolean userModificationsAllowed();
+}
diff --git 
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/configuration/NodeConfigurationController.java
 
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/configuration/NodeConfigurationController.java
index 85203d4a23a..7a5634a095b 100644
--- 
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/configuration/NodeConfigurationController.java
+++ 
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/configuration/NodeConfigurationController.java
@@ -21,7 +21,9 @@ import io.micronaut.context.annotation.Requires;
 import io.micronaut.http.annotation.Controller;
 import jakarta.inject.Named;
 import java.util.concurrent.CompletableFuture;
+import org.apache.ignite.internal.configuration.NodeConfigWriteException;
 import 
org.apache.ignite.internal.configuration.presentation.ConfigurationPresentation;
+import 
org.apache.ignite.internal.configuration.storage.LocalConfigurationStorage;
 import org.apache.ignite.internal.rest.api.configuration.NodeConfigurationApi;
 import 
org.apache.ignite.internal.rest.exception.handler.IgniteExceptionHandler;
 
@@ -31,9 +33,14 @@ import 
org.apache.ignite.internal.rest.exception.handler.IgniteExceptionHandler;
 @Controller("/management/v1/configuration/node")
 @Requires(classes = IgniteExceptionHandler.class)
 public class NodeConfigurationController extends 
AbstractConfigurationController implements NodeConfigurationApi {
+    private final LocalConfigurationStorage localConfigurationStorage;
 
-    public NodeConfigurationController(@Named("nodeCfgPresentation") 
ConfigurationPresentation<String> nodeCfgPresentation) {
+    public NodeConfigurationController(
+            @Named("nodeCfgPresentation") ConfigurationPresentation<String> 
nodeCfgPresentation,
+            LocalConfigurationStorage localConfigurationStorage
+    ) {
         super(nodeCfgPresentation);
+        this.localConfigurationStorage = localConfigurationStorage;
     }
 
     /**
@@ -64,6 +71,14 @@ public class NodeConfigurationController extends 
AbstractConfigurationController
      */
     @Override
     public CompletableFuture<Void> updateConfiguration(String 
updatedConfiguration) {
+        if (!localConfigurationStorage.userModificationsAllowed()) {
+            throw new NodeConfigWriteException(
+                    "The configuration file is read-only, so changes cannot be 
applied. "
+                            + "Check your system configuration. "
+                            + "If you are using containerization, such as 
Kubernetes, "
+                            + "the file can only be modified through native 
Kubernetes methods."
+            );
+        }
         return super.updateConfiguration(updatedConfiguration);
     }
 }
diff --git a/modules/runner/src/main/java/org/apache/ignite/IgniteServer.java 
b/modules/runner/src/main/java/org/apache/ignite/IgniteServer.java
index c7098d822af..0ee21aa549e 100644
--- a/modules/runner/src/main/java/org/apache/ignite/IgniteServer.java
+++ b/modules/runner/src/main/java/org/apache/ignite/IgniteServer.java
@@ -22,6 +22,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ForkJoinPool;
 import org.apache.ignite.internal.app.IgniteServerImpl;
+import org.apache.ignite.internal.app.config.NodeConfigFactory;
 import org.apache.ignite.lang.IgniteException;
 import org.jetbrains.annotations.Nullable;
 
@@ -78,6 +79,12 @@ public interface IgniteServer {
         return server;
     }
 
+    static IgniteServer start(String nodeName, NodeConfig nodeConfig, Path 
workDir) {
+        IgniteServer server = builder(nodeName, nodeConfig, workDir).build();
+        server.start();
+        return server;
+    }
+
     /**
      * Starts the node.
      *
@@ -97,7 +104,11 @@ public interface IgniteServer {
      * @return Node instance.
      */
     static Builder builder(String nodeName, Path configPath, Path workDir) {
-        return new Builder(nodeName, configPath, workDir);
+        return new Builder(nodeName, NodeConfigFactory.fromFile(configPath), 
workDir);
+    }
+
+    static Builder builder(String nodeName, NodeConfig nodeConfig, Path 
workDir) {
+        return new Builder(nodeName, nodeConfig, workDir);
     }
 
     /**
@@ -187,15 +198,15 @@ public interface IgniteServer {
      */
     final class Builder {
         private final String nodeName;
-        private final Path configPath;
+        private final NodeConfig nodeConfig;
         private final Path workDir;
 
         private @Nullable ClassLoader serviceLoaderClassLoader;
         private Executor asyncContinuationExecutor = ForkJoinPool.commonPool();
 
-        private Builder(String nodeName, Path configPath, Path workDir) {
+        private Builder(String nodeName, NodeConfig nodeConfig, Path workDir) {
             this.nodeName = nodeName;
-            this.configPath = configPath;
+            this.nodeConfig = nodeConfig;
             this.workDir = workDir;
         }
 
@@ -230,7 +241,7 @@ public interface IgniteServer {
         public IgniteServer build() {
             return new IgniteServerImpl(
                     nodeName,
-                    configPath,
+                    nodeConfig,
                     workDir,
                     serviceLoaderClassLoader,
                     asyncContinuationExecutor
diff --git a/modules/runner/src/main/java/org/apache/ignite/NodeConfig.java 
b/modules/runner/src/main/java/org/apache/ignite/NodeConfig.java
new file mode 100644
index 00000000000..4e83c7214a0
--- /dev/null
+++ b/modules/runner/src/main/java/org/apache/ignite/NodeConfig.java
@@ -0,0 +1,18 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite;
+
+import org.apache.ignite.internal.app.config.NodeConfigVisitor;
+
+public interface NodeConfig {
+    String initialContent();
+
+    <T> T visit(NodeConfigVisitor<T> visitor);
+}
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 b6b85b277bb..5c20b7653fe 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
@@ -57,6 +57,7 @@ import java.util.function.LongSupplier;
 import java.util.function.Supplier;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteServer;
+import org.apache.ignite.NodeConfig;
 import org.apache.ignite.catalog.IgniteCatalog;
 import org.apache.ignite.client.handler.ClientHandlerMetricSource;
 import org.apache.ignite.client.handler.ClientHandlerModule;
@@ -68,6 +69,7 @@ import org.apache.ignite.compute.IgniteCompute;
 import org.apache.ignite.configuration.ConfigurationDynamicDefaultsPatcher;
 import org.apache.ignite.configuration.ConfigurationModule;
 import org.apache.ignite.configuration.KeyIgnorer;
+import org.apache.ignite.internal.app.config.ConfigurationStorageFactory;
 import org.apache.ignite.internal.catalog.CatalogManager;
 import org.apache.ignite.internal.catalog.CatalogManagerImpl;
 import org.apache.ignite.internal.catalog.compaction.CatalogCompactionRunner;
@@ -117,9 +119,10 @@ import 
org.apache.ignite.internal.configuration.SystemDistributedExtensionConfig
 import org.apache.ignite.internal.configuration.SystemLocalConfiguration;
 import 
org.apache.ignite.internal.configuration.SystemLocalExtensionConfiguration;
 import org.apache.ignite.internal.configuration.hocon.HoconConverter;
+import org.apache.ignite.internal.configuration.presentation.HoconPresentation;
 import org.apache.ignite.internal.configuration.storage.ConfigurationStorage;
 import 
org.apache.ignite.internal.configuration.storage.DistributedConfigurationStorage;
-import 
org.apache.ignite.internal.configuration.storage.LocalFileConfigurationStorage;
+import 
org.apache.ignite.internal.configuration.storage.LocalConfigurationStorage;
 import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
 import 
org.apache.ignite.internal.configuration.validation.ConfigurationValidator;
 import 
org.apache.ignite.internal.configuration.validation.ConfigurationValidatorImpl;
@@ -513,7 +516,7 @@ public class IgniteImpl implements Ignite {
      * The Constructor.
      *
      * @param node Embedded node.
-     * @param configPath Path to node configuration in the HOCON format.
+     * @param nodeConfig Path to node configuration in the HOCON format.
      * @param workDir Work directory for the started node. Must not be {@code 
null}.
      * @param serviceProviderClassLoader The class loader to be used to load 
provider-configuration files and provider classes, or
      *         {@code null} if the system class loader (or, failing that the 
bootstrap class loader) is to be used.
@@ -522,7 +525,7 @@ public class IgniteImpl implements Ignite {
     IgniteImpl(
             IgniteServer node,
             ServerRestarter restarter,
-            Path configPath,
+            NodeConfig nodeConfig,
             Path workDir,
             @Nullable ClassLoader serviceProviderClassLoader,
             Executor asyncContinuationExecutor
@@ -550,19 +553,16 @@ public class IgniteImpl implements Ignite {
                 modules.local().polymorphicSchemaExtensions()
         );
 
-        LocalFileConfigurationStorage localFileConfigurationStorage = new 
LocalFileConfigurationStorage(
-                name,
-                configPath,
-                localConfigurationGenerator,
-                modules.local()
-        );
+        ConfigurationStorageFactory storageFactory = new 
ConfigurationStorageFactory(name, localConfigurationGenerator, vaultMgr, 
modules);
+
+        LocalConfigurationStorage localConfigurationStorage = 
nodeConfig.visit(storageFactory);
 
         ConfigurationValidator localConfigurationValidator =
                 
ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, 
modules.local().validators());
 
         nodeCfgMgr = new ConfigurationManager(
                 modules.local().rootKeys(),
-                localFileConfigurationStorage,
+                localConfigurationStorage,
                 localConfigurationGenerator,
                 localConfigurationValidator,
                 modules.local()::migrateDeprecatedConfigurations,
@@ -573,13 +573,15 @@ public class IgniteImpl implements Ignite {
         try {
             lifecycleManager.startComponentsAsync(new ComponentContext(), 
nodeCfgMgr);
         } catch (NodeStoppingException e) {
-            throw new AssertionError(String.format("Unexpected exception: 
[nodeName=%s, configPath=%s]", name, configPath), e);
+            throw new AssertionError(String.format("Unexpected exception: 
[nodeName=%s, configPath=%s]", name, nodeConfig), e);
         }
 
-        LOG.info("Starting node: [name={}, workDir={}, configPath={}]", name, 
workDir, configPath);
+        LOG.info("Starting node: [name={}, workDir={}, configPath={}]", name, 
workDir, nodeConfig);
 
         ConfigurationRegistry nodeConfigRegistry = 
nodeCfgMgr.configurationRegistry();
 
+        new 
HoconPresentation(nodeConfigRegistry).update(nodeConfig.initialContent());
+
         LOG.info("Local node configuration: {}", 
convertToHoconString(nodeConfigRegistry));
 
         NetworkConfiguration networkConfiguration = 
nodeConfigRegistry.getConfiguration(NetworkExtensionConfiguration.KEY).network();
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteRunner.java 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteRunner.java
index 9a99cdfdd44..12860bd5b1a 100644
--- 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteRunner.java
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteRunner.java
@@ -24,19 +24,23 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import jdk.internal.misc.Signal;
 import jdk.internal.misc.Signal.Handler;
 import org.apache.ignite.IgniteServer;
+import org.apache.ignite.NodeConfig;
+import org.apache.ignite.internal.app.config.NodeConfigFactory;
 import picocli.CommandLine;
+import picocli.CommandLine.ArgGroup;
 import picocli.CommandLine.Command;
 import picocli.CommandLine.Option;
 
 /**
  * The main entry point for running new Ignite node. Command-line arguments 
can be provided using environment variables
- * {@code IGNITE_CONFIG_PATH}, {@code IGNITE_WORK_DIR} and {@code 
IGNITE_NODE_NAME} for {@code --config-path}, {@code --work-dir} and
+ * //TODO {@code IGNITE_CONFIG_PATH},
+ * {@code IGNITE_WORK_DIR} and {@code IGNITE_NODE_NAME} for {@code 
--config-path}, {@code --work-dir} and
  * {@code --node-name} command line arguments respectively.
  */
 @Command(name = "runner")
 public class IgniteRunner implements Callable<IgniteServer> {
-    @Option(names = "--config-path", description = "Path to node configuration 
file in HOCON format.", required = true)
-    private Path configPath;
+    @ArgGroup(multiplicity = "1")
+    private ConfigOption config;
 
     @Option(names = "--work-dir", description = "Path to node working 
directory.", required = true)
     private Path workDir;
@@ -46,7 +50,29 @@ public class IgniteRunner implements Callable<IgniteServer> {
 
     @Override
     public IgniteServer call() throws Exception {
-        return IgniteServer.start(nodeName, configPath.toAbsolutePath(), 
workDir);
+        return IgniteServer.start(nodeName, config.configPath(), workDir);
+    }
+
+    private static class ConfigOption {
+        /**
+         * Node URL option.
+         */
+        @Option(names = "--config-path", description = "Path to node 
configuration file in HOCON format.", required = true)
+        private Path configPath;
+
+        /**
+         * Node name option.
+         */
+        @Option(names = "--bootstrap-config", description = "Node bootstrap 
configuration in HOCON format.", required = true)
+        private String bootstrapConfig;
+
+        public NodeConfig configPath() {
+            if (configPath != null) {
+                return NodeConfigFactory.fromFile(configPath);
+            }
+
+            return NodeConfigFactory.fromBootstrap(bootstrapConfig);
+        }
     }
 
     /**
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteServerImpl.java
 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteServerImpl.java
index 264fe726a90..4d84efe624a 100644
--- 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteServerImpl.java
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteServerImpl.java
@@ -30,7 +30,6 @@ import static 
org.apache.ignite.lang.ErrorGroups.Common.INTERNAL_ERR;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -39,6 +38,7 @@ import java.util.function.Supplier;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteServer;
 import org.apache.ignite.InitParameters;
+import org.apache.ignite.NodeConfig;
 import org.apache.ignite.internal.eventlog.api.IgniteEventType;
 import org.apache.ignite.internal.lang.IgniteStringFormatter;
 import org.apache.ignite.internal.lang.NodeStoppingException;
@@ -87,7 +87,7 @@ public class IgniteServerImpl implements IgniteServer {
 
     private final String nodeName;
 
-    private final Path configPath;
+    private final NodeConfig nodeConfig;
 
     private final Path workDir;
 
@@ -145,7 +145,7 @@ public class IgniteServerImpl implements IgniteServer {
      */
     public IgniteServerImpl(
             String nodeName,
-            Path configPath,
+            NodeConfig nodeConfig,
             Path workDir,
             @Nullable ClassLoader classLoader,
             Executor asyncContinuationExecutor
@@ -156,11 +156,8 @@ public class IgniteServerImpl implements IgniteServer {
         if (nodeName.isEmpty()) {
             throw new NodeStartException("Node name must not be empty.");
         }
-        if (configPath == null) {
-            throw new NodeStartException("Config path must not be null");
-        }
-        if (Files.notExists(configPath)) {
-            throw new NodeStartException("Config file doesn't exist");
+        if (nodeConfig == null) {
+            throw new NodeStartException("Node config must not be null");
         }
         if (workDir == null) {
             throw new NodeStartException("Working directory must not be null");
@@ -170,7 +167,7 @@ public class IgniteServerImpl implements IgniteServer {
         }
 
         this.nodeName = nodeName;
-        this.configPath = configPath;
+        this.nodeConfig = nodeConfig;
         this.workDir = workDir;
         this.classLoader = classLoader;
         this.asyncContinuationExecutor = asyncContinuationExecutor;
@@ -389,7 +386,7 @@ public class IgniteServerImpl implements IgniteServer {
             return failedFuture(new NodeNotStartedException());
         }
 
-        IgniteImpl instance = new IgniteImpl(this, this::restartAsync, 
configPath, workDir, classLoader, asyncContinuationExecutor);
+        IgniteImpl instance = new IgniteImpl(this, this::restartAsync, 
nodeConfig, workDir, classLoader, asyncContinuationExecutor);
 
         ackBanner();
 
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/config/BootstrapNodeConfig.java
 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/BootstrapNodeConfig.java
new file mode 100644
index 00000000000..015ecacffcb
--- /dev/null
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/BootstrapNodeConfig.java
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.internal.app.config;
+
+import org.apache.ignite.NodeConfig;
+
+public class BootstrapNodeConfig implements NodeConfig {
+    private final String nodeConfig;
+
+    public BootstrapNodeConfig(String nodeConfig) {
+        this.nodeConfig = nodeConfig;
+    }
+
+    public String nodeConfig() {
+        return nodeConfig;
+    }
+
+    @Override
+    public String initialContent() {
+        return nodeConfig;
+    }
+
+    @Override
+    public <T> T visit(NodeConfigVisitor<T> visitor) {
+        return visitor.visitBootstrapConfig(this);
+    }
+}
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/config/ConfigurationStorageFactory.java
 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/ConfigurationStorageFactory.java
new file mode 100644
index 00000000000..f64a44ec8e0
--- /dev/null
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/ConfigurationStorageFactory.java
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.internal.app.config;
+
+import org.apache.ignite.NodeConfig;
+import org.apache.ignite.internal.configuration.ConfigurationModules;
+import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator;
+import 
org.apache.ignite.internal.configuration.storage.LocalConfigurationStorage;
+import 
org.apache.ignite.internal.configuration.storage.VaultConfigurationStorage;
+import 
org.apache.ignite.internal.configuration.storage.LocalFileConfigurationStorage;
+import org.apache.ignite.internal.vault.VaultManager;
+
+public class ConfigurationStorageFactory implements 
NodeConfigVisitor<LocalConfigurationStorage> {
+    private final String nodeName;
+
+    private final ConfigurationTreeGenerator localConfigurationGenerator;
+
+    private final VaultManager vaultManager;
+
+    private final ConfigurationModules modules;
+
+    public ConfigurationStorageFactory(
+            String nodeName,
+            ConfigurationTreeGenerator localConfigurationGenerator,
+            VaultManager vaultManager,
+            ConfigurationModules modules
+    ) {
+        this.nodeName = nodeName;
+        this.localConfigurationGenerator = localConfigurationGenerator;
+        this.vaultManager = vaultManager;
+        this.modules = modules;
+    }
+
+    @Override
+    public LocalConfigurationStorage visitFileConfig(FileNodeConfig 
fileNodeConfig) {
+        return new LocalFileConfigurationStorage(
+                nodeName,
+                fileNodeConfig.configPath(),
+                localConfigurationGenerator,
+                modules.local()
+        );
+    }
+
+    @Override
+    public LocalConfigurationStorage visitBootstrapConfig(BootstrapNodeConfig 
bootstrapNodeConfig) {
+        return new VaultConfigurationStorage(
+                nodeName,
+                vaultManager
+        );
+    }
+}
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/config/FileNodeConfig.java
 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/FileNodeConfig.java
new file mode 100644
index 00000000000..331c6b37ae4
--- /dev/null
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/FileNodeConfig.java
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.internal.app.config;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.ignite.NodeConfig;
+import org.apache.ignite.internal.configuration.NodeConfigParseException;
+
+public class FileNodeConfig implements NodeConfig {
+    private final Path configPath;
+
+    public FileNodeConfig(Path configPath) {
+        this.configPath = configPath;
+    }
+
+    public Path configPath() {
+        return configPath;
+    }
+
+    @Override
+    public String initialContent() {
+        try {
+            return Files.readString(configPath);
+        } catch (IOException e) {
+            throw new NodeConfigParseException("Failed to read configuration 
file: " + configPath, e);
+        }
+    }
+
+    @Override
+    public <T> T visit(NodeConfigVisitor<T> visitor) {
+        return visitor.visitFileConfig(this);
+    }
+}
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/config/NodeConfigFactory.java
 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/NodeConfigFactory.java
new file mode 100644
index 00000000000..e72fbdce2e2
--- /dev/null
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/NodeConfigFactory.java
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.internal.app.config;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.ignite.NodeConfig;
+import org.apache.ignite.internal.configuration.NodeConfigWriteException;
+
+public class NodeConfigFactory {
+    public static NodeConfig fromFile(Path configPath) {
+        if (!Files.isWritable(configPath)) {
+            throw new NodeConfigWriteException(
+                    "The configuration file is read-only, so changes cannot be 
applied. "
+                            + "Check your system configuration. "
+                            + "If you are using containerization, such as 
Kubernetes, "
+                            + "the file can only be modified through native 
Kubernetes methods."
+            );
+        }
+        return new FileNodeConfig(configPath);
+    }
+
+    public static NodeConfig fromBootstrap(String nodeConfig) {
+
+        return new BootstrapNodeConfig(nodeConfig);
+    }
+}
diff --git 
a/modules/runner/src/main/java/org/apache/ignite/internal/app/config/NodeConfigVisitor.java
 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/NodeConfigVisitor.java
new file mode 100644
index 00000000000..8cc1a979662
--- /dev/null
+++ 
b/modules/runner/src/main/java/org/apache/ignite/internal/app/config/NodeConfigVisitor.java
@@ -0,0 +1,16 @@
+/*
+ *  Copyright (C) GridGain Systems. All Rights Reserved.
+ *  _________        _____ __________________        _____
+ *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
+ *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
+ *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
+ *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
+ */
+
+package org.apache.ignite.internal.app.config;
+
+public interface NodeConfigVisitor<T> {
+    T visitFileConfig(FileNodeConfig fileNodeConfig);
+
+    T visitBootstrapConfig(BootstrapNodeConfig bootstrapNodeConfig);
+}


Reply via email to