Micronaut Dockerfile breaks package build - java

I've created a simple Micronaut application using
mn create-app app_name --build maven
with a JDK 11 in case that matters.
This creates a maven project which compiles fine, but includes a Dockerfile like this:
FROM adoptopenjdk/openjdk11-openj9:jdk-11.0.1.13-alpine-slim
COPY target/app_name*.jar app_name.jar
EXPOSE 8080
CMD java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Dcom.sun.management.jmxremote -noverify ${JAVA_OPTS} -jar app_name.jar
However, there is no docker build included in the Maven AFAICT.
So I included this
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>${dockerfile-maven-version}</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>dockerUser/app_name</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
which does manage to build a docker image, but not without manual intervention. The reason is that upon mvn package, three jars get created in target/:
app_name-0.1.jar
app_name-0.1-shaded.jar
original-app_name-0.1.jar
which makes the docker target fail with
When using COPY with more than one source file, the destination must be a directory and end with a /
That message does make sense because all the jars match the COPY source pattern in the Dockerfile.
Right now, I just delete the other two jars (original and shaded) and run the docker target on its own, but that's only fine as long as I work in local manual mode.
Am I missing something or is this an oversight on the Micronaut project creation?

I can't help you with the micronaut configuration, unfortunately. However, if the purpose is to copy the main jar file and the unknown version suffix is the cause of the wildcard being used while copying, a finalName element can be added to the pom.xml in order to strip the version info from the name of the JAR file:
<build>
<finalName>app_name</finalName>
</build>

Am I missing something or is this an oversight on the Micronaut
project creation?
The latter.
If you file an issue at https://github.com/micronaut-projects/micronaut-profiles/issues we can get it straightened out.
Relevant files:
https://github.com/micronaut-projects/micronaut-profiles/blob/c391ef02b5ca087bbdec79f80b129240b29cc246/service/skeleton/maven-build/Dockerfile
https://github.com/micronaut-projects/micronaut-profiles/blob/c391ef02b5ca087bbdec79f80b129240b29cc246/service/skeleton/gradle-build/Dockerfile
Thanks for the input.

Related

Remove the dependency on Python while building RPM using rpm-maven-plugin

I'm using rpm-maven-plugin to build an rpm as a part of my mvn build which later will be installed in a docker image that doesn't have Python. Python is not being used in the project as well. But for some reason, the generated spec file has the line
Requires: python >= 2.6
I tried putting in
<autoRequires>no</autoRequires>
<autoProvides>no</autoProvides>
but doesn't work as well. This is causing the docker build to fail as the rpm install fails because of missing dependency. How do I remove the dependency on python?
Following is the extract from my pom.xml
...
<version.rpm-maven-plugin>2.2.0</version.rpm-maven-plugin>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>rpm-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-rpm</id>
<phase>package</phase>
<goals>
<goal>rpm</goal>
</goals>
</execution>
</executions>
<configuration>
<group>XXX</group>
<vendor>XXX</vendor>
<copyTo>
target/${install.package.name}-${project.version}.rpm
</copyTo>
<targetOS>linux</targetOS>
<autoRequires>no</autoRequires>
<autoProvides>no</autoProvides>
<mappings>
...
</mappings>
<preinstallScriptlet>
<scriptFile>${basedir}/src/main/package/control/preinst</scriptFile>
<fileEncoding>utf-8</fileEncoding>
</preinstallScriptlet>
<postinstallScriptlet>
<scriptFile>${basedir}/src/main/package/control/postinst</scriptFile>
<fileEncoding>utf-8</fileEncoding>
</postinstallScriptlet>
<preremoveScriptlet>
<scriptFile>${basedir}/src/main/package/control/prerm</scriptFile>
<fileEncoding>utf-8</fileEncoding>
</preremoveScriptlet>
<postremoveScriptlet>
<scriptFile>${basedir}/src/main/package/control/postrm</scriptFile>
<fileEncoding>utf-8</fileEncoding>
</postremoveScriptlet>
<cleanScriptlet>
<script>rm -rf ${project.build.directory}/rpm/buildroot</script>
</cleanScriptlet>
</configuration>
</plugin>
maven version: 3.5.4.
target docker image runs bare-bones SLES linux with just what is required and doesn't have Python.
Got it working by manually overriding the requires section
...
<autoRequires>no</autoRequires>
<autoProvides>no</autoProvides>
<requires>
<require>java-11-openjdk-headless</require>
</requires>
...

