wise-coders / dbschema

DbSchema Database Designer
https://dbschema.com
78 stars 3 forks source link

Can't run `DbSchema` headlessly in `Docker` container #132

Closed LuchoTurtle closed 1 month ago

LuchoTurtle commented 2 months ago

Hey DbSchema team!

Thank you for the neat application!

I'm having trouble running DbSchema 9.6.2 headlessly in a Docker container. I've tried doing this in all OS (Windows, Mac or Linux) but I keep stumbling upon the same error:

java.lang.ClassNotFoundException: com.sun.glass.ui.monocle.MonoclePlatformFactory
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:421)
    at java.base/java.lang.Class.forName(Class.java:412)
    at javafx.graphics/com.sun.glass.ui.PlatformFactory.getPlatformFactory(PlatformFactory.java:42)
    at javafx.graphics/com.sun.glass.ui.Application.run(Application.java:146)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.java:290)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:292)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:162)
    at javafx.swing/javafx.embed.swing.JFXPanel.initFx(JFXPanel.java:247)
    at javafx.swing/javafx.embed.swing.JFXPanel.<init>(JFXPanel.java:263)
    at com.wisecoders.dbs.scripting.ScriptEngine.<init>(ScriptEngine.java:44)
    at com.wisecoders.dbs.DbSchema.main(DbSchema.java:99)
Failed to load Glass factory class
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.sun.glass.ui.PlatformFactory.createApplication()" because the return value of "com.sun.glass.ui.PlatformFactory.getPlatformFactory()" is null
    at javafx.graphics/com.sun.glass.ui.Application.run(Application.java:146)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.java:290)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:292)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:162)
    at javafx.swing/javafx.embed.swing.JFXPanel.initFx(JFXPanel.java:247)
    at javafx.swing/javafx.embed.swing.JFXPanel.<init>(JFXPanel.java:263)
    at com.wisecoders.dbs.scripting.ScriptEngine.<init>(ScriptEngine.java:44)
    at com.wisecoders.dbs.DbSchema.main(DbSchema.java:99)

I've tried following all the steps in any issues/stack overflow links that I can find regarding this issue (it's obviously an JavaFX/TestFX issue):

But none of these work ☹️ .

I also made sure to build the monocle.jar properly and placed it in the lib folder, as shown in your docs. I tried this with all JDKs (8, 11, 17 and 21) and no luck (according to the .txt after downloading the installer, you preferably use JDK 11).

Dockerfile

# Use a recent Ubuntu LTS base image
FROM --platform=linux/amd64 ubuntu:18.04

# Set environment variables
ENV HOME=/home/dbschema
ENV USER=dbschema

# Create a non-root user
RUN useradd --create-home --home-dir "$HOME" "$USER"

# Copy DbSchema files to the container (assuming you have DbSchema in the build context)
COPY DbSchema $HOME/dbs
COPY openjfx-monocle-11.0.2.jar $HOME/dbs/lib/openjfx-monocle-11.0.2.jar
RUN chown -R "$USER:$USER" "$HOME/dbs"

# Switch to the non-root user
USER $USER

# Set the working directory
WORKDIR $HOME

# Copy an example Groovy script (replace with actual script or add dynamically)
# Assume the example script is named example_script.groovy and in the same directory as the Dockerfile
COPY example_script.groovy $HOME/example_script.groovy

# Set the entry point to run DbSchema in headless mode with the example script
ENTRYPOINT ["./dbs/jre/bin/java", "-Djava.awt.headless=true", "-Dglass.platform=Monocle", "-Dmonocle.platform=Headless", "-Dprism.order=sw", "-cp", "./dbs/lib/*", "com.wisecoders.dbs.DbSchema", "-x", "./example_script.groovy"]

I created a Makefile to make all the building easier.

# Define variables
DOCKERUSER = userino

MAJOR = 9
MINOR = 6
PATCH = 2

DBSCHEMA_TAR = dbschema_$(MAJOR)_$(MINOR)_$(PATCH).tar.gz
DBSCHEMA_URL = https://www.dbschema.com/download/DbSchema_unix_$(MAJOR)_$(MINOR)_$(PATCH).tar.gz

# Default target
all: download extract build

# Download thesudo make DbSchema tar.gz file if it doesn't exist
download:
    if [ ! -f $(DBSCHEMA_TAR) ]; then \
        curl -L $(DBSCHEMA_URL) --output $(DBSCHEMA_TAR); \
    fi

# Extract the downloaded tar.gz file
extract: $(DBSCHEMA_TAR)
    tar xvf $(DBSCHEMA_TAR)

# Build the Docker image
build:
    docker build -t "$(DOCKERUSER)/dbschema:v$(MAJOR).$(MINOR).$(PATCH)" .

# Clean up downloaded files (optional)
clean:
    rm -f $(DBSCHEMA_TAR)
    rm -rf DbSchema

.PHONY: all download extract build clean

[!NOTE] I created a .zip file with my attempts. You can just download and run make to get everything to the point where I'm at - attempts.zip.

I'm stumped on what this could be. All the dependencies should be there, I'm using the jre provided by the installer and I've correctly built the monocle.jar file from https://github.com/TestFX/Monocle. I'm also running the exact same command as cited in the docs but it's still yielding the same error 😭 (I've tried different variations of this command, using glass, still the same result).

Is there a missing dependency I'm failing to see? I can't find any info anywhere. https://dbschema.com/download.html states all the dependencies are in-built, so this shouldn't be a problem.

wise-coders commented 2 months ago

Thank you for trying this! Some time ago a developer was working on this, currently he is no longer part of our team. Some scripts are here: https://dbschema.com/documentation/dbschemacli.html#docker Please check this first. If you wish, please contact us on our support email, and we can plan a web meeting. If you succeed with the script, please send us a copy.

LuchoTurtle commented 1 month ago

Thanks for replying :)

I had tried the Dockerfile that you've linked there, I just didn't link it because downloading the .deb file would take a lot of space. Unfortunately, it still didn't work. Following the steps in the given Dockerfile.

# DESCRIPTION:    Image with DbSchema
# TO_BUILD:       docker build -t amcorreia/docker-dbschema .
# TO_RUN:         docker run -d --rm -it  -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY --name dbschema amcorreia/docker-dbschema

Spawned and crashed the container instantly. I can't even docker logs it because it was immediately deleted. I tried building the image and running through Docker Desktop but I got an error too 😦 :

