JCommander argument doesn't work in Docker ENTRYPOINT - java

I have a standard JCommander parameter which works fine when running the jar locally or through IntelliJ, but as soon as I try and load it through a dockerfile it returns:
Exception in thread "main" com.beust.jcommander.ParameterException: Was passed main parameter '-profile ${PROFILE}' but no main parameter was defined in your arg class
The code I'm loading the args through:
#Data
public static class Args {
#Parameter(
names = {"-profile", "-p"},
arity = 1,
required = true)
private String profile;
}
I'm parsing that via:
JCommander.newBuilder().addObject(ARGS).build().parse(args);
The entry point command I have in my Dockerfile:
ENTRYPOINT ["java" , "-jar", "/usr/app/app.jar", "-profile ${PROFILE}"]
Finally I'm just starting the container the usual way with ...-e PROFILE=dev
Is there something obvious I've missed here, do I just need to escape quotes somewhere or something?

This was an obvious mistake which took longer than I care to admit to spot. The correct way to pass arguments if of course
ENTRYPOINT ["java" , "-jar", "/usr/app/app.jar", "-profile", "${PROFILE}"]
Note the comma between the key -profile and its value ${PROFILE}.

Related

Passing a value from cmd/runtime using gradle is not getting picked up

I have an abstract class that has a value of workingDirectory (variable)
I extended this in a new class (BaseClass). I want to override this by providing a value at runtime, and this is not happening. It is taking the default value.
I am using Gradle to run that file, it has test cases
The command in the code (BaseClass)
private static final String workingDirectory = System.getenv("infrastructurePath")==null?"./infrastructure":System.getenv("infrastructurePath");
The command I used to run from cmd
.\gradlew --info :testModule:testInfrastructure -DinfrastructurePath='./infrastructure-localtests'
But, it is taking ./infrastructure every time and not ./infrastructure-localtests when I try to pass the value from the command prompt. Where do I make the change?
I faced a similar situation long back. I was using IntelliJ for the same.
Try making the following changes:
In your base class, change the name of your workingDirectory variable. It should not be the same as you have in the abstract class.
Use the new variable name everywhere.
Use System.getproperty("name of the path / or path variable");
Do not use System.getenv() with a ternary operator. It didn't work for me.
Now, go to your build.gradle.
As you told you are running the test cases. you would be having a task created in tasks.register('YourTestName', Test)
Inside that, add a new line of
systemProperty "YourPath", System.getProperty("YourPath", "./TheDefaultPathIfNoConditionMatches");
Now, at run time, if you simply run the tests, the control will go to the default path. If you want it to go to a new path, add an -D argument like this
-DinfrastructurePath="./WhateverPath"
This should work for you. Thanks.

Pass $ character to Gradle start scripts (Application plugin)

I have a Gradle build script that uses the Application plugin, and I want to pass as JVM argument a string that contains the $ character, but I can't because it always is converted to the \$ sequence of characters...
Here is my configuration:
application {
mainClass = 'example.Main'
application.applicationDefaultJvmArgs = ['-javaagent:$APP_HOME/lib/agent.jar']
}
But then in the start script I get:
DEFAULT_JVM_OPTS='"-javaagent:\$APP_HOME/lib/agent.jar"'
And because of that \ it doesn't work, I need the value to be -javaagent:$APP_HOME/lib/agent.jar. All ways I tried get the same result (using interpolation, passing the $ as \u0024, etc.).
I've found a workaround in this answer for a related question. The code in question is the following:
startScripts {
doLast {
unixScript.text = unixScript.text.replace('\\$APP_HOME', '\$APP_HOME')
//do something like this for Windows scripts if needed too
}
}

Dropwizard Enviornment Variable Substitution Type Check Error