Enable exec-maven-plugin while executing jar through java command

I am using exec-maven-plugin to execute a shell script.
<executions>
<execution>
<id>exec-ui-install</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>bash</executable>
<arguments>
<argument>${basedir}/ui-build.sh</argument>
</arguments>
<skip>${exec.skip}</skip>
</configuration>
</execution>
</executions>
I dont want this to run during build time (as i don't need to run it during build and i am building it from windows). So i am using a parameter named exec.skip and with its help i am able to skip it.
After building jar and moving it to Linux env i am using java command
Ex: java -cp : javaclass
to run the jar. During this i need to execute "exec-maven-plugin" which was disabled during build mode. How do i pass "exec.skip=true" through java command so that i can run plugin.
You cannot do it.
The maven configuration of a project is used during the build of the project.
Once the artifact/component is constructed, you don't interact any longer with maven.
In your case, you should build your component with the suitable configuration parameters before moving it to linux.
Using a Maven profile with this specific configuration that is launched by a continuous integration tool could ease the task and make it reliable.

adding ## to maven 3 artifact name for tomcat 7 parallel deployment

I have read quite a few answers on this forum, so hopefully I am asking something.
Recently we moved to Tomcat 7 and usual procedure is to pick up a war file from Nexus repository, stick it in tomcat webapps dir and start the server and use it.
But due to war file artifact name in Nexus being my-app-war-1.0.war context path in tomcat is not what is expected. I know that this can be configured by context.xml, but I was wondering if there is a way to add ## to artifact name that is deployed in Nexus.
I tried changing #{project.build.finalName} but it only changes artifact name in target directory, maven deploy plugin still uses artifactId, which is 'my-app-war'. So artifact in Nexus ends up being 'my-app-war-1.0.war' As artifactId in maven has a quite strict structure and ## is not allowed there I was wondering what would be the right way of adding ## to artifact name, as we are very likely to consider to use parallel deployment, so I am looking for ways to enable this functionality.
I guess I could deploy two versions of the same war file to Nexus, one being named slightly different(with ##), but then it`s easier to just rename it and save some space. I wonder was there any plan how would the ## would be added to application name, when Parallel naming feature was implemented in Tomcat.
You can use <classifier> configuration of maven-war-plugin. This way your war will be installed to the repository with the name ${project.artifactId}-${project.version}-my-app-war.war
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<classifier>##my-app-war</classifier>
</configuration>
</plugin>
The problem is that Nexus returning the following error if you include in maven version ##.
Illegal character in fragment at index 103
You can enter in <path> by deploying to Apache7 the characters ## for the paralell deployment as folowing:
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<executions>
<execution>
<id>remote</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
<configuration>
<mode>war</mode>
<path>/${project.artifactId}-##${project.version}</path>
<url>http://tomcat7.../manager/text</url>
<username>user</username>
<password>password</password>
<update>true</update>
</configuration>
</execution>
</executions>
</plugin>

Proguard is saying it can't find any classes

I'm using proguard with a spring mvc application and maven.
My pom.xml's build section looks like:
<build>
<finalName>myapp</finalName>
<plugins>
<plugin>
<groupId>com.pyx4me</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<obfuscate>true</obfuscate>
<!--<options>-->
<!--<option>-keep public class</option>-->
<!--</options>-->
<injar>${project.build.finalName}</injar>
<injar>${project.build.finalName}</injar>
<inFilter>com.myapp.*</inFilter>
</configuration>
</plugin>
</plugins>
I also tried:
<injar>${project.build.finalName}.war</injar>
When I run:
mvn clean install
Build failure message:
[proguard] Reading program war [/Users/me/dev/git/myproject/myapp/target/myapp.war] (filtered)
[proguard] Error: The input doesn't contain any classes. Did you specify the proper '-injars' options?
ERROR] Failed to execute goal com.pyx4me:proguard-maven-plugin:2.0.4:proguard (default) on project myapp: Obfuscation failed (result=1) -> [Help 1]
It seems to have picked up my jar correctly as the messages before show:
[INFO] --- proguard-maven-plugin:2.0.4:proguard (default) # myapp ---
[INFO] execute ProGuard [-injars, '/Users/me/dev/gitserver/myproject/myapp/target/myapp.war'(!META-INF/maven/**,com.myapp.*), -outjars, '/Users/me/dev/git/myproject/myapp/target/myapp_pg.war', -libraryjars, ....
Also, what options do you suggest I use? This is a spring mvc so I have annotations like:
#Autowired
#Service
#Repository
#Controller
So any of those classes/fields should not be renamed I would imagine.
(My goal is just to make it a headache to someone who decompiles, such that they can't just decompile and use the code. Obfuscating will let them use it, but they won't be able to maintain the codebase unless they re-write it. I don't have any fancy algorithms so I have nothing really to hide in that respect.)
Update
Let me be clear here, my spring mvc using maven for some reason (I'm new to maven) when doing a mvn clean install produces both a myapp.war file and a exploded war myapp/ (this is what I want to deploy in production, not the myapp.war file)
My myapp folder has:
/target/myapp/
/target/myapp/meta-inf (empty folder)
/target/myapp/web-inf
/target/myapp/web-inf/classes (com.myapp. ...)
/target/myapp/web-inf/lib/
/target/myapp/web-inf/ web.xml, application.xml (for spring)
/target/myapp/web-inf/views/
So proguard should be obfuscating in the /target/myapp/web-inf/classes folder right?
How do I tell it to do so?
Update 2
I'm getting this now:
OK, I am not getting: failed to execute goal ...proguard .. Can't rename /Users/me/dev/git/project1/myapp/target/myapp/web-inf/classes (see my updates section for what I changed in my pom.xml)
I changed my pom.xml with:
<configuration>
<obfuscate>true</obfuscate>
<injar>${project.build.finalName}/WEB-INF/classes/</injar>
<inFilter>com/myapp/**</inFilter>
</configuration>
ProGuard filters work on file names, so
.....(!META-INF/maven/**,com.myapp.*)
probably won't match any class files. You probably want
.....(!META-INF/maven/**,com/myapp/**)
See ProGuard manual > Usage > File Filters
Can you post your entire pom?
Normally, Maven compiles to /target/classes (Even for WAR files) and the WAR plugin does the copy to web-inf/classes right before the package phase. You should not be manually compiling classes to web-inf/lib with Maven.
EDIT: OK this has take quite a bit of research, but I've found an answer for you. First, according to the ProGuard documentation, you should not have ANY classes in your war project:
Notably, class files that are in the WEB-INF/classes directory in a
war should be packaged in a jar and put in the WEB-INF/lib directory
You need to refactor your project so your web classes are built in a separate jar. Once you have built that jar project, you must add it as a dependency in your war project.
Once I created that setup, I was successfully able to build a war project with the following configuration:
<build>
<plugins>
<plugin>
<groupId>com.pyx4me</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<inFilter>com/example/**</inFilter>
<libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jsse.jar</lib>
</libs>
<options>
<option>-keep class com.example.echo.EchoServlet</option>
<option>-injar ${project.build.directory}/${project.build.finalName}.${project.packaging}</option>
<option>-outjar ${project.build.directory}/${project.build.finalName}-proguarded.${project.packaging}</option>
</options>
</configuration>
</plugin>
</plugins>
</build>
Note the "com.example.echo.EchoServlet". Since progaurd was going to change the name of my classes, I had to "keep" this servlet name so I could reference it in the WAR project's web.xml. If you use annotation based servlet configuration, I imagine this won't be necessary.

maven upload file per scp

whats the preferred way to upload an artifact via scp to a predefined destination?
i tried using the wagon:upload mojo, but it wont execute atomatically when i defined a "executions" section in my pom like that:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>1.0-beta-3</version>
<executions>
<execution>
<phase>release</phase>
<goals>
<goal>upload</goal>
</goals>
</execution>
</executions>
<configuration>
<fromDir>target/checkout/target</fromDir>
<includes>*.jar</includes>
<url>scpexe://host/dir</url>
<toDir />
<serverId>my id</serverId>
</configuration>
</plugin>
i added the necessary extension wagon-ssh and wagon-ssh-external and it all works fine when i execute wagon:upload but it wont upload the artifact automatically in the release phase.
Is this even the right way to upload artifacts to a website, or should the deploy plugin take care of that?
thanks!
That's because no release phase exists (see Maven Lifecycle Reference)
You probably want phase deploy. And yes, wagon is usually used by the maven deploy plugin (automatically when you execute mvn deploy).

Categories