2024-09-10 02:19:54 Trace/breakpoint trap
2024-09-10 02:19:54 Sep 10, 2024 1:19:54 AM com.sun.javafx.application.PlatformImpl startup
2024-09-10 02:19:54 WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @9765753'
2024-09-10 02:19:54 Loading library prism_es2 from resource failed: java.lang.UnsatisfiedLinkError: /home/user/.openjfx/cache/18.0.1+2/libprism_es2.so: /home/user/.openjfx/cache/18.0.1+2/libprism_es2.so: cannot open shared object file: No such file or directory (Possible cause: can't load AMD 64 .so on a AARCH64 platform)
2024-09-10 02:19:54 java.lang.UnsatisfiedLinkError: /home/user/.openjfx/cache/18.0.1+2/libprism_es2.so: /home/user/.openjfx/cache/18.0.1+2/libprism_es2.so: cannot open shared object file: No such file or directory (Possible cause: can't load AMD 64 .so on a AARCH64 platform)
2024-09-10 02:19:54     at java.base/jdk.internal.loader.NativeLibraries.load(Native Method)

The only related issue I found was https://github.com/realm/realm-kotlin/issues/1010, which wasn't really helpful. I'm a bit stumped on what else I can try πŸ˜…

wise-coders commented 1 month ago

I assume the first solution, you did, is better. Right now we are missing the knowledge in docker containers. I found the monocle.jar on maven central: https://search.maven.org/artifact/org.testfx/openjfx-monocle/21.0.2/pom There is a download button up-right.

Asking ChatGPT I got the answer below. Please try this first. If this is not working, we can schedule a web call and check together.

i try to dockerize a javafx application, and i am receiving: java.lang.classnotfoundexception: com.sun.glass.ui.monocle.monocleplatformfactory Copilot Sent by Copilot:

JavaFX JavaFX Explore It sounds like you’re encountering an issue related to the Monocle platform when trying to run your JavaFX application in a Docker container. This error typically occurs because the Monocle platform, which is used for headless JavaFX applications, isn’t included in your Docker image.

Here are a few steps you can take to resolve this issue:

Include Monocle in Your Docker Image: Ensure that the Monocle JAR is included in your Docker image. You can add it to your Dockerfile like this: FROM openjdk:17-jdk COPY path/to/monocle.jar /app/libs/ COPY path/to/yourapp.jar /app/ WORKDIR /app CMD ["java", "-cp", "libs/monocle.jar:yourapp.jar", "your.main.Class"]

Set the Monocle Platform: You need to set the Monocle platform when running your application. You can do this by adding the following JVM argument: -Dglass.platform=Monocle -Dmonocle.platform=Headless

Check JavaFX Modules: Ensure that the necessary JavaFX modules are included. If you’re using Java 11 or later, you might need to explicitly add the required modules: FROM openjdk:17-jdk RUN apt-get update && apt-get install -y openjfx COPY path/to/yourapp.jar /app/ WORKDIR /app CMD ["java", "--module-path", "/usr/share/openjfx/lib", "--add-modules", "javafx.controls,javafx.graphics", "-cp", "yourapp.jar", "your.main.Class"]

Use a Compatible Base Image: Make sure your base image supports GUI applications. For example, you might use an Ubuntu base image and install the necessary libraries: FROM ubuntu:20.04 RUN apt-get update && apt-get install -y openjdk-17-jdk openjfx COPY path/to/yourapp.jar /app/ WORKDIR /app CMD ["java", "--module-path", "/usr/share/openjfx/lib", "--add-modules", "javafx.controls,javafx.graphics", "-cp", "yourapp.jar", "your.main.Class"]

These steps should help you resolve the java.lang.ClassNotFoundException:

LuchoTurtle commented 1 month ago

Thanks for sharing the Maven link. The monocle.jar files there should be the same ones that I built from https://github.com/TestFX/Monocle. I still used downloaded and used them regardless. Even with the changes on each suggestion, the error is still the same :(

I've been using the in-built java binary that comes with the installer. I did change it to use the one from FROM openjdk:17-jdk but the error still pops up.

The lat suggestion deals with javafx, a GUI library, which is redundant in this case because I'm wanting to run it headless.

πŸ€”

wise-coders commented 1 month ago

This means the error is still this one: java.lang.ClassNotFoundException: com.sun.glass.ui.monocle.MonoclePlatformFactory ? Could you please open the monocle.jar file with a zip explorer? Is the class com.sun.glass.ui.monocle.MonoclePlatformFactory present? If yes, it means is a classpath issue.

LuchoTurtle commented 1 month ago

Hm... Just ran jar -tf openjfx-monocle-11.0.2.jar and it yielded the following.

META-INF/
META-INF/MANIFEST.MF
com/
com/sun/
com/sun/glass/
com/sun/glass/ui/
com/sun/glass/ui/monocle/
com/sun/glass/ui/monocle/LookaheadTouchFilter$1.class
com/sun/glass/ui/monocle/HeadlessPlatformFactory.class
com/sun/glass/ui/monocle/MonocleApplication$1.class
com/sun/glass/ui/monocle/LinuxKeyProcessor.class
com/sun/glass/ui/monocle/MX6PlatformFactory.class
com/sun/glass/ui/monocle/X$XDisplay.class
com/sun/glass/ui/monocle/MonocleDnDClipboard.class
com/sun/glass/ui/monocle/MonocleCursor.class
com/sun/glass/ui/monocle/MonoclePixels.class
com/sun/glass/ui/monocle/LinuxAbsoluteInputCapabilities.class
com/sun/glass/ui/monocle/SysFS.class
com/sun/glass/ui/monocle/MonocleWindowManager$1.class
com/sun/glass/ui/monocle/MouseInputSynthesizer.class
com/sun/glass/ui/monocle/X11InputDeviceRegistry$1.class
com/sun/glass/ui/monocle/LinuxArch.class
com/sun/glass/ui/monocle/LinuxInput.class
com/sun/glass/ui/monocle/HeadlessScreen.class
com/sun/glass/ui/monocle/C.class
com/sun/glass/ui/monocle/UdevListener.class
com/sun/glass/ui/monocle/AndroidInputDeviceRegistry.class
com/sun/glass/ui/monocle/LinuxSystem.class
com/sun/glass/ui/monocle/MonocleRobot$1.class
com/sun/glass/ui/monocle/DispmanPlatform.class
com/sun/glass/ui/monocle/X11AcceleratedScreen.class
com/sun/glass/ui/monocle/HeadlessPlatform.class
com/sun/glass/ui/monocle/LinuxEventBuffer$EventStruct32Bit.class
com/sun/glass/ui/monocle/VNCPlatform$1$1.class
com/sun/glass/ui/monocle/X11WarpingCursor.class
com/sun/glass/ui/monocle/MonocleClipboardDelegate.class
com/sun/glass/ui/monocle/LookaheadTouchFilter.class
com/sun/glass/ui/monocle/LinuxFrameBuffer.class
com/sun/glass/ui/monocle/LinuxTouchProcessor.class
com/sun/glass/ui/monocle/X$XClientMessageEvent.class
com/sun/glass/ui/monocle/MouseInput.class
com/sun/glass/ui/monocle/VNCScreen$ConnectionAccepter.class
com/sun/glass/ui/monocle/VNCPlatformFactory.class
com/sun/glass/ui/monocle/Udev$1.class
com/sun/glass/ui/monocle/X11PlatformFactory.class
com/sun/glass/ui/monocle/OMAPCursor.class
com/sun/glass/ui/monocle/GLException.class
com/sun/glass/ui/monocle/GetEvent.class
com/sun/glass/ui/monocle/MouseState.class
com/sun/glass/ui/monocle/DispmanScreen.class
com/sun/glass/ui/monocle/MX6Cursor$MXCFBGblAlpha.class
com/sun/glass/ui/monocle/LookaheadTouchFilter$FilterState.class
com/sun/glass/ui/monocle/AndroidPlatform.class
com/sun/glass/ui/monocle/InputDeviceRegistry.class
com/sun/glass/ui/monocle/X.class
com/sun/glass/ui/monocle/VNCPlatform$1.class
com/sun/glass/ui/monocle/MonocleTrace.class
com/sun/glass/ui/monocle/TouchState$Point.class
com/sun/glass/ui/monocle/X11InputDeviceRegistry$MotionProcessor.class
com/sun/glass/ui/monocle/C$Structure.class
com/sun/glass/ui/monocle/MX6Cursor.class
com/sun/glass/ui/monocle/FBDevScreen.class
com/sun/glass/ui/monocle/LinuxInputProcessor$Logger.class
com/sun/glass/ui/monocle/MonocleRobot.class
com/sun/glass/ui/monocle/MonocleSystemClipboard.class
com/sun/glass/ui/monocle/NullCursor.class
com/sun/glass/ui/monocle/X11InputDeviceRegistry$ButtonReleaseProcessor.class
com/sun/glass/ui/monocle/LinuxMouseProcessor.class
com/sun/glass/ui/monocle/LinuxEventBuffer$EventStruct64Bit.class
com/sun/glass/ui/monocle/AndroidScreen.class
com/sun/glass/ui/monocle/DispmanPlatformFactory.class
com/sun/glass/ui/monocle/X11Screen.class
com/sun/glass/ui/monocle/LinuxTouchTransform.class
com/sun/glass/ui/monocle/LinuxKeyBits.class
com/sun/glass/ui/monocle/OMAPX11PlatformFactory.class
com/sun/glass/ui/monocle/MX6Cursor$MXCFBPos.class
com/sun/glass/ui/monocle/X$XSetWindowAttributes.class
com/sun/glass/ui/monocle/SoftwareCursor.class
com/sun/glass/ui/monocle/KeyInput.class
com/sun/glass/ui/monocle/LinuxPlatformFactory.class
com/sun/glass/ui/monocle/MonocleSettings.class
com/sun/glass/ui/monocle/IntSet.class
com/sun/glass/ui/monocle/OMAPScreen.class
com/sun/glass/ui/monocle/LinuxInputProcessor.class
com/sun/glass/ui/monocle/Framebuffer.class
com/sun/glass/ui/monocle/LinuxSystem$FbVarScreenInfo.class
com/sun/glass/ui/monocle/AcceleratedScreen.class
com/sun/glass/ui/monocle/X11Cursor.class
com/sun/glass/ui/monocle/MonocleWindowManager.class
com/sun/glass/ui/monocle/VNCScreen$ClientConnection.class
com/sun/glass/ui/monocle/RunnableQueue.class
com/sun/glass/ui/monocle/TouchPipeline.class
com/sun/glass/ui/monocle/LinuxInputDeviceRegistry.class
com/sun/glass/ui/monocle/TouchState.class
com/sun/glass/ui/monocle/LinuxStatelessMultiTouchProcessor.class
com/sun/glass/ui/monocle/Udev.class
com/sun/glass/ui/monocle/RunnableProcessor$RunLoopControl.class
com/sun/glass/ui/monocle/MonocleTimer.class
com/sun/glass/ui/monocle/LinuxEventBuffer.class
com/sun/glass/ui/monocle/AssignPointIDTouchFilter.class
com/sun/glass/ui/monocle/MonocleTimer$1.class
com/sun/glass/ui/monocle/LinuxEventBuffer$EventStruct.class
com/sun/glass/ui/monocle/MonocleApplication.class
com/sun/glass/ui/monocle/DispmanCursor.class
com/sun/glass/ui/monocle/LinuxPlatform.class
com/sun/glass/ui/monocle/OMAPPlatform.class
com/sun/glass/ui/monocle/AndroidAcceleratedScreen.class
com/sun/glass/ui/monocle/AndroidInputProcessor.class
com/sun/glass/ui/monocle/NativeCursors.class
com/sun/glass/ui/monocle/LinuxEventBuffers.class
com/sun/glass/ui/monocle/LinuxStatefulMultiTouchProcessor.class
com/sun/glass/ui/monocle/X$XColor.class
com/sun/glass/ui/monocle/X$XButtonEvent.class
com/sun/glass/ui/monocle/X11InputDeviceRegistry.class
com/sun/glass/ui/monocle/TouchInput.class
com/sun/glass/ui/monocle/X$XMotionEvent.class
com/sun/glass/ui/monocle/InputDevice.class
com/sun/glass/ui/monocle/MonocleWindow.class
com/sun/glass/ui/monocle/MX6Platform.class
com/sun/glass/ui/monocle/VNCScreen.class
com/sun/glass/ui/monocle/NativeCursor.class
com/sun/glass/ui/monocle/X11Platform.class
com/sun/glass/ui/monocle/LinuxSimpleTouchProcessor.class
com/sun/glass/ui/monocle/AndroidInputDevice.class
com/sun/glass/ui/monocle/EGL.class
com/sun/glass/ui/monocle/LinuxSystem$InputAbsInfo.class
com/sun/glass/ui/monocle/LinuxInputDevice.class
com/sun/glass/ui/monocle/MonocleView.class
com/sun/glass/ui/monocle/OMAPX11Platform.class
com/sun/glass/ui/monocle/MonoclePlatformFactory.class
com/sun/glass/ui/monocle/X$XEvent.class
com/sun/glass/ui/monocle/NativePlatformFactory.class
com/sun/glass/ui/monocle/NearbyPointsTouchFilter.class
com/sun/glass/ui/monocle/NativePlatform.class
com/sun/glass/ui/monocle/DispmanAcceleratedScreen.class
com/sun/glass/ui/monocle/KeyState.class
com/sun/glass/ui/monocle/MX6Cursor$MXCFBColorKey.class
com/sun/glass/ui/monocle/LinuxInputDevice$EventProcessor.class
com/sun/glass/ui/monocle/SmallMoveTouchFilter.class
com/sun/glass/ui/monocle/AndroidPlatformFactory.class
com/sun/glass/ui/monocle/TouchFilter.class
com/sun/glass/ui/monocle/OMAPPlatformFactory.class
com/sun/glass/ui/monocle/NativeScreen.class
com/sun/glass/ui/monocle/MX6AcceleratedScreen.class
com/sun/glass/ui/monocle/X11InputDeviceRegistry$ButtonPressProcessor.class
com/sun/glass/ui/monocle/VNCPlatform.class
com/sun/glass/ui/monocle/RunnableProcessor.class
com/sun/glass/ui/monocle/CursorPointingHandOpaque.raw
com/sun/glass/ui/monocle/CursorClosedHandTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeSouthEastOpaque.raw
com/sun/glass/ui/monocle/CursorResizeUpDownTranslucent.raw
com/sun/glass/ui/monocle/CursorTextOpaque.raw
com/sun/glass/ui/monocle/CursorMoveOpaque.raw
com/sun/glass/ui/monocle/CursorResizeLeftRightTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeDownTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeUpDownOpaque.raw
com/sun/glass/ui/monocle/CursorResizeNorthEastOpaque.raw
com/sun/glass/ui/monocle/CursorResizeDownOpaque.raw
com/sun/glass/ui/monocle/CursorResizeSouthWestOpaque.raw
com/sun/glass/ui/monocle/CursorCrosshairTranslucent.raw
com/sun/glass/ui/monocle/CursorClosedHandOpaque.raw
com/sun/glass/ui/monocle/CursorOpenHandTranslucent.raw
com/sun/glass/ui/monocle/CursorMoveTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeLeftOpaque.raw
com/sun/glass/ui/monocle/CursorResizeUpTranslucent.raw
com/sun/glass/ui/monocle/CursorTextTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeLeftTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeLeftRightOpaque.raw
com/sun/glass/ui/monocle/CursorResizeNorthWestTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeNorthWestOpaque.raw
com/sun/glass/ui/monocle/CursorPointingHandTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeSouthEastTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeRightTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeRightOpaque.raw
com/sun/glass/ui/monocle/CursorDefaultOpaque.raw
com/sun/glass/ui/monocle/CursorDisappearOpaque.raw
com/sun/glass/ui/monocle/CursorWaitOpaque.raw
com/sun/glass/ui/monocle/CursorDefaultTranslucent.raw
com/sun/glass/ui/monocle/CursorOpenHandOpaque.raw
com/sun/glass/ui/monocle/CursorResizeNorthEastTranslucent.raw
com/sun/glass/ui/monocle/CursorResizeSouthWestTranslucent.raw
com/sun/glass/ui/monocle/CursorCrosshairOpaque.raw
com/sun/glass/ui/monocle/CursorResizeUpOpaque.raw
com/sun/glass/ui/monocle/CursorDisappearTranslucent.raw
com/sun/glass/ui/monocle/CursorWaitTranslucent.raw

com/sun/glass/ui/monocle/MonoclePlatformFactory.class is in fact there, so it seems like a classpath issue?

Am I not meant to run with the java binary in the installer?

ENTRYPOINT ["./dbs/jre/bin/java", "-Djava.awt.headless=true", "-Dglass.platform=Monocle", "-Dmonocle.platform=Headless", "-Dprism.order=sw", "-cp", "./dbs/lib/*", "com.wisecoders.dbs.DbSchema", "-x", "./example_script.groovy"]

Or am I missing a configuration in the command? I know for a fact I'm copying the monocle.jar to the folder in my Dockerfile.

COPY DbSchema $HOME/dbs
COPY openjfx-monocle-11.0.2.jar $HOME/dbs/lib/openjfx-monocle-11.0.2.jar
wise-coders commented 1 month ago

Everything look fine. The error is strange: first time javafx.graphics/com.sun.glass.ui.Application.run(Application.java:146) goes through, second time says return value of "com.sun.glass.ui.PlatformFactory.getPlatformFactory()" is null. I assume the error is in Monocle with the Java version. We should create a issue here: https://github.com/TestFX/Monocle/issues Would you like to create an issue or should I do it? Is better that you create, and I subscribe to it.

LuchoTurtle commented 1 month ago

Okay, maybe that's not needed, I think I got it working :)

So, with this Dockerfile:

FROM --platform=linux/amd64 ubuntu:22.04

# Install JDK 17, OpenJFX, and other dependencies
RUN apt update -q && \
    apt install -y -q openjdk-17-jre openjdk-17-jdk-headless wget unzip libgl1-mesa-glx libgl1-mesa-dri

# Download and extract the JavaFX SDK (compatible with JDK 17 version)
RUN wget https://download2.gluonhq.com/openjfx/17.0.2/openjfx-17.0.2_linux-x64_bin-sdk.zip -O /tmp/openjfx.zip && \
    unzip /tmp/openjfx.zip -d /opt && \
    rm /tmp/openjfx.zip

# Set JavaFX environment variable for library path
ENV PATH_TO_FX=/opt/javafx-sdk-17.0.2/lib

# Set environment variables for DbSchema
ENV HOME=/home/dbschema
ENV USER=dbschema

# Create a non-root user
RUN useradd --create-home --home-dir "$HOME" "$USER"

# Copy DbSchema files to the container
COPY DbSchema $HOME/app
COPY openjfx-monocle-17.0.10.jar $HOME/dbs/lib/openjfx-monocle-17.0.10.jar
RUN chown -R "$USER:$USER" "$HOME/app"

# Copy Monocle jar to JavaFX lib directory
RUN cp $HOME/dbs/lib/openjfx-monocle-17.0.10.jar /opt/javafx-sdk-17.0.2/lib/

# Switch to non-root user
USER $USER

# Set the working directory
WORKDIR $HOME

# Copy an example Groovy script
COPY example_script.groovy $HOME/example_script.groovy

# Set the entry point to run DbSchema in headless mode with the example script
ENTRYPOINT ["java", "-Djava.awt.headless=true", "-Dglass.platform=Monocle", "-Dmonocle.platform=Headless", "-Dprism.order=sw", "-Dprism.verbose=true", "-Djavafx.platform=monocle", "--module-path", "/opt/javafx-sdk-17.0.2/lib", "--add-modules", "javafx.controls,javafx.base,javafx.graphics,javafx.swing", "--add-exports=javafx.graphics/com.sun.glass.ui=ALL-UNNAMED", "--add-exports=javafx.graphics/com.sun.javafx.util=ALL-UNNAMED", "--add-exports=javafx.graphics/com.sun.javafx.logging=ALL-UNNAMED", "--add-exports=javafx.base/com.sun.javafx.logging=ALL-UNNAMED", "-cp", "./app/lib/*:/opt/javafx-sdk-17.0.2/lib/openjfx-monocle-17.0.10.jar", "com.wisecoders.dbs.DbSchema", "-x", "./example_script.groovy"]

with this Makefile

# Define variables
DOCKERUSER = user

MAJOR = 9
MINOR = 6
PATCH = 2

DBSCHEMA_TAR = dbschema_$(MAJOR)_$(MINOR)_$(PATCH).tar.gz
DBSCHEMA_URL = https://www.dbschema.com/download/DbSchema_unix_$(MAJOR)_$(MINOR)_$(PATCH).tar.gz

# Default target
all: download extract build

# Download the DbSchema tar.gz file if it doesn't exist
download:
    if [ ! -f $(DBSCHEMA_TAR) ]; then \
        curl -L $(DBSCHEMA_URL) --output $(DBSCHEMA_TAR); \
    fi

# Extract the downloaded tar.gz file
extract: $(DBSCHEMA_TAR)
    tar xvf $(DBSCHEMA_TAR)

# Build the Docker image
build:
    docker build -t "$(DOCKERUSER)/dbschema:v$(MAJOR).$(MINOR).$(PATCH)" .

# Clean up downloaded files (optional)
clean:
    rm -f $(DBSCHEMA_TAR)
    rm -rf DbSchema

.PHONY: all download extract build clean

and having an example_script.groovy and openjfx-monocle-17.0.10.jar on the same folder, I can get it working by running make. It looks a bit "hacky", as I had to tackle each error as I went, but yeah!

The Dockerfile may be verbose, but at least it works. I had to add the modules incrementally and add them to the classpath. When running a simple groovy script that just prints a string ("Hello from DbSchema in headless mode!"), it shows the following in Docker.

WARNING: package com.sun.javafx.logging not in javafx.graphics
Prism pipeline init order: sw 
Using Double Precision Marlin Rasterizer
Using dirty region optimizations
Not using texture mask for primitives
Not forcing power of 2 sizes for textures
Using hardware CLAMP_TO_ZERO mode
Opting in for HiDPI pixel scaling
*** Fallback to Prism SW pipeline
Prism pipeline name = com.sun.prism.sw.SWPipeline
(X) Got class = class com.sun.prism.sw.SWPipeline
Initialized prism pipeline: com.sun.prism.sw.SWPipeline
DbSchema 9.6.2 build 240906

Execute Script './example_script.groovy' as Java Groovy.

 vsync: true vpipe: false
Hello from DbSchema in headless mode!
QuantumRenderer: shutdown

Further questions

The reason I'm wanting to run DbSchema headlessly is because I want to incorporate it into a Github Action workflow to create an HTML5 Documentation ERD diagram and zip it as an artifact. So I have a few questions:

wise-coders commented 1 month ago

Thank you very much for this work and for sending the files. We will include them in the actual Tools / Automation Scripts. Probably the menu and the dialog will be renamed. The next beta update will include them: https://dbschema.com/beta.php If you wish, we can add your name as author in the files. Please let me know.

See a sample script for exporting the Documentation in Tools / Automation Scripts / Documentation / Generate Documentation. Do you own a floating license? We should add a way to make possible to register as client to a given Floating License Server. Now is possible only interactive, from the Help / Registration Dialog. We will add more parameters to the DbSchemaCLI client register command. Tomorrow we will release a beta update with this features under: https://dbschema.com/beta.php Please check the build number, it should be the date from today or tomorrow.

LuchoTurtle commented 1 month ago

You're welcome :) And sure, you can add my username if you want to :D

Okay, will do that. I've just been trying to run this headlessly, so I'll take a gander on the GUI for sample scripts.

Regarding the licensing, I do know that my organization has one, I just need to clarify which type. But if so, could you clarify better how I could run DbSchema headlessly in a Github Action to generate an HTML5 page? Would I need to have a server running in the case of a floating license? In case we do not have a floating license and just have a normal (whicH I don't have access still), would restrictions be lifted by downloading the Pro installer? πŸ‘€

wise-coders commented 1 month ago

Looking for your name I see only LuchoTurtle on GitHub, but I am not sure if this is not an alias?

Floating licenses always require a running server. If you have a normal license, you can use it on two computers. You have to use also the register command from DbSchemaCLI.

LuchoTurtle commented 1 month ago

My name is "Luis Arteiro" but you can use my username or my GH profile URL. Or none at all, it's okay haha.

Yeah, I can see that. In that case, to generate HTML5 docs from Github Actions, I'd need a floating license, is that correct?

wise-coders commented 1 month ago

It will work with any license. Just need to have one.

LuchoTurtle commented 1 month ago

Gotcha, thanks!

LuchoTurtle commented 1 month ago

(oops, closed by mistake. But I'll leave it up to y'all to close it or not).

wise-coders commented 1 month ago

We can close it, reopen it later if needed.

LuchoTurtle commented 1 month ago

@wise-coders hmm, I'm having a bit of trouble connecting to a database when running this headlessly.

You can see the files in https://github.com/dwyl/dbschema-demo/pull/2 where I'm trying to do this with (they're the same as I mentioned in this issue).

My groovy script looks like this:

    Project proj = new Project("sample", "SqlServer");
    println "Project " + proj.getName()

    Connector con = ConnectorManager.createConnector("pg_con","testdb", "localhost", 5432, "org.postgresql.Driver", "postgres", "postgres")
    // HERE SPECIFY THE CONNECTION PASSWORD
    con.setPassword("postgres")

    con.importSchemes( proj, "public")
    for( Schema sch : project.schemas ){
        out.println( "Schema " + sch.getNameWithCatalog() )
        for ( Table table : sch.tables ){
            out.println( "  Table " + table.getName() )
        }
    }

However, when I execute it, I keep getting the following error:

Script failed: Please edit the connection 'pg_con' and press 'Connect'.
The connection is missing the driver.
The driver is downloaded automatically from the DbSchema website when editing the connection.
java.sql.SQLException: Please edit the connection 'pg_con' and press 'Connect'.
The connection is missing the driver.
The driver is downloaded automatically from the DbSchema website when editing the connection.
    at com.wisecoders.dbs.dbms.connect.model.envoy.Envoy.s(Envoy.java:57)
    at com.wisecoders.dbs.dbms.connect.model.envoy.Envoy.a(Envoy.java:135)
    at com.wisecoders.dbs.dbms.Dbms.listSchemasAndCatalogs(Dbms.java:293)
    at com.wisecoders.dbs.dbms.Dbms.loadSchemasAndCatalogs(Dbms.java:272)
    at com.wisecoders.dbs.schema.Connector.importSchemes(Connector.java:830)
    at com.wisecoders.dbs.schema.Connector.importSchemes(Connector.java:815)
    at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
    at Script1.run(Script1.groovy:14)
    at com.wisecoders.dbs.scripting.actions.ScriptFileAction.a(ScriptFileAction.java:58)
    at com.wisecoders.dbs.scripting.ScriptEngine.<init>(ScriptEngine.java:[46](https://github.com/dwyl/dbschema-demo/actions/runs/10850357540/job/30111609344#step:10:47))
    at com.wisecoders.dbs.DbSchema.main(DbSchema.java:97)

I know there needs to be a driver when connecting to a database, which is automatically downloaded when I navigate the GUI. However, my jdbc URL is correct, I'm using the correct path and I know I'm copying the drivers that come with the installer correctly in the Dockerfile:

# Copy drivers to `.DbSchema` directory (assuming the user is "dbschema")
RUN mkdir -p "$HOME/.DbSchema"
COPY DbSchema/drivers $HOME/.DbSchema/drivers/

# Copy drivers to `.DbSchema` directory (per docs)
RUN mkdir -p /home/users/.DbSchema/drivers/
COPY DbSchema/drivers /home/users/.DbSchema/drivers/

According to the docs, the drivers should be under /home/users/.DbSchema/drivers/<rdbms>, which is I'm doing above.

I know that the JDBC string is also correct because it works when I run with the GUI, like so:

image

Is there something I'm missing? I don't know what the code does or where else it downloads the drivers to when I open the GUI and "edit the connection", I can't do that headlessly. The code is not open-source either, so I don't know where else I should place the PostgresSQL driver.

I know for a fact that the drivers are being placed in the directories because I'm inspecting the Docker container locally and I can see the driver files under home/dbschema/.DbSchema/drivers/ (I even added in /home/users/.DbSchema/drivers/, just in case).

I don't know what else to do :/

Any ideas? πŸ‘€

wise-coders commented 1 month ago

Please download and unzip the driver https://dbschema.com/jdbc-drivers/PostgresJdbcDriver.zip to user home .DbSchema/drivers/PostgreSQL.

LuchoTurtle commented 1 month ago

The URL you linked is 404 😒 .

But assuming the driver is the same one that comes with the installer, I mentioned in my comment that I already copy all the drivers from the installer to /home/dbschema/.DbSchema/drivers/ and /home/users/.DbSchema/drivers/ (just in case) inside the docker container.

wise-coders commented 1 month ago

https://dbschema.com/jdbc-drivers/PostgreSQOJdbcDriver.zip and .DbSchema/drivers/PostgreSQL

LuchoTurtle commented 1 month ago

That link doesn't exist, it's 404.

image

And, as previously mentioned, I did add the driver to the path. I've added to three paths, just to check:

Inside each drivers folder, there's a folder for each database driver, including the PostgreSQL.

image

It doesn't work, it still asks for the driver..

wise-coders commented 1 month ago

Please excuse me, I misstyped me few times. Here is it: https://dbschema.com/jdbc-drivers/PostgreSQLJdbcDriver.zip It was a wrong letter in PostgreSQL.

Under drivers, it is one more sub-folder PostgreSQL: .DbSchema/drivers/PostgreSQL

LuchoTurtle commented 1 month ago

Perhaps I wasn't clear in my responses, I'm sorry. The installer that is downloaded already has several drivers, including PostgreSQL. I'm copying all of them under the drivers folder, all the paths that I've mentioned in fact include the PostgreSQL folder, as shown in the pic above. DbSchema doesn't seem to detect any of them :/

wise-coders commented 1 month ago

Agree, but in your list the last folder is 'drivers', and it should be 'PostgreSQL'. Drivers from different databases are landing in different folders.

LuchoTurtle commented 1 month ago

Yes, but I'm copying the drivers folder from the installer (which has the PostgreSQL folder inside it) to the drivers folder within the Docker container in the paths that I've linked above.

image

πŸ˜…

wise-coders commented 1 month ago

We will need some time to debug this issue, probably till end of the week.

Do you get any errors in .DbSchema/logs ? It could be that the error has to do with the .DbSchema/config/dbms and connections folder to do.

LuchoTurtle commented 1 month ago

I don't see any logs folder bring created, unfortunately 😟

Thanks for taking time to look into this πŸ™

wise-coders commented 1 month ago

Please excuse the delays. We added this to Dockerfile and it worked: RUN mkdir -p /home/dbschema/.DbSchema/drivers/PostgreSQL RUN wget https://dbschema.com/jdbc-drivers/PostgreSQLJdbcDriver.zip -O /home/dbschema/.DbSchema/drivers/PostgreSQL/PostgreSQLJdbcDriver.zip && \ unzip /home/dbschema/.DbSchema/drivers/PostgreSQL/PostgreSQLJdbcDriver.zip

LuchoTurtle commented 1 month ago

Thank you for the response :) Can you provide your full Dockerfile? I'm trying to run it like this:

FROM --platform=linux/amd64 ubuntu:22.04

# Install JDK 17, OpenJFX, and other dependencies
RUN apt update -q && \
    apt install -y -q openjdk-17-jre openjdk-17-jdk-headless wget unzip libgl1-mesa-glx libgl1-mesa-dri

# Download and extract the JavaFX SDK (compatible with JDK 17 version)
RUN wget https://download2.gluonhq.com/openjfx/17.0.2/openjfx-17.0.2_linux-x64_bin-sdk.zip -O /tmp/openjfx.zip && \
    unzip /tmp/openjfx.zip -d /opt && \
    rm /tmp/openjfx.zip

# Set JavaFX environment variable for library path and copy Monocle jar to JavaFX lib directory
ENV PATH_TO_FX=/opt/javafx-sdk-17.0.2/lib
COPY openjfx-monocle-17.0.10.jar /opt/javafx-sdk-17.0.2/lib/

# Set environment variables for DbSchema
ENV HOME=/home/dbschema
ENV USER=dbschema

# Create a non-root user
RUN useradd --create-home --home-dir "$HOME" "$USER"

# Copy DbSchema files to the container
COPY DbSchema $HOME/app
COPY openjfx-monocle-17.0.10.jar $HOME/app/lib/openjfx-monocle-17.0.10.jar
RUN chown -R "$USER:$USER" "$HOME/app"

# Copy drivers to `.DbSchema` directory (assuming the user is "dbschema")
RUN mkdir -p /home/dbschema/.DbSchema/drivers/PostgreSQL
RUN wget dbschema.com/jdbc-drivers/PostgreSQLJdbcDriver.zip -O /home/dbschema/.DbSchema/drivers/PostgreSQL/PostgreSQLJdbcDriver.zip && \
    unzip /home/dbschema/.DbSchema/drivers/PostgreSQL/PostgreSQLJdbcDriver.zip

# Switch to non-root user
USER $USER

# Set the working directory
WORKDIR $HOME

# Copy an example Groovy script
COPY example_script.groovy $HOME/example_script.groovy

# Create the script that runs DbSchema and propagates the exit code
RUN echo '#!/bin/sh\n' \
    'set -e\n' \
    'java -Djava.awt.headless=true -Dglass.platform=Monocle -Dmonocle.platform=Headless -Dprism.order=sw -Dprism.verbose=true -Djavafx.platform=monocle --module-path /opt/javafx-sdk-17.0.2/lib --add-modules javafx.controls,javafx.base,javafx.graphics,javafx.swing --add-exports=javafx.graphics/com.sun.glass.ui=ALL-UNNAMED --add-exports=javafx.graphics/com.sun.javafx.util=ALL-UNNAMED --add-exports=javafx.graphics/com.sun.javafx.logging=ALL-UNNAMED --add-exports=javafx.base/com.sun.javafx.logging=ALL-UNNAMED -cp ./app/lib/*:/opt/javafx-sdk-17.0.2/lib/openjfx-monocle-17.0.10.jar com.wisecoders.dbs.DbSchema -x ./example_script.groovy\n' \
    'EXIT_CODE=$?\n' \
    'if [ $EXIT_CODE -ne 0 ]; then\n' \
    '  echo "Script execution failed with exit code $EXIT_CODE."\n' \
    '  exit $EXIT_CODE\n' \
    'else\n' \
    '  echo "Script executed successfully."\n' \
    '  exit 0\n' \
    'fi' > /home/dbschema/run_dbschema.sh

# Make the script executable
RUN chmod +x /home/dbschema/run_dbschema.sh

# Modify the entry point to use the shell script
ENTRYPOINT ["sh", "/home/dbschema/run_dbschema.sh"]

And this Groovy script:

import com.wisecoders.dbs.schema.*

try {
    Project proj = new Project("sample", "SqlServer");
    println "Project " + proj.getName()

    Connector con = ConnectorManager.createConnector("pg_con","testdb", "localhost", 5432, "org.postgresql.Driver", "postgres", "postgres")
    // HERE SPECIFY THE CONNECTION PASSWORD
    con.setPassword("postgres")

    con.importSchemes( proj, "public")
    for( Schema sch : project.schemas ){
        out.println( "Schema " + sch.getNameWithCatalog() )
        for ( Table table : sch.tables ){
            out.println( "  Table " + table.getName() )
        }
    }

} 
// Ensure the script exits with a non-zero status on failure
catch (Exception e) {
    println "Script failed: ${e.message}"
    e.printStackTrace()
    System.exit(1)  
}

// Explicitly exit with 0 if the script succeeds
System.exit(0)

at https://github.com/dwyl/dbschema-demo/pull/2 and it fails https://github.com/dwyl/dbschema-demo/actions/runs/10977992520/job/30480602086?pr=2 πŸ€”

Did you run it locally? It's not working on the Github Action (when it should, according to you guys πŸ˜„ )

wise-coders commented 1 month ago

Please check the beta update from today ( please check the build number, it should be from today ): https://dbschema.com/beta.php Check in menu Manage/ Java Plugins / Docker

We fail on makefile, we are getting an error: make -f Makefile all make: Makefile: No such file or directory make: *** No rule to make target 'Makefile'. Stop.

Probably the Makefile is not in the expected location. Any idea is appreciated.

For debugging, please include a println System.getProperty("user.home"). You can also list the content of the folder, something like: import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.stream.Stream;

String userHome = System.getProperty("user.home"); Path homePath = Paths.get(userHome).resolve("/.DbSchema/drivers/PostgreSQL");

try (Stream paths = Files.list(homePath)) { paths.filter(Files::isRegularFile) .forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); }

LuchoTurtle commented 1 month ago
String userHome = System.getProperty("user.home");
Path homePath = Paths.get(userHome).resolve("/.DbSchema/drivers/PostgreSQL");

And it prints /.DbSchema/drivers/PostgreSQL/postgresql-42.7.3.jar. So, this means that the files are being copied and sent to the correct place, right? Unless the driver file is not being properly detected in headless mode. I can't see the code, so there's not much I can do to help debug this :(

wise-coders commented 1 month ago

I think the problem is the slash before .DbSchema. Probably it thinks this is root, and it does not resolve relative but absolute. I expect to print /home/youUser/.DbSchema....

LuchoTurtle commented 1 month ago

We'd need to know how you fetch the drivers in your source code. I've tried tinkering with the HOME variable in my dockerfile loads amount of times and I've inclusively set the user.home property inside the groovy script to make sure that's the case.

    System.getProperties().setProperty("user.home", "/home/dbschema/"); // set `user.home` here
    String userHome = System.getProperty("user.home");
    System.out.println(userHome);
    Path homePath = Paths.get(userHome).resolve(".DbSchema/drivers/PostgreSQL");

    try (Stream paths = Files.list(homePath)) {
        paths.filter(Files::isRegularFile).forEach(System.out::println);
    } catch (IOException e) {
        e.printStackTrace();
    }

This prints:

/home/dbschema/
/home/dbschema/.DbSchema/drivers/PostgreSQL/postgresql-42.7.3.jar
Project sample
Script failed: Please edit the connection 'pg_con' and press 'Connect'.
The connection is missing the driver.
The driver is downloaded automatically from the DbSchema website when editing the connection.
java.sql.SQLException: Please edit the connection 'pg_con' and press 'Connect'.
The connection is missing the driver.

As you can see, /home/dbschema exists and in the loop of homePath, it prints the driver. So the driver is there. Unless setting the property doesn't really affect DbSchema's internal code.

Then again, I'm blind because I don't know how y'all implemented this. How are you locating the drivers in your source code? πŸ‘€

wise-coders commented 1 month ago

We are also reading the variable System.getProperty("user.home"), but at the very beginning of DbSchema code. Maybe give it a try and copy the drivers in /.DbSchema/drivers/PostgreSQL ?

LuchoTurtle commented 1 month ago

Thanks for the quick feedback :)

That's what I've already been doing. In my Dockerfile, I've been copying the drivers folder in every possible location that I think it may work, including /.DbSchema/drivers/.

RUN mkdir -p /.DbSchema/drivers/
COPY DbSchema/drivers /.DbSchema/drivers/

If you also use System.getProperty("user.home") in your source code and setProperty doesn't get propagated, maybe it's the way the DbSchema is invoked? Which is weird, because I've even tried calling it from the root of the file directory within the Docker container already and it did nothing, either.

Maybe I should try to scrap the Dockerfile and try another approach, I think I've exhausted all possible scenarios.

wise-coders commented 1 month ago

Can you please search on the virtual machine for a folder .DbSchema/drivers ? DbSchema will create this folder at startup, if is not existing. Something is wired.

LuchoTurtle commented 1 month ago

.DbSchema/drivers is correctly populated, according to the Dockerfile.

# Copy drivers to `.DbSchema` directory (per docs) LAST ATTEMPT
RUN mkdir -p /.DbSchema/drivers/
COPY DbSchema/drivers /.DbSchema/drivers/
image

It's most likely the way I'm running the DbSchema binary. Perhaps the way it's called makes it so that the home directory is not defined? πŸ‘€

wise-coders commented 1 month ago

DbSchema creates automatically the .DbSchema/drivers at startup. Start the container one time without creating this folder nor the drivers, and do a find to check were it was created.

LuchoTurtle commented 1 month ago

Hmm, okay.

So here's the Dockerfile I tried. Pretty much the same but I didn't copy the drivers in any place.

FROM --platform=linux/amd64 ubuntu:22.04

# Install JDK 17, OpenJFX, and other dependencies
RUN apt update -q && \
    apt install -y -q openjdk-17-jre openjdk-17-jdk-headless wget unzip libgl1-mesa-glx libgl1-mesa-dri

# Download and extract the JavaFX SDK (compatible with JDK 17 version)
RUN wget https://download2.gluonhq.com/openjfx/17.0.2/openjfx-17.0.2_linux-x64_bin-sdk.zip -O /tmp/openjfx.zip && \
    unzip /tmp/openjfx.zip -d /opt && \
    rm /tmp/openjfx.zip

# Set JavaFX environment variable for library path and copy Monocle jar to JavaFX lib directory
ENV PATH_TO_FX=/opt/javafx-sdk-17.0.2/lib
COPY openjfx-monocle-17.0.10.jar /opt/javafx-sdk-17.0.2/lib/

# Set environment variables for DbSchema
ENV HOME=/home/dbschema
ENV USER=dbschema

# Create a non-root user
RUN useradd --create-home --home-dir "$HOME" "$USER"

# Copy DbSchema files to the container
COPY DbSchema $HOME/app
COPY openjfx-monocle-17.0.10.jar $HOME/app/lib/openjfx-monocle-17.0.10.jar
RUN chown -R "$USER:$USER" "$HOME/app"

# Copy drivers to `.DbSchema` directory (assuming the user is "dbschema")
#RUN mkdir -p "$HOME/.DbSchema"
#COPY DbSchema/drivers $HOME/.DbSchema/drivers/
#
## Copy drivers to `.DbSchema` directory (per docs)
#RUN mkdir -p /home/users/.DbSchema/drivers/
#COPY DbSchema/drivers /home/users/.DbSchema/drivers/
#
## Copy drivers to `.DbSchema` directory (per docs) LAST ATTEMPT
#RUN mkdir -p /.DbSchema/drivers/
#COPY DbSchema/drivers /.DbSchema/drivers/
#
## Copy drivers to `.DbSchema` directory (another directory)
#RUN mkdir -p .DbSchema/drivers/
#COPY DbSchema/drivers .DbSchema/drivers/

# Set correct ownership for the dbschema user
RUN chown -R dbschema:dbschema /home/dbschema
# Switch to non-root user
USER $USER

# Set the working directory
WORKDIR $HOME

# Copy an example Groovy script
COPY example_script.groovy $HOME/example_script.groovy

# Create the script that runs DbSchema and propagates the exit code
RUN echo '#!/bin/sh\n' \
    'set -e\n' \
    'java -Djava.awt.headless=true -Dglass.platform=Monocle -Dmonocle.platform=Headless -Dprism.order=sw -Dprism.verbose=true -Djavafx.platform=monocle --module-path /opt/javafx-sdk-17.0.2/lib --add-modules javafx.controls,javafx.base,javafx.graphics,javafx.swing --add-exports=javafx.graphics/com.sun.glass.ui=ALL-UNNAMED --add-exports=javafx.graphics/com.sun.javafx.util=ALL-UNNAMED --add-exports=javafx.graphics/com.sun.javafx.logging=ALL-UNNAMED --add-exports=javafx.base/com.sun.javafx.logging=ALL-UNNAMED -cp /home/dbschema/app/lib/*:/opt/javafx-sdk-17.0.2/lib/openjfx-monocle-17.0.10.jar com.wisecoders.dbs.DbSchema -x  /home/dbschema/example_script.groovy\n' \
    'EXIT_CODE=$?\n' \
    'if [ $EXIT_CODE -ne 0 ]; then\n' \
    '  echo "Script execution failed with exit code $EXIT_CODE."\n' \
    '  exit $EXIT_CODE\n' \
    'else\n' \
    '  echo "Script executed successfully."\n' \
    '  exit 0\n' \
    'fi' > /home/dbschema/run_dbschema.sh

# Make the script executable
RUN chmod +x /home/dbschema/run_dbschema.sh

RUN sh /home/dbschema/run_dbschema.sh

# Modify the entry point to use the shell script
#ENTRYPOINT ["sh", "/home/dbschema/run_dbschema.sh"]
CMD ["tail", "-f", "/dev/null"]

[!NOTE]

CMD ["tail", "-f", "/dev/null"] is only used so the container doesn't exit instantly.

.DbSchema/drivers don't appear to be in any directory (I've checked each one individually). It's not being created when executing DbSchema, it seems πŸ€”

image
wise-coders commented 4 weeks ago

Could you please add in the code this line: com.wisecoders.dbs.cli.command.connectivity.DownloadDriverCommand.downloadDriver("PostgreSQL") Please use a fresh copy of DbSchema - it will get a hotpatch on website by tomorrow morning.

LuchoTurtle commented 3 weeks ago

Thank you for sticking up with this :)

I have a feeling that there must be something wrong with how you check the driver in your code. Do you use System.getProperty("user.home")?

I've added your com.wisecoders.dbs.cli.command.connectivity.DownloadDriverCommand.downloadDriver("PostgreSQL") line but it still fails with the same error that I need to download the driver.

Here's how my Groovy script looks like:

    com.wisecoders.dbs.cli.command.connectivity.DownloadDriverCommand.downloadDriver("PostgreSQL")

    String userHome = System.getProperty("user.home");
    println("userHome: " + userHome)

    Path homePath = Paths.get(userHome).resolve(".DbSchema/drivers/PostgreSQL");;
    try (Stream paths = Files.list(homePath)) {
        paths.filter(Files::isRegularFile).forEach(System.out::println);
    } 

    // the rest

It prints:

 userHome: /home/dbschema
/home/dbschema/.DbSchema/drivers/PostgreSQL/postgresql-42.7.3.jar

So, userHome is defined inside /home/dbschema and the path /home/dbschema/.DbSchema/drivers/PostgreSQL/postgresql-42.7.3.jar does exist. This is where DbSchema should look for drivers, theoretically. Or am I wrong? How do you check for the driver location?

wise-coders commented 2 weeks ago

Now I found the problem. It is in the script, this line should contain dbId 'PostgreSQL', case sensitive. Connector con = ConnectorManager.createConnector("pg_con","PostgreSQL",

We will improve also the error message, to make clear the DBMS name.

LuchoTurtle commented 2 weeks ago

Thank you so much for responding!

That may have been it! The error is different (it says the connection is returning NULL), but that's probably me having trouble connecting the DbSchema running on the container to my localhost instance of PostgreSQL database.

It says this:

 Script failed: Error connecting to database. Got NULL connection.
 Please report this issue to technicians using Help / Technical Support.
 java.sql.SQLException: Error connecting to database. Got NULL connection.
 Please report this issue to technicians using Help / Technical Support.
        at com.wisecoders.dbs.dbms.connect.model.envoy.Envoy.s(Envoy.java:102)
        at com.wisecoders.dbs.dbms.connect.model.envoy.Envoy.a(Envoy.java:134)
        at com.wisecoders.dbs.dbms.Dbms.listSchemasAndCatalogs(Dbms.java:294)
        at com.wisecoders.dbs.dbms.Dbms.loadSchemasAndCatalogs(Dbms.java:273)
        at com.wisecoders.dbs.schema.Connector.importSchemes(Connector.java:831)
        at com.wisecoders.dbs.schema.Connector.importSchemes(Connector.java:815)
        at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
        at Script1.run(Script1.groovy:28)
        at com.wisecoders.dbs.scripting.actions.ScriptFileAction.a(ScriptFileAction.java:58)
        at com.wisecoders.dbs.scripting.ScriptEngine.<init>(ScriptEngine.java:46)
        at com.wisecoders.dbs.DbSchema.main(DbSchema.java:98)

I'm running another container instance that is running PostgreSQL.

services:
  postgres-db:
    image: postgres:14
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - my-network

  app:
    build: .
    depends_on:
      - postgres-db
    networks:
      - my-network
    environment:
      DB_HOST: postgres-db
      DB_USER: postgres
      DB_PASSWORD: postgres
      DB_NAME: postgres
      DB_PORT: 5432
    entrypoint: ["/home/dbschema/wait-for-postgres.sh"]

volumes:
  postgres-data:

networks:
  my-network:

The app service (which builds and executes our Dockerfile) only runs if the PostgreSQL instance is accessible. This is checked with psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c '\q. So, we know for a fact that the PostgreSQL database is reachable from app because it only executes if this command does. And this command only executes successfully if it can connect to the PostgreSQL.

Maybe it's the JDBCL URL? I've tried connecting with "jdbc::postgresql://postgres-db:5432/postgres" (postgres-db instead of localhost because postgres-db is the name of the service in the docker-compose.yml file) and it still has trouble connecting.

What is the piece of code that y'all connect to the database? πŸ€” I'm trying to debug.

Thanks! ❀️

wise-coders commented 2 weeks ago

The JDBC URL should use the same host as $DB_HOST. But I assume the error is not from the wrong host. Usually is would throw a different exception. Check also the PostgreSQL logs. One possible reason is that you have to enable remote connectivity in PostgreSQL. https://dbschema.com/documentation/postgresql/#remote

Please let me know if you can find out which is the reason. Maybe we can improve our error messages.

LuchoTurtle commented 1 week ago

Thank you! I've found the error and fixed it!

I'm working on this in https://github.com/dwyl/dbschema-demo/pull/2 and it's practically done, I'm just going to document the steps next. I see that you are using my code in the Automation Scripts tab in the GUI. The code there is severely outdated and doesn't really work, so I recommend updating to the now-working source code in the linked PR (or just add the Dockerfile example below, whatever's reasonable for you).

image

Here is the working Dockerfile:

FROM --platform=linux/amd64 ubuntu:22.04

# Install JDK 17, OpenJFX, and other dependencies
RUN apt update -q && \
    apt install -y -q openjdk-17-jre openjdk-17-jdk-headless wget unzip libgl1-mesa-glx libgl1-mesa-dri postgresql-client

# Download and extract the JavaFX SDK (compatible with JDK 17 version, required by DbSchema)
RUN wget https://download2.gluonhq.com/openjfx/17.0.2/openjfx-17.0.2_linux-x64_bin-sdk.zip -O /tmp/openjfx.zip && \
    unzip /tmp/openjfx.zip -d /opt && \
    rm /tmp/openjfx.zip

# Set JavaFX environment variable for library path and copy Monocle jar to JavaFX lib directory
ENV PATH_TO_FX=/opt/javafx-sdk-17.0.2/lib
COPY openjfx-monocle-17.0.10.jar $PATH_TO_FX/

# Set work directory to `/home/dbschema` - DbSchema's home directory
WORKDIR /home/dbschema

# Copy DbSchema installer files to the container
# Copy the monocle jar to the lib directory (as per https://dbschema.com/documentation/dbschemacli.html#docker)
# Copy the example script to the current directory
COPY DbSchema ./app
COPY openjfx-monocle-17.0.10.jar ./app/lib/openjfx-monocle-17.0.10.jar
COPY example_script.groovy .

# Create a simple script that runs DbSchema and propagates the exit code.
# This is done to ensure that the container exits with the correct exit code (if the script fails, the container should fail too).
RUN echo '#!/bin/sh\n' \
    'set -e\n' \
    'java -Djava.awt.headless=true -Dglass.platform=Monocle -Dmonocle.platform=Headless -Dprism.order=sw -Djavafx.platform=monocle --module-path /opt/javafx-sdk-17.0.2/lib --add-modules javafx.controls,javafx.base,javafx.graphics,javafx.swing --add-exports=javafx.graphics/com.sun.glass.ui=ALL-UNNAMED --add-exports=javafx.graphics/com.sun.javafx.util=ALL-UNNAMED --add-exports=javafx.graphics/com.sun.javafx.logging=ALL-UNNAMED --add-exports=javafx.base/com.sun.javafx.logging=ALL-UNNAMED -cp ./app/lib/*:/opt/javafx-sdk-17.0.2/lib/openjfx-monocle-17.0.10.jar com.wisecoders.dbs.DbSchema -x  ./example_script.groovy\n' \
    'EXIT_CODE=$?\n' \
    'if [ $EXIT_CODE -ne 0 ]; then\n' \
    '  echo "Script execution failed with exit code $EXIT_CODE."\n' \
    '  exit $EXIT_CODE\n' \
    'else\n' \
    '  echo "Script executed successfully."\n' \
    '  exit 0\n' \
    'fi' > /home/dbschema/run_dbschema.sh

# Run the script as the entry point
ENTRYPOINT ["sh", "/home/dbschema/run_dbschema.sh"]

# Uncomment to keep the container running after the script execution
#RUN sh /home/dbschema/run_dbschema.sh || true
#CMD ["tail", "-f", "/dev/null"]

Running any Groovy script here should work. This Dockerfile assumes the installer is downloaded and extracted in the same folder. Here is the Makefile to automate that (we only need to run sudo make.

# Define variables
DOCKERUSER = userino

MAJOR = 9
MINOR = 6
PATCH = 3

DBSCHEMA_TAR = dbschema_$(MAJOR)_$(MINOR)_$(PATCH).tar.gz
DBSCHEMA_URL = https://www.dbschema.com/download/DbSchema_unix_$(MAJOR)_$(MINOR)_$(PATCH).tar.gz

# Default target
all: download extract

# Download the DbSchema `tar.gz` file if it doesn't exist
download:
    if [ ! -f $(DBSCHEMA_TAR) ]; then \
        curl -L $(DBSCHEMA_URL) --output $(DBSCHEMA_TAR); \
    fi

# Extract the downloaded `tar.gz` file
extract: $(DBSCHEMA_TAR)
    tar xvf $(DBSCHEMA_TAR)

# Clean up downloaded files (optional)
clean:
    rm -f $(DBSCHEMA_TAR)
    rm -rf DbSchema

.PHONY: all download extract clean

In the aforementioned PR, I have an additional docker-compose that creates a PostgreSQL database (and populates it with a .sql file) and a Groovy script that generates an HTML5 page. This can all be done within a Github Action workflow.

wise-coders commented 1 week ago

Thank you very much for sending the latest files! We are updating them in DbSchema.