I'm a Dropwizard newbie and am using an existing Dropwizard service, where I am attempting to create YML values that are overridable depending on the environment that my service is deployed to (i.e. Dev, QA, Prod). I tried Googling my error message, but really didn't find a whole lot for this specific error, so I thought that I would post a new question for this.
When I run my script that starts the service, I get the following error:
my-host:my-service jthoms$ ./start.sh 3.0.0
Starting my-service...
src/main/resources/configuration.yml has an error:
* Incorrect type of value at: downstream_service.loggingEnabled; is of type: String, expected: boolean
Note that I have already created a MyServiceConfiguration class which extends Dropwizard's main Configuration class and delegates to a DownstreamServiceConfiguration class that has a boolean field for the loggingEnabled property. I did this in accordance with the Dropwizard Core doc.
My start.sh script is as follows:
#!/bin/sh
if [ "$#" -ne 1 ]; then
echo "Please pass jar version! Usage: ./start.sh <jar_version>"
exit 1
fi
echo "Starting my-service with version '$1'"
java $DEBUG_ARGS -Xmx128m -jar target/my-service-$1.jar server src/main/resources/configuration.yml
My configuration.yml is as follows:
server:
...
downstream_service:
loggingEnabled: ${DW_DOWNSTREAM_SERVICE_LOGGING_ENABLED}
...
logging:
...
I don't understand what's causing this type safety error. How can I import my environment variables to Dropwizard as a non-string type?
After some Googling around, I found the solution(s) to my issue, and thought that I would share my answer here for others with the same error message I was getting.
The problem wasn't that my boolean DW_DOWNSTREAM_SERVICE_LOGGING_ENABLED environment was being treated as a string, the problem was the boolean YML property just wasn't being wired up correctly, so the string value it was finding wasn't the string literal, true. Rather, it was the string literal ${DW_DOWNSTREAM_SERVICE_LOGGING_ENABLED}. Basically, Dropwizard just wasn't substituting ${DW_DOWNSTREAM_SERVICE_LOGGING_ENABLED} for true in the first place.
The solution involved two things:
Call the script that actually creates the environment variables from my start.sh script. I had actually forgotten to do this. Doh!
Configure the application's bootstrap to use an EnvironmentVariableSubstitutor as per this answer. Note that you don't need to set the EnvironmentVariableSubstitutor to use non-strict checking, the shell variables aren't being unconditionally interpreted as strings by Dropwizard. The following code needs to be added to your main Application class.
#Override
public void initialize(Bootstrap<MyServiceConfiguration> bootstrap) {
bootstrap.setConfigurationSourceProvider(
new SubstitutingSourceProvider(bootstrap.getConfigurationSourceProvider(),
new EnvironmentVariableSubstitutor()));
}
Those two things combined solved the problem.

Packaging a jar with preconfigured command line arguments

I am wondering if there's a way to create a jar that includes some command line arguments in it, the arguments that are usually passed in the command line when one tries to start up the jar (these parameters are then passed on to the main function). Basically instead of starting my app with
java -jar myapp.jar "arg1" "arg2", I want to start my app with
java -jar myapp.jar
and have "arg1" and "arg2" passed to the main function.
The reason behind this is that I want to deploy this to different environments, and I want my jar to contain different parameters according to the environment it's being deployed at.
Maybe there's another way to achieve similar results ??
Cheers.
PS: Looking for a maven solution.
Edit: I'll add a complete example to make this a bit more clear:
Let's say I have 2 environments: "Production" and "Test". I want to run the jar in the same way no matter in what environment I deploy it. So I always want to run it with:
java -jar myapp.jar
But! In order for my 2 environments to run ok, I need the Production environment jar to start it's main method with an argument "prod" and I need the Test environment jar to start it's main method with an argument "test".
If I correctly understood your problem, in your main() you could define a simple logic to handle the case where you do not specify any input parameter; the logic could retrieve the desired values according to the correct platform/env.
As an example:
public class Test01
{
public static void main(String... aaa)
{
// Check input
if(aaa.length == 0) {
/* Insert logic to retrieve the value you want, depending on the platform/environment.
* A trivial example could be: */
aaa = new String[2];
aaa[0] = "First value";
aaa[1] = "Second value";
}
// Processing, e.g. print the 2 input values
System.out.println(aaa[0] + ", " + aaa[1]);
}
}
Fyi, I created a runnable jar using eclipse, and start the application by either
java -jar Test01.jar
or
java -jar Test01.jar arg1 arg2
Hope this helps!
One solution is to change main(String[] args) to get values from env var if they are not present in the passed arguments.
String user;
String password;
if(args.length < 2)
{
user = System.getenv("appUser");
password = System.getenv("appPassword");
} else {
user = args[0];
password = args[1];
}
You can also create another class with a main function that will call the real one.
public class CallerMyApp{
public void main(String[] args) {
String[] realArgs = {System.getenv("appUser"), System.getenv("appPassword")};
MyApp.main(realArgs);
}
}
Then to execute its something like
java -cp myapp.jar CallerMyApp

How to add command line parameter dependency using JCommander?

I am using JCommander for command line parameters parsing. I would like to add parameter dependency, but from the JCommander documentation, I am not able to find out if it is even supported. Has anyone tried it ?
For example, java -jar Some.jar -a Foo -b Hola
So, option -b shall only accompany with option -a.
This is supported in args4j. However, I can't use args4j because it does not support multiple values as JCommander.
Thanks
Yes, you can use args4j, it does support multiple values.
JCommander:
#Parameter(names={"--length", "-l"})
int length;
Args4j:
#Option(name = "-l", aliases = { "--length" })
int length;
About validation and dependency: You can do this manually, of course. It's not too much of programming. Just ignore option b if a is not given either, or throw an exception if a is non-null but b is null.
I had exactly the same problem but it looks like that args4j has added support for multiple values:
import org.kohsuke.args4j.spi.StringArrayOptionHandler;
#Option(name = "-p", handler = StringArrayOptionHandler.class, required = true)
private List<String> list;
which should allow
-p arg1 arg2 ...

Categories

Resources