You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by se...@apache.org on 2020/12/17 13:43:19 UTC

[ignite-3] branch main updated: IGNITE-13718 IgniteRunner application integrating configuration module and using it to configure REST API

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

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


The following commit(s) were added to refs/heads/main by this push:
     new edc458e  IGNITE-13718 IgniteRunner application integrating configuration module and using it to configure REST API
edc458e is described below

commit edc458ee886d40fb82d7ae3bce3adac92c8ef1da
Author: Sergey Chugunov <se...@gmail.com>
AuthorDate: Thu Dec 17 16:40:49 2020 +0300

    IGNITE-13718 IgniteRunner application integrating configuration module and using it to configure REST API
---
 modules/ignite-runner/pom.xml                      |  86 +++++++++++
 .../java/org/apache/ignite/app/IgniteRunner.java   | 101 +++++++++++++
 .../ignite/configuration/ConfigurationModule.java  |  82 +++++++++++
 .../extended/AutoAdjustConfigurationSchema.java    |  36 +++++
 .../extended/BaselineConfigurationSchema.java      |  29 ++++
 .../extended/DataStorageConfigurationSchema.java   |  37 +++++
 .../extended/LocalConfigurationSchema.java         |  39 +++++
 .../extended/RestConfigurationSchema.java          |  33 +++++
 .../presentation/FormatConverter.java              |  35 +++++
 .../presentation/json/JsonConverter.java           |  63 ++++++++
 .../java/org/apache/ignite/rest/ErrorResult.java   |  33 +++++
 .../java/org/apache/ignite/rest/RestModule.java    | 160 +++++++++++++++++++++
 .../org/apache/ignite/utils/IgniteProperties.java  |  75 ++++++++++
 .../src/main/resources/bootstrap-config.json       |   1 +
 .../src/main/resources/ignite.properties           |  18 +++
 .../src/main/resources/simplelogger.properties     |  19 +++
 pom.xml                                            |   1 +
 17 files changed, 848 insertions(+)

