Flyway - Different Migrations for certain envioronments - Spring Boot - java

We are configuraing/starting our flyway migrations in java in our Spring Boot App.
So we have both sql and java migration files.
In certain environments we want extra migrations to run. Basically in a QA env we want to prepare the DB with data for tests.
So I know you can configure multiple migration locations in java.
So I can do something like this
if(isQAenv == true)
{
Flyway.configure().locations("/db/migrations/","db/qaMigrations/")
else{
Flyway.configure().locations("/db/migrations/")
}
My issue is with the versioning and making sure stuff gets executed as intended in all envs.
Do I need to maintain the numbering system to be the correct order?
So lets say I have the following migration scripts that should run in all envs
db/migrations/V1__table1.sql
db/migrations/V2__table2.sql
db/migrations/V4__table2.sql
And this migration only runs in QA env
db/qaMigrations/V3__insert_statements.sql
Now in a non QA env, my beacon_history_table has migration for 1,2,4. Is there any way to avoid this and have something that looks cleaner in the history table?

You can easily do that using profiles, so suppose you have profiles i.e dev, prod, then you can easily define the spring.flyway.locations path in your properties file for that profile or in a section for that profile in application.yml file.
spring:
profiles: prod
flyway:
locations: classpath:/db/migration,classpath:/prod/db/migration
---
spring:
profiles: dev
flyway:
locations: classpath:/db/migration,classpath:/dev/db/migration
Or if you have properties file then you should have file i.e application-dev.properties and then
spring.flyway.locations=classpath:/db/migration,classpath:/dev/db/migration
All the paths, mentioned above should be present inside the resources folder.

Related

Spring Boot: Load common config application properties file using bootstrap.yml

In our config server we have following application properties files:
helloApp-dev.properties //dev env properties
helloApp-commonConfig.properties //common properties across env
The properties are accessible from URI like:
https://myapp.abc.com/1234/helloApp-dev.properties
https://myapp.abc.com/1234/helloApp-commonConfig.properties
Below is our bootstrap.yml of helloApp application:
---
spring:
application:
name: helloApp
---
spring
profiles: dev
cloud:
config:
label: 1234
name: {spring.application.name}
uri: https://myapp.abc.com/
I am using Spring boot version 2.2.4. The helloApp-dev.properties are loading successfully in application but not commonConfig.
The configuration in commonConfig is not being loaded because you are not indicating to Spring that it should load that profile/config, because you are activating only the dev profile - and the configuration for that profile is the one which is being loaded:
---
spring
profiles: dev
In addition to the good solutions proposed by #akozintsov in his/her answer, if you need to include certain common configuration in different environments or profiles, let's say dev, qa or prod, you can use the spring.profiles.include configuration property and include, as a comma separated list of values, if using properties files, or as a list, if using yaml, the different common profiles and corresponding configurations you need to.
In your example, in helloApp-dev.properties you need to include the following information within the rest of your configuration:
spring.profiles.include=commonConfig
These related SO question and this article could be of help as well.
To load properties file, profiles should match.
You have 2 solutions:
Rename helloApp-commonConfig.properties -> helloApp.properties
Use multiple profiles for your application (dev, commonConfig)

Manage Spring Boot Profiles with Gradle

I have a Spring boot application which is managed by Gradle.
What is done so far:
Created application.yaml, application-dev.yaml, and application-qa.yaml files
Mentioned spring: profiles: active: dev in application.yaml (default profile should be dev if none is mentioned)
What need to be done:
Need to build war with profile mentioned or passed while building. Example, for QA build, spring: profiles: active: should have value qa, so that it can pick-up application-qa.yaml properties.
If no profile is passed, then by default dev profile should be selected
What is tried so far:
Added #activeProfiles# in spring: profiles: active: #activeProfiles# in application.yaml and added below snippet in build.gradle:
processResources {
filter org.apache.tools.ant.filters.ReplaceTokens, tokens: [
activeProfiles: activeProfiles
]
}
And fired following command to build the war - gradlew clean build -PactiveProfiles=qa, and it just did right job for war file. But now issue with this approach is, how to provide default value for activeProfiles while running the project from IDE (I usually prefer to run main class from IntelliJ)?
I am also not sure if this is the correct approach or is there any other approach to achieve this task. I have already done all these stuff with Maven, and with ease, but I am new to Gradle, and it's project requirement to use Gradle.
One common approach to switch between profiles in different environments is to set up SPRING_PROFILES_ACTIVE environment variable to your desired value and let Spring boot use that. For example, in QA environment you would set the value to qa and Spring will automatically use qa application properties.
Read more : https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-set-active-spring-profiles
I was able to set default profile, if no profile is passed while running/building the code, using below configurations in build.gradle file. No extra configuration is needed in any IDE to run the project.
def activeProfiles=project.properties['activeProfiles'] ?: "dev" // set default (dev) profile if no profile is passed as property
processResources {
filter org.apache.tools.ant.filters.ReplaceTokens, tokens: [
activeProfiles: activeProfiles
]
}
I have 3 yaml files for configurations as per environments:
application.yaml
application-dev.yaml
application-qa.yaml
application.yaml contains below configuration for spring profile management, and other common configurations:
spring:
profiles:
active: #activeProfiles#
...
application-dev.yaml and application-qa.yaml files contain configurations related to respective environments.

Spring Boot - Profiles (application.properties) to define baseUrl for HTTP requests

The situation is that I have two api projects, API A does HTTP requests to API B. Both API's are deployed to a development and production environment.
What I want to achieve is the following: Build the project based on a specific profile (dev or prod) so that the code can use a particular baseurl to talk with the correct api on the correct environment.
So if I build API A based on prod flag, I want it to use the specific url to make http requests to API B that is deployed on it's own prod environment.
It looks like you're referring to profiles of maven, however you should probably check out spring profiles. The concept should change :
You're not supposed to build different artifacts for different environments.
Instead create a spring profile in service A:
application-dev.properties:
url.addr=dev-service-host:1234
application-prod.properties:
url.addr=prod-service-b-host:4321
Then run the application with --spring.profiles.active=dev (or prod) flag.
Spring boot will load the correct definitions automatically because the dev/prod matches the suffix of properties file
You can define Spring-Boot profile as:
spring.profiles.active=prod
You also should have profiled .properties files in resources:
in application-dev.properties you should have api.b.url={api_b_url_on_dev_environment}
in application-prod.properties you should have api.b.url={api_b_url_on_prod_environment}
Or if you don't want to recompile your application after changing properties you may use outside .properties files.
In order for them to be included during app's deployment do the following:
in some config directory add application-dev.properties and application-prod.properties
deploy you app with the following properties: --spring.profiles.active=dev and --spring.config.additional-location=config/application.properties
This way the outside profiled properties will be included in deployment process. These .properties files have the highest priority in Spring.

How to externalize application.properties files in Spring Boot to e.g. external dependent JAR?

I have a simple Maven module (not a Spring Boot application) in which I have placed my application.properties file.
I have 6-7 Spring Boot applications and I don't want to have an application.properties file in each and every application directory. I prefer it, if it is at one single place (external Maven module).
I am adding the maven module as a dependency in each of those Spring Boot application poms.
But, when I run those applications, it is not able to auto-detect the application.properties file because it is coming from a dependent jar not present physically in each of their application directories.
Is there any way to make this possible? I would like to avoid having properties files in 6-7 different locations, because that becomes tough to manage and handle.
Thank you in advance!
Consider using Spring Cloud Config that provides server and client-side support for externalized configuration in a distributed system. It requires some small effort, but it is very useful in long term. Config server manages configuration files (.properties or .yml), you can still use different config per profile (e.g. application-test.properties, application-prod.properties etc.). Your application has a higher priority, so you can always override properties coming from config server if needed. Another cool feature is that config server can utilize Git repository, so you can easily version all your configuration files. It also supports encryption - any fragile data can be encrypted so only your application knows how to decrypt it.
Config server
Config server is nothing else than a simple Spring Boot application that can be implemented as:
#SpringBootApplication
#EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
SpringApplication.run(ConfigServer.class, args);
}
}
with simple application.properties file included:
server.port: 8888
spring.cloud.config.server.git.uri: file://${user.home}/config-repo
with dependency in pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Config client
On client side you add a dependency to your pom.xml (or its equivalent in build.gradle if you use Gradle):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
and all you have to do is add a URL to config server to your application.properties (or application.yml if you use YAML insted):
spring.cloud.config.uri: http://myconfigserver.com
Config files structure
Now let's say you have set up Git repository for your configuration files. Let's assume that your applications are named like horus, venus, mercury etc. and you have 3 different profiles: dev, test and prod. You also have some configuration that is common for all applications. In this case your configuration files structure would look like this (I will use properties files here but it applies to YAML as well):
application.properties - common config for all apps no matter what profile they use
application-dev.properties - common config for all apps running with dev profile
application-test.properties - common config for all apps running with test profile
application-prod.properties - common config for all apps running with prod profile
horus.properties - horus app config for, common for all profiles
horus-dev.properties - horus app config for dev profile only
horus-test.properties - horus app config for test profile only
horus-prod.properties - horus app config for prod profile only
etc.
There are some additional options that can be set (like encryption, connection strategy (fail fast or ignore) etc.), everything is well described and documented in official documentation https://cloud.spring.io/spring-cloud-config/ Hope it helps you making a good choice for managing your configuration in distributed application environment. Config server is a solution that was invented to solve this problem.
While Szymon Stepniak's answer certainly is a "by-the-book" of Spring Boot answer, I understand your situation, and even tried to do what you try to do by myself. Indeed, you can't define application.properties in other "external modules".
Here is how I've solved it:
Create a configuration in the "common" module
Create a property file in src/main/resources. It shouldn't be named application properties, It's better to provide a unique name for it (at least this is how I've done it, so let's assume that the file is called application-common.properties)
Use #PropertySources annotation to define a property file and load it with configuration.
Here is an example:
package com.myapp.common;
#Configuration
#PropertySources({
#PropertySource("classpath:application-common.properties")
})
public class MyConfiguration {
// you don't really have to define beans
}
Now if you want this configuration to load automatically only because the dependency is defined in your spring boot module of your build system, I've found the best to utilize spring factories:
Create the file src/main/resources/META-INF/spring.factories
Place the following into this file:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.myapp.common.MyConfiguration

