This is an automated email from the ASF dual-hosted git repository. apkhmv 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 107e2c73bb IGNITE-19291 Generate default node configuration file at compile-time (#2357) 107e2c73bb is described below commit 107e2c73bb766f732effd0401c2608fae0c059b8 Author: Cyrill <cyrill.si...@gmail.com> AuthorDate: Fri Jul 28 12:43:47 2023 +0300 IGNITE-19291 Generate default node configuration file at compile-time (#2357) Now all distributions contains a node configuration file with all defaults set. --- modules/runner/build.gradle | 28 +++++ .../configuration/generator/DefaultsGenerator.java | 116 +++++++++++++++++++++ packaging/build.gradle | 4 +- packaging/db/build.gradle | 53 ++++++---- 4 files changed, 182 insertions(+), 19 deletions(-) diff --git a/modules/runner/build.gradle b/modules/runner/build.gradle index 830c2c03c2..e793f5cf0b 100644 --- a/modules/runner/build.gradle +++ b/modules/runner/build.gradle @@ -23,6 +23,23 @@ apply from: "$rootDir/buildscripts/java-integration-test.gradle" description = 'ignite-runner' +sourceSets { + defaultsGenerator { + compileClasspath += sourceSets.main.output + runtimeClasspath += sourceSets.main.output + } +} + +configurations { + defaultsGeneratorImplementation.extendsFrom implementation + defaultsGenerator { + canBeConsumed = true + canBeResolved = false + // this configuration will share the same dependencies as the main one + extendsFrom implementation, runtimeOnly + } +} + dependencies { annotationProcessor project(':ignite-configuration-annotation-processor') annotationProcessor libs.picocli.annotation.processor @@ -207,3 +224,14 @@ jar { ) } } + + +tasks.register('defaultsJar', Jar) { + from sourceSets.defaultsGenerator.output + archiveAppendix = "generator" +} + +artifacts { + // declare both jars to provide enough dependencies to the caller + defaultsGenerator defaultsJar, jar +} 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 new file mode 100644 index 0000000000..d17b08e1c4 --- /dev/null +++ b/modules/runner/src/defaultsGenerator/java/org/apache/ignite/internal/configuration/generator/DefaultsGenerator.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.configuration.generator; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.apache.ignite.configuration.ConfigurationModule; +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.ConfigurationModules; +import org.apache.ignite.internal.configuration.ConfigurationTreeGenerator; +import org.apache.ignite.internal.configuration.ServiceLoaderModulesProvider; +import org.apache.ignite.internal.configuration.storage.ConfigurationStorage; +import org.apache.ignite.internal.configuration.storage.LocalFileConfigurationStorage; +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.jetbrains.annotations.Nullable; + +/** + * A generator of the default local configuration file. + */ +public class DefaultsGenerator { + + /** + * Entry point to the config file generation. + * + * <p>The generator looks for all available configuration roots with type {@link ConfigurationType#LOCAL} in its own classpath, + * so please make sure the classpath is properly constructed. + * + * @param args The first element represents the path to the config file. + * If the file exists and is not empty, the stored configuration will be merged with the defaults. + * Please note: the file will be overwritten. + */ + public static void main(String[] args) { + if (args.length < 1) { + throw new IllegalArgumentException("Please provide the path to the config file as an argument"); + } + Path configPath = Paths.get(args[0]); + + ConfigurationChanger changer = null; + try { + changer = createConfigurationChanger(configPath); + changer.start(); + changer.onDefaultsPersisted().get(5, TimeUnit.SECONDS); + } catch (Exception e) { + throw new IllegalStateException("Failed to generate defaults file." + + "Please make sure that the classloader for loading services is correct."); + } finally { + if (changer != null) { + changer.stop(); + } + } + } + + /** + * This uses fragments of cluster initialization from {@code IgniteImpl} class to set up local configuration framework. + */ + private static ConfigurationChanger createConfigurationChanger(Path configPath) { + + ConfigurationModules modules = loadConfigurationModules(DefaultsGenerator.class.getClassLoader()); + + ConfigurationTreeGenerator localConfigurationGenerator = new ConfigurationTreeGenerator( + modules.local().rootKeys(), + modules.local().internalSchemaExtensions(), + modules.local().polymorphicSchemaExtensions() + ); + + ConfigurationStorage storage = new LocalFileConfigurationStorage(configPath, localConfigurationGenerator); + + ConfigurationValidator configurationValidator = + ConfigurationValidatorImpl.withDefaultValidators(localConfigurationGenerator, modules.local().validators()); + + ConfigurationUpdateListener empty = (oldRoot, newRoot, storageRevision, notificationNumber) -> + CompletableFuture.completedFuture(null); + + return new ConfigurationChanger(empty, modules.local().rootKeys(), storage, configurationValidator) { + @Override + public InnerNode createRootNode(RootKey<?, ?> rootKey) { + return localConfigurationGenerator.instantiateNode(rootKey.schemaClass()); + } + }; + } + + private static ConfigurationModules loadConfigurationModules(@Nullable ClassLoader classLoader) { + var modulesProvider = new ServiceLoaderModulesProvider(); + List<ConfigurationModule> modules = modulesProvider.modules(classLoader); + + if (modules.isEmpty()) { + throw new IllegalStateException("No configuration modules were loaded. " + + "Please make sure that the classloader for loading services is correct."); + } + + return new ConfigurationModules(modules); + } +} diff --git a/packaging/build.gradle b/packaging/build.gradle index 5efc65a272..17ac134c73 100644 --- a/packaging/build.gradle +++ b/packaging/build.gradle @@ -36,6 +36,7 @@ configurations { cliZip dbZip release + localDefaults } dependencies { @@ -47,6 +48,7 @@ dependencies { release project(path: ':packaging-db', configuration: 'dbRelease') release project(path: ':ignite-jdbc', configuration: 'jdbcRelease') release project(path: ':platforms', configuration: 'platformsRelease') + localDefaults project(path: ':packaging-db', configuration: 'localDefaults') } // Task that generates start script for cli @@ -99,7 +101,7 @@ docker { from "$rootDir/assembly/README.md" } into('etc') { - from 'config/ignite-config.conf' + from configurations.localDefaults from 'docker/ignite.java.util.logging.properties' } into('lib') { diff --git a/packaging/db/build.gradle b/packaging/db/build.gradle index d2df58d25f..eeee9c613c 100644 --- a/packaging/db/build.gradle +++ b/packaging/db/build.gradle @@ -34,10 +34,26 @@ import org.gradle.crypto.checksum.Checksum configurations { dbArtifacts + defaultsGenerator + dbZip { + canBeConsumed = true + canBeResolved = false + } + dbRelease { + canBeConsumed = true + canBeResolved = false + } + localDefaults { + canBeConsumed = true + canBeResolved = false + } } dependencies { - dbArtifacts(project(':ignite-runner')) + dbArtifacts project(':ignite-runner') + + defaultsGenerator configurations.dbArtifacts + defaultsGenerator project(path: ':ignite-runner', configuration: 'defaultsGenerator') } def tokens = [ @@ -71,6 +87,19 @@ task replaceZipScriptVars(type: Copy) { into "$buildDir/zip/" } +def copyConfig = tasks.register('copyConfig', Copy) { + from "$rootDir/packaging/config/ignite-config.conf" + into layout.buildDirectory.dir("config") +} + +def generateConfigDefaults = tasks.register('generateConfigDefaults', JavaExec) { + classpath = configurations.defaultsGenerator + mainClass = "org.apache.ignite.internal.configuration.generator.DefaultsGenerator" + dependsOn copyConfig + args layout.buildDirectory.file("config/ignite-config.conf").get() + outputs.file layout.buildDirectory.file("config/ignite-config.conf") +} + distributions { main { distributionBaseName = 'ignite3-db' @@ -91,7 +120,7 @@ distributions { } into('etc') { from "$buildDir/zip/${zipStartScriptTokens.VARS_FILE_NAME}" - from "$rootDir/packaging/config/ignite-config.conf" + from generateConfigDefaults from "$buildDir/zip/ignite.java.util.logging.properties" } into('bin') { @@ -117,16 +146,9 @@ task createChecksums(type: Checksum) { checksumAlgorithm = Checksum.Algorithm.SHA512 } -// Expose zip artifacts to be consumed by others -configurations { - dbZip { - canBeConsumed = true - canBeResolved = false - } -} - artifacts { dbZip(distZip) + localDefaults generateConfigDefaults } // Explicitly create task so that the resulting artifact is not added to the configuration @@ -213,7 +235,7 @@ ospackage { fileType CONFIG from "$buildDir/linux/service/vars.env" from "$buildDir/linux/ignite.java.util.logging.properties" - from "$rootDir/packaging/config/ignite-config.conf" + from generateConfigDefaults } into('etc') { @@ -224,12 +246,7 @@ ospackage { link "/opt/ignite3db", "${packageTokens.INSTALL_DIR}" } -configurations { - dbRelease { - canBeConsumed = true - canBeResolved = false - } -} + if (project.hasProperty('prepareRelease')) { artifacts { @@ -292,7 +309,7 @@ setupBuilder { from('log') } into('etc') { - from "${rootDir}/packaging/config/ignite-config.conf" + from generateConfigDefaults } into('etc') { from("ignite.java.util.logging.properties")