Wednesday, April 13, 2022

[SOLVED] Externalized configuration for rpm

Issue

INTRO:

This question is fairly similar to href="https://stackoverflow.com/questions/23427745/how-to-put-a-directory-first-on-the-classpath-with-spring-boot">How to put a directory first on the classpath with Spring Boot? and I've searched around a bit but unfortunately nothing worked so far. Neither changing to packaging=ZIP in the spring-boot-maven-plugin nor using loader.path as explained in boot features external config or how to - properties and configuration, so I must be missing something. One more thing, if possible I would like to avoid passing each and every configuration file as an argument with file://....


I have an application which originally was a simulator for several types of services: sftp, soap, etc. Initially it supported 1 instance of each server type configurable through a properties file.

I've now updated it to support multiple server instances on separate ports, and the configuration is done in a YAML file, and I've also migrated from classic spring to boot. Finally the application is delivered as an RPM, which has the following structure

installation-dir
    |--bin
    |    '-- simulator.sh [lifecycle management script]
    |--config
    |    |--application.properties
    |    |--log4j2.xml
    |    |--samples       [sample files for various operations]
    |    |    |-- sample1.csv
    |    |    |-- sample2.csv
    |    |    '-- sample3.csv
    |    |--simulators.yaml [simulators config]
    |    '--simulator.jks
    |--lib
    |    '-- simulator-1.0.jar
    '--log
         '-- simulator.log

Before, simulators.sh launched the main class adding the config dir to the classpath, and spring would load the properties file without any issue:

java <other args> -cp "..." com.whatever.SimulatorLauncher

Since the migration, it now launches the generated jar, so the -cp is no longer used, and I'm having trouble making it pick up the configuration files:

java <other args> lib/simulator-1.0.jar

Ignoring for a bit the fact that it does not find aplication.properties, the simulators' config is loaded as below:

@Configuration
@ConfigurationProperties(locations = {"classpath:/simulators.yml"}, ignoreUnknownFields = false, prefix = "simulators")
public class SimulatorSettings {
    private static final Logger log = LoggerFactory.getLogger(SimulatorSettings.class);

    @NotNull
    private List<SftpSettings> sftp;

    @NotNull
    private List<SoapSettings> soap;

Since the config should be updateable without having to repackage the application, all of the files are excluded from the resulting jar, but packaged in the rpm under config:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <excludes>
                    <!-- these files will be included in the rpm under config -->
                    <exclude>application.properties</exclude>
                    <exclude>log4j2.xml</exclude>
                    <exclude>samples/**</exclude>
                    <exclude>simulators.yml</exclude>
                    <exclude>simulator.jks</exclude>
                </excludes>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <mainClass>com.whatever.SimulatorLauncher</mainClass>
                <layout>ZIP</layout>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>rpm-maven-plugin</artifactId>
            <version>2.1.5</version>
            ...
            <configuration>
            ...
                    <mapping>
                        <directory>${rpm.app.home}/config</directory>
                        <sources>
                            <source>
                                <location>src/main/resources</location>
                                <includes>
                                    <include>application.properties</include>
                                    <include>simulators.yml</include>
                                    <include>log4j2.xml</include>
                                    <include>nls-sim.jks</include>
                                </includes>
                            </source>
                        </sources>
                        <filemode>755</filemode>
                    </mapping>

Any help or hints are greatly appreciated.


Solution

I ended up removing the spring-boot-maven-plugin to prevent repackaging, and created the RPM with my artefact & its dependencies and launching the application like before:

java <other args> -cp "<installation dir>/config:...:<libs>" com.whatever.SimulatorLauncher

Still, I'd be interested to find out if anybody knows a way of doing it with a spring boot repackaged jar...



Answered By - Morfic
Answer Checked By - David Marino (WPSolving Volunteer)