JAVA SPRING - Using Maven, steps to create 2 war file (quality & production)

Can anyone please help me to create 2 war files using maven, java spring?
Requirement: Need 4 war file
For that 1st create 2 war file
(make another 2 copy from this with different name for oauth)
database name only diff between staging & production war
staging (http://10.19:3006/imdesk_imapi_staging)-sql datasource- for staging
1)war - api
2)oauth staging war - copy
production (http://10.19:3006/imdesk_imapi_production)-sql datasource for ****production****
1)api - war
2)oauth war - copy
work with maven profiles
http://maven.apache.org/guides/introduction/introduction-to-profiles.html
so you can create different artifacts for different stages
I see two paths you could take to solve the issue:
1. Use maven profiles.
http://maven.apache.org/guides/introduction/introduction-to-profiles.html
How can a profile be triggered? How does this vary according to the type of profile being used?
A profile can be triggered/activated in several ways:
Explicitly
Through Maven settings
Based on environment variables
OS settings
Present or missing files
Details on profile activation
Profiles can be explicitly specified using the -P CLI option.
This option takes an argument that is a comma-delimited list of profile-ids to use. When this option is specified, the profile(s) specified in the option argument will be activated in addition to any profiles which are activated by their activation configuration or the section in settings.xml.
mvn groupId:artifactId:goal -P profile-1,profile-2
2. Use Spring profiles.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
Spring Profiles provide a way to segregate parts of your application configuration and make it only available in certain environments. Any #Component or #Configuration can be marked with #Profile to limit when it is loaded:
`#Configuration
#Profile("production")
public class ProductionConfiguration {
// ...
}
In the normal Spring way, you can use a spring.profiles.active Environment property to specify which profiles are active. You can specify the property in any of the usual ways, for example you could include it in your application.properties:
spring.profiles.active=dev,hsqldb
or specify on the command line using the switch --spring.profiles.active=dev,hsqldb

Categories