diff --git a/modules/ignite-runner/pom.xml b/modules/ignite-runner/pom.xml
new file mode 100644
index 0000000..b357f90
--- /dev/null
+++ b/modules/ignite-runner/pom.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.ignite</groupId>
+    <artifactId>ignite-runner</artifactId>
+    <version>3.0-SNAPSHOT</version>
+    <url>http://ignite.apache.org</url>
+
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-configuration</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.8.6</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.javalin</groupId>
+            <artifactId>javalin</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>1.7.30</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-configuration-annotation-processor</artifactId>
+            <version>${project.version}</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/app/IgniteRunner.java b/modules/ignite-runner/src/main/java/org/apache/ignite/app/IgniteRunner.java
new file mode 100644
index 0000000..ef197c1
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/app/IgniteRunner.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.app;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import org.apache.ignite.configuration.ConfigurationModule;
+import org.apache.ignite.rest.RestModule;
+import org.apache.ignite.utils.IgniteProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Sample application integrating new configuration module and providing standard REST API to access and modify it.
+ */
+public class IgniteRunner {
+    /** */
+    private static final String CONF_PARAM_NAME = "--config";
+
+    /** */
+    private static final String DFLT_CONF_FILE_NAME = "bootstrap-config.json";
+
+    /** */
+    private static final String VER_KEY = "version";
+
+    /** */
+    private final static Logger log = LoggerFactory.getLogger(IgniteRunner.class);
+
+    /**
+     * It is possible to start application with a custom configuration in form of json file other than that in resources.
+     *
+     * To make application pick up custom configuration file its full path should be passed to arguments after key "--config".
+     *
+     * @param args Empty or providing path to custom configuration file after marker parameter "--config".
+     */
+    public static void main(String[] args) throws IOException {
+        ackVersion();
+
+        ConfigurationModule confModule = new ConfigurationModule();
+
+        Reader confReader = null;
+
+        try {
+            if (args != null) {
+                for (int i = 0; i < args.length; i++) {
+                    if (CONF_PARAM_NAME.equals(args[i]) && i + 1 < args.length) {
+                        confReader = new FileReader(args[i + 1]);
+
+                        break;
+                    }
+                }
+            }
+
+            if (confReader == null) {
+                confReader = new InputStreamReader(
+                    IgniteRunner.class.getClassLoader().getResourceAsStream(DFLT_CONF_FILE_NAME));
+            }
+
+            confModule.bootstrap(confReader);
+        }
+        finally {
+            if (confReader != null)
+                confReader.close();
+        }
+
+        RestModule rest = new RestModule(confModule, log);
+
+        rest.start();
+
+        ackSuccessStart();
+    }
+
+    /** */
+    private static void ackSuccessStart() {
+        log.info("Ignite application started successfully");
+    }
+
+    /** */
+    private static void ackVersion() {
+        String ver = IgniteProperties.get(VER_KEY);
+
+        log.info("Starting Ignite of version " + ver);
+    }
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/ConfigurationModule.java b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/ConfigurationModule.java
new file mode 100644
index 0000000..c04f5bf
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/ConfigurationModule.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration;
+
+import java.io.Reader;
+import java.io.Serializable;
+import java.util.function.Consumer;
+
+import org.apache.ignite.configuration.extended.InitLocal;
+import org.apache.ignite.configuration.extended.LocalConfigurationImpl;
+import org.apache.ignite.configuration.extended.Selectors;
+import org.apache.ignite.configuration.presentation.FormatConverter;
+import org.apache.ignite.configuration.presentation.json.JsonConverter;
+import org.apache.ignite.configuration.storage.ConfigurationStorage;
+
+/**
+ * Module is responsible for preparing configuration when module is started.
+ *
+ * Preparing configuration includes reading it from configuration file, parsing it and initializing
+ * {@link Configurator} object.
+ */
+public class ConfigurationModule {
+    static {
+        try {
+            Selectors.LOCAL_BASELINE_AUTO_ADJUST_ENABLED.select(null);
+        }
+        catch (Throwable ignored) {
+            // No-op.
+        }
+    }
+
+    /** */
+    private final ConfigurationStorage storage = new ConfigurationStorage() {
+        /** {@inheritDoc} */
+        @Override public <T extends Serializable> void save(String propertyName, T object) {
+
+        }
+
+        /** {@inheritDoc} */
+        @Override public <T extends Serializable> T get(String propertyName) {
+            return null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public <T extends Serializable> void listen(String key, Consumer<T> listener) {
+
+        }
+    };
+
+    /** */
+    private Configurator<LocalConfigurationImpl> localConfigurator;
+
+    /** */
+    public void bootstrap(Reader confReader) {
+        FormatConverter converter = new JsonConverter();
+
+        Configurator<LocalConfigurationImpl> configurator =
+            Configurator.create(storage, LocalConfigurationImpl::new, converter.convertFrom(confReader, "local", InitLocal.class));
+
+        localConfigurator = configurator;
+    }
+
+    /** */
+    public Configurator<LocalConfigurationImpl> localConfigurator() {
+        return localConfigurator;
+    }
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/AutoAdjustConfigurationSchema.java b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/AutoAdjustConfigurationSchema.java
new file mode 100644
index 0000000..c0bfaca
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/AutoAdjustConfigurationSchema.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration.extended;
+
+
+import javax.validation.constraints.Min;
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.Value;
+
+/** */
+@Config(value = "auto_adjust")
+public class AutoAdjustConfigurationSchema {
+    /** */
+    @Value
+    private boolean enabled;
+
+    /** */
+    @Value
+    @Min(value = 0, message = "Minimum value is 0")
+    private int timeout;
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/BaselineConfigurationSchema.java b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/BaselineConfigurationSchema.java
new file mode 100644
index 0000000..930c67b
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/BaselineConfigurationSchema.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration.extended;
+
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.ConfigValue;
+
+/** */
+@Config
+public class BaselineConfigurationSchema {
+    /** */
+    @ConfigValue
+    private AutoAdjustConfigurationSchema autoAdjust;
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/DataStorageConfigurationSchema.java b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/DataStorageConfigurationSchema.java
new file mode 100644
index 0000000..b2a3a9a
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/DataStorageConfigurationSchema.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration.extended;
+
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.Value;
+
+/** */
+@Config
+public class DataStorageConfigurationSchema {
+    /** */
+    @Value
+    private int pageSize;
+
+    /** */
+    @Value
+    private String storagePath;
+
+    /** */
+    @Value
+    private String walPath;
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/LocalConfigurationSchema.java b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/LocalConfigurationSchema.java
new file mode 100644
index 0000000..60a1a9f
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/LocalConfigurationSchema.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration.extended;
+
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.ConfigValue;
+
+/**
+ *
+ */
+@Config(value = "local", root = true)
+public class LocalConfigurationSchema {
+    /** */
+    @ConfigValue
+    private RestConfigurationSchema rest;
+
+    /** */
+    @ConfigValue
+    private BaselineConfigurationSchema baseline;
+
+    /** */
+    @ConfigValue
+    private DataStorageConfigurationSchema dataStorage;
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/RestConfigurationSchema.java b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/RestConfigurationSchema.java
new file mode 100644
index 0000000..d25c61c
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/extended/RestConfigurationSchema.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration.extended;
+
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.Value;
+
+/** */
+@Config
+public class RestConfigurationSchema {
+    /** */
+    @Value
+    private int port;
+
+    /** */
+    @Value
+    private int portRange;
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/presentation/FormatConverter.java b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/presentation/FormatConverter.java
new file mode 100644
index 0000000..6bba4cf
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/presentation/FormatConverter.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration.presentation;
+
+import java.io.Reader;
+
+/** */
+public interface FormatConverter {
+    /** */
+    String convertTo(Object obj);
+
+    /** */
+    String convertTo(String rootName, Object obj);
+
+    /** */
+    <T> T convertFrom(String source, String rootName, Class<T> clazz);
+
+    /** */
+    <T> T convertFrom(Reader source, String rootName, Class<T> clazz);
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/presentation/json/JsonConverter.java b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/presentation/json/JsonConverter.java
new file mode 100644
index 0000000..5622e2f
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/configuration/presentation/json/JsonConverter.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration.presentation.json;
+
+import java.io.Reader;
+
+import com.google.gson.Gson;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.ignite.configuration.presentation.FormatConverter;
+
+/** */
+public class JsonConverter implements FormatConverter {
+    /** */
+    private final Gson gson = new Gson();
+
+    /** {@inheritDoc} */
+    @Override public String convertTo(Object obj) {
+        return gson.toJson(obj);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String convertTo(String rootName, Object src) {
+        Map<String, Object> res = new HashMap<>();
+
+        res.put(rootName, src);
+
+        return gson.toJson(res);
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T convertFrom(String source, String rootName, Class<T> clazz) {
+        Map map = gson.fromJson(source, Map.class);
+
+        String root = gson.toJson(map.get(rootName));
+
+        return gson.fromJson(root, clazz);
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T convertFrom(Reader source, String rootName, Class<T> clazz) {
+        Map map = gson.fromJson(source, Map.class);
+
+        String root = gson.toJson(map.get(rootName));
+
+        return gson.fromJson(root, clazz);
+    }
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/rest/ErrorResult.java b/modules/ignite-runner/src/main/java/org/apache/ignite/rest/ErrorResult.java
new file mode 100644
index 0000000..431f3d1
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/rest/ErrorResult.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.rest;
+
+/** */
+public class ErrorResult {
+    /** */
+    private final String type;
+
+    /** */
+    private final String message;
+
+    /** */
+    public ErrorResult(String type, String message) {
+        this.type = type;
+        this.message = message;
+    }
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/rest/RestModule.java b/modules/ignite-runner/src/main/java/org/apache/ignite/rest/RestModule.java
new file mode 100644
index 0000000..4ce35ed
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/rest/RestModule.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.rest;
+
+import com.google.gson.JsonSyntaxException;
+import io.javalin.Javalin;
+import org.apache.ignite.configuration.ConfigurationModule;
+import org.apache.ignite.configuration.Configurator;
+import org.apache.ignite.configuration.extended.ChangeLocal;
+import org.apache.ignite.configuration.extended.Local;
+import org.apache.ignite.configuration.extended.LocalConfigurationImpl;
+import org.apache.ignite.configuration.extended.Selectors;
+import org.apache.ignite.configuration.internal.selector.SelectorNotFoundException;
+import org.apache.ignite.configuration.presentation.FormatConverter;
+import org.apache.ignite.configuration.presentation.json.JsonConverter;
+import org.apache.ignite.configuration.validation.ConfigurationValidationException;
+import org.slf4j.Logger;
+
+/**
+ * Rest module is responsible for starting a REST endpoints for accessing and managing configuration.
+ *
+ * It is started on port 8080 by default but it is possible to change this in configuration itself.
+ * Refer to default config file in resources for the example.
+ */
+public class RestModule {
+    /** */
+    private static final int DFLT_PORT = 8080;
+
+    /** */
+    private static final String CONF_URL = "/management/v1/configuration/";
+
+    /** */
+    private static final String PATH_PARAM = "selector";
+
+    /** */
+    private final ConfigurationModule confModule;
+
+    /** */
+    private final Logger log;
+
+    /** */
+    public RestModule(ConfigurationModule confModule, Logger log) {
+        this.confModule = confModule;
+        this.log = log;
+    }
+
+    /** */
+    public void start() {
+        Configurator<LocalConfigurationImpl> configurator = confModule.localConfigurator();
+
+        Integer port = configurator.getPublic(Selectors.LOCAL_REST_PORT);
+        Integer portRange = configurator.getPublic(Selectors.LOCAL_REST_PORT_RANGE);
+        Javalin app = null;
+
+        if (portRange == null || portRange == 0) {
+            try {
+                app = Javalin.create().start(port != null ? port : DFLT_PORT);
+            }
+            catch (RuntimeException e) {
+                log.warn("Failed to start REST endpoint: ", e);
+
+                throw e;
+            }
+        }
+        else {
+            int startPort = port;
+
+            for (int portCandidate = startPort; portCandidate < startPort + portRange; portCandidate++) {
+                try {
+                    app = Javalin.create().start(portCandidate);
+                }
+                catch (RuntimeException ignored) {
+                    // No-op.
+                }
+
+                if (app != null)
+                    break;
+            }
+
+            if (app == null) {
+                String msg = "Cannot start REST endpoint. " +
+                    "All ports in range [" + startPort + ", " + (startPort + portRange) + ") are in use.";
+
+                log.warn(msg);
+
+                throw new RuntimeException(msg);
+            }
+        }
+
+        log.info("REST protocol started successfully on port " + app.port());
+
+        FormatConverter converter = new JsonConverter();
+
+        app.get(CONF_URL, ctx -> {
+            Local local = configurator.getRoot().value();
+
+            ctx.result(converter.convertTo("local", local));
+        });
+
+        app.get(CONF_URL + ":" + PATH_PARAM, ctx -> {
+            try {
+                Object subTree = configurator.getPublic(Selectors.find(ctx.pathParam(PATH_PARAM)));
+
+                String res = converter.convertTo(subTree);
+
+                ctx.result(res);
+            }
+            catch (SelectorNotFoundException selectorE) {
+                ErrorResult eRes = new ErrorResult("CONFIG_PATH_UNRECOGNIZED", selectorE.getMessage());
+
+                ctx.status(400).result(converter.convertTo("error", eRes));
+            }
+        });
+
+        app.post(CONF_URL, ctx -> {
+            try {
+                ChangeLocal local = converter.convertFrom(ctx.body(), "local", ChangeLocal.class);
+
+                configurator.set(Selectors.LOCAL, local);
+            }
+            catch (SelectorNotFoundException selectorE) {
+                ErrorResult eRes = new ErrorResult("CONFIG_PATH_UNRECOGNIZED", selectorE.getMessage());
+
+                ctx.status(400).result(converter.convertTo("error", eRes));
+            }
+            catch (ConfigurationValidationException validationE) {
+                ErrorResult eRes = new ErrorResult("APPLICATION_EXCEPTION", validationE.getMessage());
+
+                ctx.status(400).result(converter.convertTo("error", eRes));
+            }
+            catch (JsonSyntaxException e) {
+                String msg = e.getCause() != null ? e.getCause().getMessage() : e.getMessage();
+
+                ErrorResult eRes = new ErrorResult("VALIDATION_EXCEPTION", msg);
+
+                ctx.status(400).result(converter.convertTo("error", eRes));
+            }
+            catch (Exception e) {
+                ErrorResult eRes = new ErrorResult("VALIDATION_EXCEPTION", e.getMessage());
+
+                ctx.status(400).result(converter.convertTo("error", eRes));
+            }
+        });
+    }
+}
diff --git a/modules/ignite-runner/src/main/java/org/apache/ignite/utils/IgniteProperties.java b/modules/ignite-runner/src/main/java/org/apache/ignite/utils/IgniteProperties.java
new file mode 100644
index 0000000..4f6766c
--- /dev/null
+++ b/modules/ignite-runner/src/main/java/org/apache/ignite/utils/IgniteProperties.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Utility class to read Ignite properties from properties file.
+ */
+public class IgniteProperties {
+    /** Properties file path. */
+    private static final String FILE_PATH = "ignite.properties";
+
+    /** Properties. */
+    private static final Properties PROPS;
+
+    /** */
+    static {
+        PROPS = new Properties();
+
+        readProperties(FILE_PATH, PROPS, true);
+    }
+
+    /**
+     * @param path Path.
+     * @param props Properties.
+     * @param throwExc Flag indicating whether to throw an exception or not.
+     */
+    public static void readProperties(String path, Properties props, boolean throwExc) {
+        try (InputStream is = IgniteProperties.class.getClassLoader().getResourceAsStream(path)) {
+            if (is == null) {
+                if (throwExc)
+                    throw new RuntimeException("Failed to find properties file: " + path);
+                else
+                    return;
+            }
+
+            props.load(is);
+        }
+        catch (IOException e) {
+            throw new RuntimeException("Failed to read properties file: " + path, e);
+        }
+    }
+
+    /**
+     * Returns property value for a given key or {@code null} if nothing was found.
+     *
+     * @return Value or {@code null}.
+     */
+    public static String get(String key) {
+        return PROPS.getProperty(key, "");
+    }
+
+    /** */
+    private IgniteProperties() {
+        // No-op.
+    }
+}
diff --git a/modules/ignite-runner/src/main/resources/bootstrap-config.json b/modules/ignite-runner/src/main/resources/bootstrap-config.json
new file mode 100644
index 0000000..3b29984
--- /dev/null
+++ b/modules/ignite-runner/src/main/resources/bootstrap-config.json
@@ -0,0 +1 @@
+{"local":{"rest":{"port":8080,"portRange":100},"baseline":{"autoAdjust":{"timeout":10000,"enabled":true}},"dataStorage": {"pageSize":4096,"storagePath":"db/data","walPath":"db/wal"}}}
\ No newline at end of file
diff --git a/modules/ignite-runner/src/main/resources/ignite.properties b/modules/ignite-runner/src/main/resources/ignite.properties
new file mode 100644
index 0000000..4fe61e2
--- /dev/null
+++ b/modules/ignite-runner/src/main/resources/ignite.properties
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+version=${pom.version}
\ No newline at end of file
diff --git a/modules/ignite-runner/src/main/resources/simplelogger.properties b/modules/ignite-runner/src/main/resources/simplelogger.properties
new file mode 100644
index 0000000..4d52a62
--- /dev/null
+++ b/modules/ignite-runner/src/main/resources/simplelogger.properties
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.slf4j.simpleLogger.defaultLogLevel=off
+org.slf4j.simpleLogger.log.org.apache.ignite.app.IgniteRunner=info
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index a27e525..64f2265 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,5 +40,6 @@
     <modules>
         <module>modules/configuration</module>
         <module>modules/configuration-annotation-processor</module>
+        <module>modules/ignite-runner</module>
     </modules>
 </project>