Skip to content

Commit

Permalink
[#3360] Create native executable command line client
Browse files Browse the repository at this point in the history
The build jobs have been changed to consistently use the
eclipse/hono-builder container image for building Hono. This image
contains specific versions of Maven, the GraalVM SDK with the
native-image compiler plugin and the UPX tool for compressing binary
artifacts.

The release build job has been extended with an additional invocation
of mvn clean install used to build the native executable of the CLI.

The native executable needs to be built in a separate run because in the
first build the JAR file artifacts are being signed by the Eclipse JAR
signer service which results in signature errors during the native
executable build.

Signed-off-by: Kai Hudalla <kai.hudalla@bosch.io>
  • Loading branch information
sophokles73 committed Aug 22, 2022
1 parent bba7910 commit 0dfa63c
Show file tree
Hide file tree
Showing 5 changed files with 530 additions and 93 deletions.
69 changes: 69 additions & 0 deletions builder/HonoBuilder.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Copyright (c) 2022 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public Li2cense 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0
#
# SPDX-License-Identifier: EPL-2.0

# This Dockerfile is based on https://github.com/findepi/graalvm-docker.
# It has been adapted to use Mandrel instead of Oracle's GraalVM distribution and has been
# extended with steps for installing Maven, GnuPG (required for creating signatures of
# artifacts to be deployed to Maven Central) and UPX.
# The resulting image can be used to build Hono from source, including the native executable
# of the hono-cli artifact.

FROM debian:stable-slim

ARG MANDREL_VERSION=22.2.0.0-Final
# either java11 or java17
ARG JDK_VERSION=java17
ARG MVN_VERSION=3.8.6

ENV GRAALVM_HOME=/graalvm
ENV MAVEN_HOME=/maven
ENV JAVA_HOME=${GRAALVM_HOME}

RUN set -xeu && \
export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
git \
curl \
gcc \
g++ \
libfreetype6-dev \
libz-dev \
gpg \
pinentry-tty \
openssh-client \
upx-ucl \
&& \
mkdir ${GRAALVM_HOME} && \
curl -fsSL "https://github.com/graalvm/mandrel/releases/download/mandrel-${MANDREL_VERSION}/mandrel-${JDK_VERSION}-linux-amd64-${MANDREL_VERSION}.tar.gz" \
| tar -zxC ${GRAALVM_HOME} --strip-components 1 && \
find ${GRAALVM_HOME} -name "*src.zip" -printf "Deleting %p\n" -exec rm {} + && \
{ test ! -d ${GRAALVM_HOME}/legal || tar czf ${GRAALVM_HOME}/legal.tgz ${GRAALVM_HOME}/legal/; } && \
{ test ! -d ${GRAALVM_HOME}/legal || rm -r ${GRAALVM_HOME}/legal; } && \
rm -rf ${GRAALVM_HOME}/man `# does not exist in java11 package` && \
mkdir ${MAVEN_HOME} && \
curl -fsSL "https://dlcdn.apache.org/maven/maven-3/${MVN_VERSION}/binaries/apache-maven-${MVN_VERSION}-bin.tar.gz" \
| tar -zxC ${MAVEN_HOME} --strip-components 1 && \
echo Cleaning up... && \
apt-get remove -y \
curl \
&& \
apt-get autoremove -y && \
apt-get clean && rm -r "/var/lib/apt/lists"/* && \
echo 'PATH="${GRAALVM_HOME}/bin:$PATH"' | install --mode 0644 /dev/stdin /etc/profile.d/graal-on-path.sh && \
echo 'PATH="${MAVEN_HOME}/bin:$PATH"' | install --mode 0644 /dev/stdin /etc/profile.d/maven-on-path.sh && \
echo OK

# This applies to all container processes. However, `bash -l` will source `/etc/profile` and set $PATH on its own. For this reason, we
# *also* set $PATH in /etc/profile.d/*
ENV PATH=${GRAALVM_HOME}/bin:${MAVEN_HOME}/bin:$PATH
ENV SHELL=/bin/bash
141 changes: 48 additions & 93 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@
<description>Quarkus based Hono Command line Interface</description>

<properties>
<!--
this property prevents the Nexus Staging Maven Plugin to
deploy this module's artifacts to Maven Central' staging repo
-->
<skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo>
<!--
this property prevents the Nexus Staging Maven Plugin to
deploy this module's artifacts to the configured project repository
-->
<skipStaging>true</skipStaging>
<maven.source.skip>true</maven.source.skip>
<maven.javadoc.skip>true</maven.javadoc.skip>
<gpg.skip>true</gpg.skip>
<quarkus.package.type>uber-jar</quarkus.package.type>
<quarkus.package.runner-suffix>-exec</quarkus.package.runner-suffix>
</properties>
Expand Down Expand Up @@ -124,120 +137,62 @@
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<!-- Copy legal documents from "legal" module to "target/classes" folder so that we make sure to include
legal docs in all modules. -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<!-- Execution and configuration for copying certificates from related module to "target/classes" folder
so that we can include them in the image. -->
<id>copy_demo_certs</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeArtifactIds>
hono-demo-certs
</includeArtifactIds>
<outputDirectory>${project.build.directory}/config</outputDirectory>
<includes>
*.pem,
*.jks,
*.p12
</includes>
<useSubDirectoryPerArtifact>true</useSubDirectoryPerArtifact>
<stripClassifier>true</stripClassifier>
<stripVersion>true</stripVersion>
<excludeTransitive>true</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<profiles>

<profile>
<id>build-native-image</id>
<id>build-cli-native-executable</id>
<!--
This profile can be used to build a native executable from the hono-cli jar file.
-->
<properties>
<!-- build native image inside of a container, doesn't require GraalVM SDK to be installed locally -->
<quarkus.native.remote-container-build>true</quarkus.native.remote-container-build>
<quarkus.native.builder-image>${native.builder-image.name}</quarkus.native.builder-image>
<quarkus.package.type>native</quarkus.package.type>
<!--
By default, use remote container based build which does not require local installation of the GraalVM SDK
and native-image compiler.
-->
<quarkus.native.remote-container-build>true</quarkus.native.remote-container-build>
<!-- include all JSSE related classes -->
<quarkus.native.enable-all-security-services>true</quarkus.native.enable-all-security-services>
<!-- allow incomplete class path in order to not require (optional) compression codec dependencies of Netty -->
<!-- use Base64 encoder/decoder that is compatible with vert.x 3 -->
<!--
allow incomplete class path in order to not require (optional) compression codec dependencies of Netty,
open up certain modules' packages as required by native-image builder
(see https://www.graalvm.org/release-notes/22_2/#native-image)
-->
<quarkus.native.additional-build-args>
--initialize-at-run-time=io.netty.internal.tcnative.SSL\,org.apache.kafka.common.security.authenticator.SaslClientAuthenticator,
--allow-incomplete-classpath,
-Dvertx.json.base64=legacy
-J--add-opens=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk=ALL-UNNAMED,
-J--add-opens=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.localization=ALL-UNNAMED,
-J--add-opens=org.graalvm.nativeimage.base/com.oracle.svm.util=ALL-UNNAMED,
-J--add-opens=org.graalvm.sdk/org.graalvm.nativeimage.impl=ALL-UNNAMED
</quarkus.native.additional-build-args>
<quarkus.native.resources.includes>hono-cli-build.properties</quarkus.native.resources.includes>
</properties>

<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<images>
<image>
<name>${docker.repository}/%a-native:%v</name>
<build>
<maintainer>The Eclipse Hono project</maintainer>
<labels>
<project>Eclipse Hono</project>
</labels>
<tags>
<tag>${docker.image.additional.tag}</tag>
</tags>
<imagePullPolicy>Always</imagePullPolicy>
<from>${native.image.name}</from>
<workdir>/opt/hono</workdir>
<entryPoint>
<arg>/opt/hono/${project.artifactId}-${project.version}-runner</arg>
<arg>-Djava.util.logging.manager=org.jboss.logmanager.LogManager</arg>
</entryPoint>
<assembly>
<mode>dir</mode>
<basedir>/</basedir>
<inline>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>opt/hono</outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}-runner</include>
</includes>
</fileSet>
</fileSets>
</inline>
</assembly>
</build>
</image>
</images>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--
This is an optional dependency of picocli but without it, native executable compilation fails
due to unresolved classes.
-->
<dependency>
<groupId>com.googlecode.juniversalchardet</groupId>
<artifactId>juniversalchardet</artifactId>
<version>1.0.3</version>
<optional>true</optional>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
56 changes: 56 additions & 0 deletions jenkins/Failing-Pipeline.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2022 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/

/**
* Jenkins pipeline script for Hono release including the CLI native executable.
*
*/

pipeline {
agent {
kubernetes {
yamlFile 'jenkins/HonoBuilderPod.yaml'
defaultContainer 'hono-builder'
}
}

options {
buildDiscarder(logRotator(numToKeepStr: '3'))
disableConcurrentBuilds()
timeout(time: 45, unit: 'MINUTES')
}

parameters {
string(
name: "BRANCH",
description: "The branch to build and release from.\nExamples:\n refs/heads/master\nrefs/heads/1.4.x",
defaultValue: "refs/heads/master",
trim: true)
}

stages {

stage("Check build environment") {
steps {
sh '''#!/bin/bash
printenv SHELL
git --version
mvn --version
java --version
native-image --version
upx --version
'''
}
}
}
}

0 comments on commit 0dfa63c

Please sign in to comment.