From 5185487fb83ecd44d1638dadc79a8573430e691d Mon Sep 17 00:00:00 2001 From: gyurix Date: Sun, 27 Apr 2025 23:02:49 +0200 Subject: [PATCH] Add Drone CI pipeline configuration and Dockerfile for Guacamole client --- .drone.yml | 34 ++ Dockerfile.alpine | 122 +++++ start.sh | 1276 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1432 insertions(+) create mode 100644 .drone.yml create mode 100644 Dockerfile.alpine create mode 100644 start.sh diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 000000000..f40c290fd --- /dev/null +++ b/.drone.yml @@ -0,0 +1,34 @@ +kind: pipeline +type: kubernetes +name: default + +node_selector: + physical-node: dev1 + +trigger: + event: + - push + +workspace: + path: /drone/src + +steps: + - name: pull image to dockerhub + image: docker.io/owncloudci/drone-docker-buildx:4 + privileged: true + settings: + cache-from: [ "safebox/guacamole-tomcat" ] + repo: safebox/guacamole-tomcat + dockerfile: Dockerfile.alpine + tags: latest + username: + from_secret: dockerhub-username + password: + from_secret: dockerhub-password + platforms: + - linux/amd64 + - linux/arm64 + when: + event: + - push + diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 000000000..78f352090 --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,122 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# +# Dockerfile for guacamole-client +# + +# Use args for Tomcat image label to allow image builder to choose alternatives +# such as `--build-arg TOMCAT_JRE=jre8-alpine` +# +ARG TOMCAT_VERSION=9 +ARG TOMCAT_JRE=jdk21 + +# Use official maven image for the build +FROM maven:3-eclipse-temurin-21 AS builder + +# Use Mozilla's Firefox PPA (newer Ubuntu lacks a "firefox-esr" package and +# provides only a transitional "firefox" package that actually requires Snap +# and thus can't be used within Docker) +RUN apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y software-properties-common \ + && add-apt-repository -y ppa:mozillateam/ppa + +# Explicitly prefer packages from the Firefox PPA +COPY guacamole-docker/mozilla-firefox.pref /etc/apt/preferences.d/ + +# Install firefox browser for sake of JavaScript unit tests +RUN apt-get update && apt-get install -y firefox + +# Arbitrary arguments that can be passed to the maven build. By default, an +# argument will be provided to explicitly unskip any skipped tests. To, for +# example, allow the building of the RADIUS auth extension, pass a build profile +# as well: `--build-arg MAVEN_ARGUMENTS="-P lgpl-extensions -DskipTests=false"`. +ARG MAVEN_ARGUMENTS="-DskipTests=false" + +# Versions of JDBC drivers to bundle within image +ARG MSSQL_JDBC_VERSION=9.4.1 +ARG MYSQL_JDBC_VERSION=8.3.0 +ARG PGSQL_JDBC_VERSION=42.7.2 + +# Build environment variables +ENV \ + BUILD_DIR=/tmp/guacamole-docker-BUILD + +# Add configuration scripts +COPY guacamole-docker/bin/ /opt/guacamole/bin/ +COPY guacamole-docker/build.d/ /opt/guacamole/build.d/ +COPY guacamole-docker/entrypoint.d/ /opt/guacamole/entrypoint.d/ +COPY guacamole-docker/environment/ /opt/guacamole/environment/ + +# Copy source to container for sake of build +COPY . "$BUILD_DIR" + +# Run the build itself +RUN /opt/guacamole/bin/build-guacamole.sh "$BUILD_DIR" /opt/guacamole + +RUN rm -rf /opt/guacamole/build.d /opt/guacamole/bin/build-guacamole.sh + +# For the runtime image, we start with the official Tomcat distribution + +RUN ls -al /opt/guacamole/ + +FROM alpine + +COPY --from=builder /opt/guacamole /opt/guacamole + +RUN ls -al / + +ENV TOMCAT_MAJOR=9 \ + TOMCAT_VERSION=9.0.78 \ + CATALINA_HOME=/opt/guacamole + +RUN \ + apk add --update --no-cache \ + openjdk8-jre curl mariadb-client bash openssl && \ + curl -jkSL -o /tmp/apache-tomcat.tar.gz \ + http://archive.apache.org/dist/tomcat/tomcat-${TOMCAT_MAJOR}/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz && \ + gunzip /tmp/apache-tomcat.tar.gz && \ + tar -C /opt -xf /tmp/apache-tomcat.tar && \ + ln -s /opt/apache-tomcat-$TOMCAT_VERSION /usr/local/tomcat && \ + chmod -R a+rx /usr/local/tomcat/ + +# cleanup +RUN apk del curl && \ + rm -rf /tmp/* /var/cache/apk/* /usr/local/tomcat/webapps/* + + +# Create a new user guacamole +COPY /start.sh /opt/guacamole/bin/ +RUN chmod a+x /opt/guacamole/bin/start.sh +ARG UID=1001 +ARG GID=1001 +RUN addgroup -g $GID guacamole +RUN adduser -S -D -s /usr/sbin/nologin -u $UID guacamole --ingroup guacamole + +# Run with user guacamole +USER guacamole + +EXPOSE 8080 + +WORKDIR $CATALINA_HOME + +# Start Guacamole under Tomcat, listening on 0.0.0.0:8080 +EXPOSE 8080 +CMD ["/opt/guacamole/bin/start.sh" ] \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100644 index 000000000..c9b8f7294 --- /dev/null +++ b/start.sh @@ -0,0 +1,1276 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +## +## @fn start.sh +## +## Automatically configures and starts Guacamole under Tomcat. Guacamole's +## guacamole.properties file will be automatically generated based on the +## linked database container (either MySQL, PostgreSQL or SQLServer) and the linked guacd +## container. The Tomcat process will ultimately replace the process of this +## script, running in the foreground until terminated. +## + +GUACAMOLE_HOME_TEMPLATE="$GUACAMOLE_HOME" + +GUACAMOLE_HOME="$HOME/.guacamole" +GUACAMOLE_EXT="$GUACAMOLE_HOME/extensions" +GUACAMOLE_LIB="$GUACAMOLE_HOME/lib" +GUACAMOLE_PROPERTIES="$GUACAMOLE_HOME/guacamole.properties" + +## +## Sets the given property to the given value within guacamole.properties, +## creating guacamole.properties first if necessary. +## +## @param NAME +## The name of the property to set. +## +## @param VALUE +## The value to set the property to. +## +set_property() { + + NAME="$1" + VALUE="$2" + + # Ensure guacamole.properties exists + if [ ! -e "$GUACAMOLE_PROPERTIES" ]; then + mkdir -p "$GUACAMOLE_HOME" + echo "# guacamole.properties - generated $(date)" >"$GUACAMOLE_PROPERTIES" + fi + + # Set property + echo "$NAME: $VALUE" >>"$GUACAMOLE_PROPERTIES" + +} + +## +## Sets the given property to the given value within guacamole.properties only +## if a value is provided, creating guacamole.properties first if necessary. +## +## @param NAME +## The name of the property to set. +## +## @param VALUE +## The value to set the property to, if any. If omitted or empty, the +## property will not be set. +## +set_optional_property() { + + NAME="$1" + VALUE="$2" + + # Set the property only if a value is provided + if [ -n "$VALUE" ]; then + set_property "$NAME" "$VALUE" + fi + +} + +# Print error message regarding missing required variables for MySQL authentication +mysql_missing_vars() { + cat <= 40 characters. +## +associate_duo() { + # Verify required parameters are present + if [ -z "$DUO_INTEGRATION_KEY" ] || + [ -z "$DUO_SECRET_KEY" ] || + [ ${#DUO_APPLICATION_KEY} -lt 40 ]; then + cat < element + xmlstarlet edit --inplace \ + --insert '/Server/Service/Engine/Host/*' --type elem -n Valve \ + --insert '/Server/Service/Engine/Host/Valve[not(@className)]' --type attr -n className -v org.apache.catalina.valves.RemoteIpValve \ + $CATALINA_BASE/conf/server.xml + + # Allowed IPs + if [ -z "$PROXY_ALLOWED_IPS_REGEX" ]; then + echo "Using default Tomcat allowed IPs regex" + else + xmlstarlet edit --inplace \ + --insert '/Server/Service/Engine/Host/Valve[@className="org.apache.catalina.valves.RemoteIpValve"]' \ + --type attr -n internalProxies -v "$PROXY_ALLOWED_IPS_REGEX" \ + $CATALINA_BASE/conf/server.xml + fi + + # X-Forwarded-For + if [ -z "$PROXY_IP_HEADER" ]; then + echo "Using default Tomcat proxy IP header" + else + xmlstarlet edit --inplace \ + --insert "/Server/Service/Engine/Host/Valve[@className='org.apache.catalina.valves.RemoteIpValve']" \ + --type attr -n remoteIpHeader -v "$PROXY_IP_HEADER" \ + $CATALINA_BASE/conf/server.xml + fi + + # X-Forwarded-Proto + if [ -z "$PROXY_PROTOCOL_HEADER" ]; then + echo "Using default Tomcat proxy protocol header" + else + xmlstarlet edit --inplace \ + --insert "/Server/Service/Engine/Host/Valve[@className='org.apache.catalina.valves.RemoteIpValve']" \ + --type attr -n protocolHeader -v "$PROXY_PROTOCOL_HEADER" \ + $CATALINA_BASE/conf/server.xml + fi + + # X-Forwarded-By + if [ -z "$PROXY_BY_HEADER" ]; then + echo "Using default Tomcat proxy forwarded by header" + else + xmlstarlet edit --inplace \ + --insert "/Server/Service/Engine/Host/Valve[@className='org.apache.catalina.valves.RemoteIpValve']" \ + --type attr -n remoteIpProxiesHeader -v "$PROXY_BY_HEADER" \ + $CATALINA_BASE/conf/server.xml + fi +} + +## +## Adds api-session-timeout to guacamole.properties +## +associate_apisessiontimeout() { + set_optional_property "api-session-timeout" "$API_SESSION_TIMEOUT" +} + +## +## Starts Guacamole under Tomcat, replacing the current process with the +## Tomcat process. As the current process will be replaced, this MUST be the +## last function run within the script. +## +start_guacamole() { + + # User-only writable CATALINA_BASE + CATALINA_BASE=$HOME/tomcat + CATALINA_HOME=/usr/local/tomcat + export CATALINA_BASE=$HOME/tomcat + export CATALINA_HOME=/usr/local/tomcat + for dir in logs temp webapps work; do + mkdir -p $CATALINA_BASE/$dir + done + cp -R /usr/local/tomcat/conf $CATALINA_BASE + + # Set up Tomcat RemoteIPValve + if [ "$REMOTE_IP_VALVE_ENABLED" = "true" ]; then + enable_remote_ip_valve + fi + + # Install webapp + ln -sf /opt/guacamole/guacamole.war $CATALINA_BASE/webapps/${WEBAPP_CONTEXT:-guacamole}.war + + # Start tomcat + cd /usr/local/tomcat + exec bin/catalina.sh run + +} + +# +# Start with a fresh GUACAMOLE_HOME +# + +rm -Rf "$GUACAMOLE_HOME" + +# +# Copy contents of provided GUACAMOLE_HOME template, if any +# + +if [ -n "$GUACAMOLE_HOME_TEMPLATE" ]; then + cp -a "$GUACAMOLE_HOME_TEMPLATE/." "$GUACAMOLE_HOME/" +fi + +# +# Create and define Guacamole lib and extensions directories +# + +mkdir -p "$GUACAMOLE_EXT" +mkdir -p "$GUACAMOLE_LIB" + +# +# Point to associated guacd +# + +# Use linked container for guacd if specified +if [ -n "$GUACD_NAME" ]; then + GUACD_HOSTNAME="$GUACD_PORT_4822_TCP_ADDR" + GUACD_PORT="$GUACD_PORT_4822_TCP_PORT" +fi + +# Use default guacd port if none specified +GUACD_PORT="${GUACD_PORT-4822}" + +# Verify required guacd connection information is present +if [ -z "$GUACD_HOSTNAME" -o -z "$GUACD_PORT" ]; then + cat </dev/null) + if [[ "$(echo $?)" == "1" ]]; then + echo "Database already exists" + /usr/bin/mariadb -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE -h $MYSQL_HOSTNAME --port $MYSQL_PORT <$i + break + else + echo "MYSQL database automaticaly initialized." + fi + done +fi + +# +# Finally start Guacamole (under Tomcat) +# + +start_guacamole