V4.1 Prep

Build Path options

added Candle
Added Custom
This commit is contained in:
Joshua Hare 2025-08-27 12:47:16 +10:00
parent f1478561c1
commit 6ae0e56118
8 changed files with 715 additions and 182 deletions

View File

@ -2,57 +2,130 @@
setlocal enabledelayedexpansion setlocal enabledelayedexpansion
REM --- Configuration --- REM --- Configuration ---
set REPO_URL=https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git set REPO_URL_HAPI=https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git
set CLONE_DIR=hapi-fhir-jpaserver set REPO_URL_CANDLE=https://github.com/FHIR/fhir-candle.git
set CLONE_DIR_HAPI=hapi-fhir-jpaserver
set CLONE_DIR_CANDLE=fhir-candle
set SOURCE_CONFIG_DIR=hapi-fhir-setup set SOURCE_CONFIG_DIR=hapi-fhir-setup
set CONFIG_FILE=application.yaml set CONFIG_FILE=application.yaml
REM --- Define Paths --- REM --- Define Paths ---
set SOURCE_CONFIG_PATH=..\%SOURCE_CONFIG_DIR%\target\classes\%CONFIG_FILE% set SOURCE_CONFIG_PATH=..\%SOURCE_CONFIG_DIR%\target\classes\%CONFIG_FILE%
set DEST_CONFIG_PATH=%CLONE_DIR%\target\classes\%CONFIG_FILE% set DEST_CONFIG_PATH=%CLONE_DIR_HAPI%\target\classes\%CONFIG_FILE%
REM === CORRECTED: Prompt for Version === REM --- NEW: Define a variable for the custom FHIR URL and server type ---
set "CUSTOM_FHIR_URL_VAL="
set "SERVER_TYPE="
set "CANDLE_FHIR_VERSION="
REM === MODIFIED: Prompt for Installation Mode ===
:GetModeChoice :GetModeChoice
SET "APP_MODE=" REM Clear the variable first SET "APP_MODE=" REM Clear the variable first
echo.
echo Select Installation Mode: echo Select Installation Mode:
echo 1. Standalone (Includes local HAPI FHIR Server - Requires Git & Maven) echo 1. Lite (Excludes local HAPI FHIR Server - No Git/Maven/Dotnet needed)
echo 2. Lite (Excludes local HAPI FHIR Server - No Git/Maven needed) echo 2. Custom URL (Uses a custom FHIR Server - No Git/Maven/Dotnet needed)
CHOICE /C 12 /N /M "Enter your choice (1 or 2):" echo 3. Hapi (Includes local HAPI FHIR Server - Requires Git & Maven)
echo 4. Candle (Includes local FHIR Candle Server - Requires Git & Dotnet)
CHOICE /C 1234 /N /M "Enter your choice (1, 2, 3, or 4):"
IF ERRORLEVEL 4 (
SET APP_MODE=standalone
SET SERVER_TYPE=candle
goto :GetCandleFhirVersion
)
IF ERRORLEVEL 3 (
SET APP_MODE=standalone
SET SERVER_TYPE=hapi
goto :ModeSet
)
IF ERRORLEVEL 2 ( IF ERRORLEVEL 2 (
SET APP_MODE=standalone
goto :GetCustomUrl
)
IF ERRORLEVEL 1 (
SET APP_MODE=lite SET APP_MODE=lite
goto :ModeSet goto :ModeSet
) )
IF ERRORLEVEL 1 (
SET APP_MODE=standalone
goto :ModeSet
)
REM If somehow neither was chosen (e.g., Ctrl+C), loop back REM If somehow neither was chosen (e.g., Ctrl+C), loop back
echo Invalid input. Please try again. echo Invalid input. Please try again.
goto :GetModeChoice goto :GetModeChoice
:GetCustomUrl
set "CONFIRMED_URL="
:PromptUrlLoop
echo.
set /p "CUSTOM_URL_INPUT=Please enter the custom FHIR server URL: "
echo.
echo You entered: !CUSTOM_URL_INPUT!
set /p "CONFIRM_URL=Is this URL correct? (Y/N): "
if /i "!CONFIRM_URL!" EQU "Y" (
set "CONFIRMED_URL=!CUSTOM_URL_INPUT!"
goto :ConfirmUrlLoop
) else (
goto :PromptUrlLoop
)
:ConfirmUrlLoop
echo.
echo Please re-enter the URL to confirm it is correct:
set /p "CUSTOM_URL_INPUT=Re-enter URL: "
if /i "!CUSTOM_URL_INPUT!" EQU "!CONFIRMED_URL!" (
set "CUSTOM_FHIR_URL_VAL=!CUSTOM_URL_INPUT!"
echo.
echo Custom URL confirmed: !CUSTOM_FHIR_URL_VAL!
goto :ModeSet
) else (
echo.
echo URLs do not match. Please try again.
goto :PromptUrlLoop
)
:GetCandleFhirVersion
echo.
echo Select the FHIR version for the Candle server:
echo 1. R4 (4.0)
echo 2. R4B (4.3)
echo 3. R5 (5.0)
CHOICE /C 123 /N /M "Enter your choice (1, 2, or 3):"
IF ERRORLEVEL 3 (
SET CANDLE_FHIR_VERSION=r5
goto :ModeSet
)
IF ERRORLEVEL 2 (
SET CANDLE_FHIR_VERSION=r4b
goto :ModeSet
)
IF ERRORLEVEL 1 (
SET CANDLE_FHIR_VERSION=r4
goto :ModeSet
)
echo Invalid input. Please try again.
goto :GetCandleFhirVersion
:ModeSet :ModeSet
IF "%APP_MODE%"=="" ( IF "%APP_MODE%"=="" (
echo Invalid choice detected after checks. Exiting. echo Invalid choice detected after checks. Exiting.
goto :eof goto :eof
) )
echo Selected Mode: %APP_MODE% echo Selected Mode: %APP_MODE%
echo Server Type: %SERVER_TYPE%
echo. echo.
REM === END CORRECTION === REM === END MODIFICATION ===
REM === Conditionally Execute HAPI Setup === REM === Conditionally Execute Server Setup ===
IF "%APP_MODE%"=="standalone" ( IF "%SERVER_TYPE%"=="hapi" (
echo Running Standalone setup including HAPI FHIR... echo Running Hapi server setup...
echo. echo.
REM --- Step 0: Clean up previous clone (optional) --- REM --- Step 0: Clean up previous clone (optional) ---
echo Checking for existing directory: %CLONE_DIR% echo Checking for existing directory: %CLONE_DIR_HAPI%
if exist "%CLONE_DIR%" ( if exist "%CLONE_DIR_HAPI%" (
echo Found existing directory, removing it... echo Found existing directory, removing it...
rmdir /s /q "%CLONE_DIR%" rmdir /s /q "%CLONE_DIR_HAPI%"
if errorlevel 1 ( if errorlevel 1 (
echo ERROR: Failed to remove existing directory: %CLONE_DIR% echo ERROR: Failed to remove existing directory: %CLONE_DIR_HAPI%
goto :error goto :error
) )
echo Existing directory removed. echo Existing directory removed.
@ -62,8 +135,8 @@ IF "%APP_MODE%"=="standalone" (
echo. echo.
REM --- Step 1: Clone the HAPI FHIR server repository --- REM --- Step 1: Clone the HAPI FHIR server repository ---
echo Cloning repository: %REPO_URL% into %CLONE_DIR%... echo Cloning repository: %REPO_URL_HAPI% into %CLONE_DIR_HAPI%...
git clone "%REPO_URL%" "%CLONE_DIR%" git clone "%REPO_URL_HAPI%" "%CLONE_DIR_HAPI%"
if errorlevel 1 ( if errorlevel 1 (
echo ERROR: Failed to clone repository. Check Git installation and network connection. echo ERROR: Failed to clone repository. Check Git installation and network connection.
goto :error goto :error
@ -72,10 +145,10 @@ IF "%APP_MODE%"=="standalone" (
echo. echo.
REM --- Step 2: Navigate into the cloned directory --- REM --- Step 2: Navigate into the cloned directory ---
echo Changing directory to %CLONE_DIR%... echo Changing directory to %CLONE_DIR_HAPI%...
cd "%CLONE_DIR%" cd "%CLONE_DIR_HAPI%"
if errorlevel 1 ( if errorlevel 1 (
echo ERROR: Failed to change directory to %CLONE_DIR%. echo ERROR: Failed to change directory to %CLONE_DIR_HAPI%.
goto :error goto :error
) )
echo Current directory: %CD% echo Current directory: %CD%
@ -118,47 +191,141 @@ IF "%APP_MODE%"=="standalone" (
echo Current directory: %CD% echo Current directory: %CD%
echo. echo.
) ELSE ( ) ELSE IF "%SERVER_TYPE%"=="candle" (
echo Running Lite setup, skipping HAPI FHIR build... echo Running FHIR Candle server setup...
REM Ensure the hapi-fhir-jpaserver directory doesn't exist or is empty if Lite mode is chosen after a standalone attempt echo.
if exist "%CLONE_DIR%" (
echo Found existing HAPI directory in Lite mode. Removing it to avoid build issues... REM --- Step 0: Clean up previous clone (optional) ---
rmdir /s /q "%CLONE_DIR%" echo Checking for existing directory: %CLONE_DIR_CANDLE%
if exist "%CLONE_DIR_CANDLE%" (
echo Found existing directory, removing it...
rmdir /s /q "%CLONE_DIR_CANDLE%"
if errorlevel 1 (
echo ERROR: Failed to remove existing directory: %CLONE_DIR_CANDLE%
goto :error
)
echo Existing directory removed.
) else (
echo Directory does not exist, proceeding with clone.
) )
REM Create empty target directories expected by Dockerfile COPY, even if not used echo.
mkdir "%CLONE_DIR%\target\classes" 2> nul
mkdir "%CLONE_DIR%\custom" 2> nul REM --- Step 1: Clone the FHIR Candle server repository ---
REM Create a placeholder empty WAR file to satisfy Dockerfile COPY echo Cloning repository: %REPO_URL_CANDLE% into %CLONE_DIR_CANDLE%...
echo. > "%CLONE_DIR%\target\ROOT.war" git clone "%REPO_URL_CANDLE%" "%CLONE_DIR_CANDLE%"
echo. > "%CLONE_DIR%\target\classes\application.yaml" if errorlevel 1 (
echo ERROR: Failed to clone repository. Check Git and Dotnet installation and network connection.
goto :error
)
echo Repository cloned successfully.
echo.
REM --- Step 2: Navigate into the cloned directory ---
echo Changing directory to %CLONE_DIR_CANDLE%...
cd "%CLONE_DIR_CANDLE%"
if errorlevel 1 (
echo ERROR: Failed to change directory to %CLONE_DIR_CANDLE%.
goto :error
)
echo Current directory: %CD%
echo.
REM --- Step 3: Build the FHIR Candle server using Dotnet ---
echo ===> "Starting Dotnet build (Step 3)...""
dotnet publish -c Release -f net9.0 -o publish
echo ===> Dotnet command finished. Checking error level...
if errorlevel 1 (
echo ERROR: Dotnet build failed. Check Dotnet SDK installation.
cd ..
goto :error
)
echo Dotnet build completed successfully. ErrorLevel: %errorlevel%
echo.
REM --- Step 4: Navigate back to the parent directory ---
echo ===> "Changing directory back (Step 4)..."
cd ..
if errorlevel 1 (
echo ERROR: Failed to change back to the parent directory. ErrorLevel: %errorlevel%
goto :error
)
echo Current directory: %CD%
echo.
) ELSE (
echo Running Lite setup, skipping server build...
REM Ensure the server directories don't exist in Lite mode
if exist "%CLONE_DIR_HAPI%" (
echo Found existing HAPI directory in Lite mode. Removing it to avoid build issues...
rmdir /s /q "%CLONE_DIR_HAPI%"
)
if exist "%CLONE_DIR_CANDLE%" (
echo Found existing Candle directory in Lite mode. Removing it to avoid build issues...
rmdir /s /q "%CLONE_DIR_CANDLE%"
)
REM Create empty placeholder files to satisfy Dockerfile COPY commands in Lite mode.
mkdir "%CLONE_DIR_HAPI%\target\classes" 2> nul
mkdir "%CLONE_DIR_HAPI%\custom" 2> nul
echo. > "%CLONE_DIR_HAPI%\target\ROOT.war"
echo. > "%CLONE_DIR_HAPI%\target\classes\application.yaml"
mkdir "%CLONE_DIR_CANDLE%\publish" 2> nul
echo. > "%CLONE_DIR_CANDLE%\publish\fhir-candle.dll"
echo Placeholder files created for Lite mode build. echo Placeholder files created for Lite mode build.
echo. echo.
) )
REM === Modify docker-compose.yml to set APP_MODE === REM === MODIFIED: Update docker-compose.yml to set APP_MODE and HAPI_FHIR_URL ===
echo Updating docker-compose.yml with APP_MODE=%APP_MODE%... echo Updating docker-compose.yml with APP_MODE=%APP_MODE% and HAPI_FHIR_URL...
( (
echo version: '3.8' echo version: '3.8'
echo services: echo services:
echo fhirflare: echo fhirflare:
echo build: echo build:
echo context: . echo context: .
echo dockerfile: Dockerfile IF "%SERVER_TYPE%"=="hapi" (
echo dockerfile: Dockerfile.hapi
) ELSE IF "%SERVER_TYPE%"=="candle" (
echo dockerfile: Dockerfile.candle
) ELSE (
echo dockerfile: Dockerfile.lite
)
echo ports: echo ports:
echo - "5000:5000" IF "%SERVER_TYPE%"=="candle" (
echo - "8080:8080" # Keep port exposed, even if Tomcat isn't running useful stuff in Lite echo - "5000:5000"
echo - "5001:5826"
) ELSE (
echo - "5000:5000"
echo - "8080:8080"
)
echo volumes: echo volumes:
echo - ./instance:/app/instance echo - ./instance:/app/instance
echo - ./static/uploads:/app/static/uploads echo - ./static/uploads:/app/static/uploads
echo - ./instance/hapi-h2-data/:/app/h2-data # Keep volume mounts consistent IF "%SERVER_TYPE%"=="hapi" (
echo - ./instance/hapi-h2-data/:/app/h2-data # Keep volume mounts consistent
)
echo - ./logs:/app/logs echo - ./logs:/app/logs
IF "%SERVER_TYPE%"=="hapi" (
echo - ./hapi-fhir-jpaserver/target/ROOT.war:/usr/local/tomcat/webapps/ROOT.war
echo - ./hapi-fhir-jpaserver/target/classes/application.yaml:/usr/local/tomcat/conf/application.yaml
) ELSE IF "%SERVER_TYPE%"=="candle" (
echo - ./fhir-candle/publish/:/app/fhir-candle-publish/
)
echo environment: echo environment:
echo - FLASK_APP=app.py echo - FLASK_APP=app.py
echo - FLASK_ENV=development echo - FLASK_ENV=development
echo - NODE_PATH=/usr/lib/node_modules echo - NODE_PATH=/usr/lib/node_modules
echo - APP_MODE=%APP_MODE% echo - APP_MODE=%APP_MODE%
echo - APP_BASE_URL=http://localhost:5000 echo - APP_BASE_URL=http://localhost:5000
echo - HAPI_FHIR_URL=http://localhost:8080/fhir IF DEFINED CUSTOM_FHIR_URL_VAL (
echo - HAPI_FHIR_URL=!CUSTOM_FHIR_URL_VAL!
) ELSE (
IF "%SERVER_TYPE%"=="candle" (
echo - HAPI_FHIR_URL=http://localhost:5826/fhir/%CANDLE_FHIR_VERSION%
echo - ASPNETCORE_URLS=http://0.0.0.0:5826
) ELSE (
echo - HAPI_FHIR_URL=http://localhost:8080/fhir
)
)
echo command: supervisord -c /etc/supervisord.conf echo command: supervisord -c /etc/supervisord.conf
) > docker-compose.yml.tmp ) > docker-compose.yml.tmp

View File

@ -3,13 +3,16 @@ FROM tomcat:10.1-jdk17
# Install build dependencies, Node.js 18, and coreutils (for stdbuf) # Install build dependencies, Node.js 18, and coreutils (for stdbuf)
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-pip python3-venv curl coreutils \ python3 python3-pip python3-venv curl coreutils git \
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \ && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \ && apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# ADDED: Install the Dotnet SDK for the FHIR Candle server
# This makes the image a universal base for either server type
RUN apt-get update && apt-get install -y dotnet-sdk-6.0
# Install specific versions of GoFSH and SUSHI # Install specific versions of GoFSH and SUSHI
# REMOVED pip install fhirpath from this line
RUN npm install -g gofsh fsh-sushi RUN npm install -g gofsh fsh-sushi
# ADDED: Download the latest HL7 FHIR Validator CLI # ADDED: Download the latest HL7 FHIR Validator CLI
@ -24,7 +27,6 @@ RUN chmod 755 validator_cli.jar
# Change back to the main app directory for the next steps # Change back to the main app directory for the next steps
WORKDIR /app WORKDIR /app
# Set up Python environment # Set up Python environment
WORKDIR /app
RUN python3 -m venv /app/venv RUN python3 -m venv /app/venv
ENV PATH="/app/venv/bin:$PATH" ENV PATH="/app/venv/bin:$PATH"
@ -55,6 +57,9 @@ COPY hapi-fhir-jpaserver/target/classes/application.yaml /app/config/application
COPY hapi-fhir-jpaserver/target/classes/application.yaml /usr/local/tomcat/webapps/app/config/application.yaml COPY hapi-fhir-jpaserver/target/classes/application.yaml /usr/local/tomcat/webapps/app/config/application.yaml
COPY hapi-fhir-jpaserver/custom/ /usr/local/tomcat/webapps/custom/ COPY hapi-fhir-jpaserver/custom/ /usr/local/tomcat/webapps/custom/
# ADDED: Copy pre-built Candle DLL files
COPY fhir-candle/publish/ /app/fhir-candle-publish/
# Install supervisord # Install supervisord
RUN pip install supervisor RUN pip install supervisor
@ -62,7 +67,7 @@ RUN pip install supervisor
COPY supervisord.conf /etc/supervisord.conf COPY supervisord.conf /etc/supervisord.conf
# Expose ports # Expose ports
EXPOSE 5000 8080 EXPOSE 5000 8080 5001
# Start supervisord # Start supervisord
CMD ["supervisord", "-c", "/etc/supervisord.conf"] CMD ["supervisord", "-c", "/etc/supervisord.conf"]

62
Dockerfile.candle Normal file
View File

@ -0,0 +1,62 @@
# Base image with Python and Dotnet
FROM mcr.microsoft.com/dotnet/sdk:9.0
# Install build dependencies, Node.js 18, and coreutils (for stdbuf)
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-pip python3-venv curl coreutils git \
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
# Install specific versions of GoFSH and SUSHI
RUN npm install -g gofsh fsh-sushi
# ADDED: Download the latest HL7 FHIR Validator CLI
RUN mkdir -p /app/validator_cli
WORKDIR /app/validator_cli
# Download the validator JAR and a separate checksum file for verification
RUN curl -L -o validator_cli.jar "https://github.com/hapifhir/org.hl7.fhir.core/releases/latest/download/validator_cli.jar"
# Set permissions for the downloaded file
RUN chmod 755 validator_cli.jar
# Change back to the main app directory for the next steps
WORKDIR /app
# Set up Python environment
RUN python3 -m venv /app/venv
ENV PATH="/app/venv/bin:$PATH"
# ADDED: Uninstall old fhirpath just in case it's in requirements.txt
RUN pip uninstall -y fhirpath || true
# ADDED: Install the new fhirpathpy library
RUN pip install --no-cache-dir fhirpathpy
# Copy Flask files
COPY requirements.txt .
# Install requirements (including Pydantic - check version compatibility if needed)
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
COPY services.py .
COPY forms.py .
COPY package.py .
COPY templates/ templates/
COPY static/ static/
COPY tests/ tests/
# Ensure /tmp, /app/h2-data, /app/static/uploads, and /app/logs are writable
RUN mkdir -p /tmp /app/h2-data /app/static/uploads /app/logs && chmod 777 /tmp /app/h2-data /app/static/uploads /app/logs
# Copy pre-built Candle DLL files
COPY fhir-candle/publish/ /app/fhir-candle-publish/
# Install supervisord
RUN pip install supervisor
# Configure supervisord
COPY supervisord.conf /etc/supervisord.conf
# Expose ports
EXPOSE 5000 5001
# Start supervisord
CMD ["supervisord", "-c", "/etc/supervisord.conf"]

66
Dockerfile.hapi Normal file
View File

@ -0,0 +1,66 @@
# Base image with Python, Java, and Maven
FROM tomcat:10.1-jdk17
# Install build dependencies, Node.js 18, and coreutils (for stdbuf)
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-pip python3-venv curl coreutils git maven \
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
# Install specific versions of GoFSH and SUSHI
RUN npm install -g gofsh fsh-sushi
# ADDED: Download the latest HL7 FHIR Validator CLI
RUN mkdir -p /app/validator_cli
WORKDIR /app/validator_cli
# Download the validator JAR and a separate checksum file for verification
RUN curl -L -o validator_cli.jar "https://github.com/hapifhir/org.hl7.fhir.core/releases/latest/download/validator_cli.jar"
# Set permissions for the downloaded file
RUN chmod 755 validator_cli.jar
# Change back to the main app directory for the next steps
WORKDIR /app
# Set up Python environment
RUN python3 -m venv /app/venv
ENV PATH="/app/venv/bin:$PATH"
# ADDED: Uninstall old fhirpath just in case it's in requirements.txt
RUN pip uninstall -y fhirpath || true
# ADDED: Install the new fhirpathpy library
RUN pip install --no-cache-dir fhirpathpy
# Copy Flask files
COPY requirements.txt .
# Install requirements (including Pydantic - check version compatibility if needed)
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
COPY services.py .
COPY forms.py .
COPY package.py .
COPY templates/ templates/
COPY static/ static/
COPY tests/ tests/
# Ensure /tmp, /app/h2-data, /app/static/uploads, and /app/logs are writable
RUN mkdir -p /tmp /app/h2-data /app/static/uploads /app/logs && chmod 777 /tmp /app/h2-data /app/static/uploads /app/logs
# Copy pre-built HAPI WAR and configuration
COPY hapi-fhir-jpaserver/target/ROOT.war /usr/local/tomcat/webapps/
COPY hapi-fhir-jpaserver/target/classes/application.yaml /usr/local/tomcat/conf/
COPY hapi-fhir-jpaserver/target/classes/application.yaml /app/config/application.yaml
COPY hapi-fhir-jpaserver/target/classes/application.yaml /usr/local/tomcat/webapps/app/config/application.yaml
COPY hapi-fhir-jpaserver/custom/ /usr/local/tomcat/webapps/custom/
# Install supervisord
RUN pip install supervisor
# Configure supervisord
COPY supervisord.conf /etc/supervisord.conf
# Expose ports
EXPOSE 5000 8080
# Start supervisord
CMD ["supervisord", "-c", "/etc/supervisord.conf"]

58
Dockerfile.lite Normal file
View File

@ -0,0 +1,58 @@
# Base image with Python and Node.js
FROM python:3.9-slim
# Install Node.js 18 and npm
RUN apt-get update && apt-get install -y --no-install-recommends \
curl coreutils git \
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
# Install specific versions of GoFSH and SUSHI
RUN npm install -g gofsh fsh-sushi
# ADDED: Download the latest HL7 FHIR Validator CLI
RUN mkdir -p /app/validator_cli
WORKDIR /app/validator_cli
# Download the validator JAR and a separate checksum file for verification
RUN curl -L -o validator_cli.jar "https://github.com/hapifhir/org.hl7.fhir.core/releases/latest/download/validator_cli.jar"
# Set permissions for the downloaded file
RUN chmod 755 validator_cli.jar
# Change back to the main app directory for the next steps
WORKDIR /app
# Set up Python environment
RUN python3 -m venv /app/venv
ENV PATH="/app/venv/bin:$PATH"
# ADDED: Uninstall old fhirpath just in case it's in requirements.txt
RUN pip uninstall -y fhirpath || true
# ADDED: Install the new fhirpathpy library
RUN pip install --no-cache-dir fhirpathpy
# Copy Flask files
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
COPY services.py .
COPY forms.py .
COPY package.py .
COPY templates/ templates/
COPY static/ static/
COPY tests/ tests/
# Ensure necessary directories are writable
RUN mkdir -p /app/static/uploads /app/logs && chmod 777 /app/static/uploads /app/logs
# Install supervisord
RUN pip install supervisor
# Configure supervisord
COPY supervisord.conf /etc/supervisord.conf
# Expose ports
EXPOSE 5000
# Start supervisord
CMD ["supervisord", "-c", "/etc/supervisord.conf"]

View File

@ -3,14 +3,13 @@ services:
fhirflare: fhirflare:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile.lite
ports: ports:
- "5000:5000" - "5000:5000"
- "8080:8080" # Keep port exposed, even if Tomcat isn't running useful stuff in Lite - "8080:8080"
volumes: volumes:
- ./instance:/app/instance - ./instance:/app/instance
- ./static/uploads:/app/static/uploads - ./static/uploads:/app/static/uploads
- ./instance/hapi-h2-data/:/app/h2-data # Keep volume mounts consistent
- ./logs:/app/logs - ./logs:/app/logs
environment: environment:
- FLASK_APP=app.py - FLASK_APP=app.py

View File

@ -1,18 +1,21 @@
#!/bin/bash #!/bin/bash
# --- Configuration --- # --- Configuration ---
REPO_URL="https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git" REPO_URL_HAPI="https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git"
CLONE_DIR="hapi-fhir-jpaserver" REPO_URL_CANDLE="https://github.com/FHIR/fhir-candle.git"
SOURCE_CONFIG_DIR="hapi-fhir-Setup" # Assuming this is relative to the script's parent CLONE_DIR_HAPI="hapi-fhir-jpaserver"
CLONE_DIR_CANDLE="fhir-candle"
SOURCE_CONFIG_DIR="hapi-fhir-Setup"
CONFIG_FILE="application.yaml" CONFIG_FILE="application.yaml"
# --- Define Paths --- # --- Define Paths ---
# Note: Adjust SOURCE_CONFIG_PATH if SOURCE_CONFIG_DIR is not a sibling directory
# This assumes the script is run from a directory, and hapi-fhir-setup is at the same level
SOURCE_CONFIG_PATH="../${SOURCE_CONFIG_DIR}/target/classes/${CONFIG_FILE}" SOURCE_CONFIG_PATH="../${SOURCE_CONFIG_DIR}/target/classes/${CONFIG_FILE}"
DEST_CONFIG_PATH="${CLONE_DIR}/target/classes/${CONFIG_FILE}" DEST_CONFIG_PATH="${CLONE_DIR_HAPI}/target/classes/${CONFIG_FILE}"
APP_MODE="" APP_MODE=""
CUSTOM_FHIR_URL_VAL=""
SERVER_TYPE=""
CANDLE_FHIR_VERSION=""
# --- Error Handling Function --- # --- Error Handling Function ---
handle_error() { handle_error() {
@ -20,25 +23,39 @@ handle_error() {
echo "An error occurred: $1" echo "An error occurred: $1"
echo "Script aborted." echo "Script aborted."
echo "------------------------------------" echo "------------------------------------"
# Removed 'read -p "Press Enter to exit..."' as it's not typical for non-interactive CI/CD
exit 1 exit 1
} }
# === Prompt for Installation Mode === # === MODIFIED: Prompt for Installation Mode ===
get_mode_choice() { get_mode_choice() {
echo ""
echo "Select Installation Mode:" echo "Select Installation Mode:"
echo "1. Standalone (Includes local HAPI FHIR Server - Requires Git & Maven)" echo "1. Lite (Excludes local HAPI FHIR Server - No Git/Maven/Dotnet needed)"
echo "2. Lite (Excludes local HAPI FHIR Server - No Git/Maven needed)" echo "2. Custom URL (Uses a custom FHIR Server - No Git/Maven/Dotnet needed)"
echo "3. Hapi (Includes local HAPI FHIR Server - Requires Git & Maven)"
echo "4. Candle (Includes local FHIR Candle Server - Requires Git & Dotnet)"
while true; do while true; do
read -r -p "Enter your choice (1 or 2): " choice read -r -p "Enter your choice (1, 2, 3, or 4): " choice
case "$choice" in case "$choice" in
1) 1)
APP_MODE="standalone" APP_MODE="lite"
break break
;; ;;
2) 2)
APP_MODE="lite" APP_MODE="standalone"
get_custom_url_prompt
break
;;
3)
APP_MODE="standalone"
SERVER_TYPE="hapi"
break
;;
4)
APP_MODE="standalone"
SERVER_TYPE="candle"
get_candle_fhir_version
break break
;; ;;
*) *)
@ -47,156 +64,301 @@ get_mode_choice() {
esac esac
done done
echo "Selected Mode: $APP_MODE" echo "Selected Mode: $APP_MODE"
echo "Server Type: $SERVER_TYPE"
echo echo
} }
# === NEW: Prompt for Custom URL ===
get_custom_url_prompt() {
local confirmed_url=""
while true; do
echo
read -r -p "Please enter the custom FHIR server URL: " custom_url_input
echo
echo "You entered: $custom_url_input"
read -r -p "Is this URL correct? (Y/N): " confirm_url
if [[ "$confirm_url" =~ ^[Yy]$ ]]; then
confirmed_url="$custom_url_input"
break
else
echo "URL not confirmed. Please re-enter."
fi
done
while true; do
echo
read -r -p "Please re-enter the URL to confirm it is correct: " custom_url_input
if [ "$custom_url_input" = "$confirmed_url" ]; then
CUSTOM_FHIR_URL_VAL="$custom_url_input"
echo
echo "Custom URL confirmed: $CUSTOM_FHIR_URL_VAL"
break
else
echo
echo "URLs do not match. Please try again."
confirmed_url="$custom_url_input"
fi
done
}
# === NEW: Prompt for Candle FHIR version ===
get_candle_fhir_version() {
echo ""
echo "Select the FHIR version for the Candle server:"
echo "1. R4 (4.0)"
echo "2. R4B (4.3)"
echo "3. R5 (5.0)"
while true; do
read -r -p "Enter your choice (1, 2, or 3): " choice
case "$choice" in
1)
CANDLE_FHIR_VERSION=r4
break
;;
2)
CANDLE_FHIR_VERSION=r4b
break
;;
3)
CANDLE_FHIR_VERSION=r5
break
;;
*)
echo "Invalid input. Please try again."
;;
esac
done
}
# Call the function to get mode choice # Call the function to get mode choice
get_mode_choice get_mode_choice
# === Conditionally Execute HAPI Setup === # === Conditionally Execute Server Setup ===
if [ "$APP_MODE" = "standalone" ]; then case "$SERVER_TYPE" in
echo "Running Standalone setup including HAPI FHIR..." "hapi")
echo echo "Running Hapi server setup..."
echo
# --- Step 0: Clean up previous clone (optional) --- # --- Step 0: Clean up previous clone (optional) ---
echo "Checking for existing directory: $CLONE_DIR" echo "Checking for existing directory: $CLONE_DIR_HAPI"
if [ -d "$CLONE_DIR" ]; then if [ -d "$CLONE_DIR_HAPI" ]; then
echo "Found existing directory, removing it..." echo "Found existing directory, removing it..."
rm -rf "$CLONE_DIR" rm -rf "$CLONE_DIR_HAPI"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
handle_error "Failed to remove existing directory: $CLONE_DIR" handle_error "Failed to remove existing directory: $CLONE_DIR_HAPI"
fi
echo "Existing directory removed."
else
echo "Directory does not exist, proceeding with clone."
fi fi
echo "Existing directory removed." echo
else
echo "Directory does not exist, proceeding with clone."
fi
echo
# --- Step 1: Clone the HAPI FHIR server repository --- # --- Step 1: Clone the HAPI FHIR server repository ---
echo "Cloning repository: $REPO_URL into $CLONE_DIR..." echo "Cloning repository: $REPO_URL_HAPI into $CLONE_DIR_HAPI..."
git clone "$REPO_URL" "$CLONE_DIR" git clone "$REPO_URL_HAPI" "$CLONE_DIR_HAPI"
if [ $? -ne 0 ]; then
handle_error "Failed to clone repository. Check Git installation and network connection."
fi
echo "Repository cloned successfully."
echo
# --- Step 2: Navigate into the cloned directory ---
echo "Changing directory to $CLONE_DIR..."
cd "$CLONE_DIR" || handle_error "Failed to change directory to $CLONE_DIR."
echo "Current directory: $(pwd)"
echo
# --- Step 3: Build the HAPI server using Maven ---
echo "===> Starting Maven build (Step 3)..."
mvn clean package -DskipTests=true -Pboot
if [ $? -ne 0 ]; then
echo "ERROR: Maven build failed."
cd ..
handle_error "Maven build process resulted in an error."
fi
echo "Maven build completed successfully."
echo
# --- Step 4: Copy the configuration file ---
echo "===> Starting file copy (Step 4)..."
echo "Copying configuration file..."
# Corrected SOURCE_CONFIG_PATH to be relative to the new current directory ($CLONE_DIR)
# This assumes the original script's SOURCE_CONFIG_PATH was relative to its execution location
# If SOURCE_CONFIG_DIR is ../hapi-fhir-setup relative to script's original location:
# Then from within CLONE_DIR, it becomes ../../hapi-fhir-setup
# We defined SOURCE_CONFIG_PATH earlier relative to the script start.
# So, when inside CLONE_DIR, the path from original script location should be used.
# The original script had: set SOURCE_CONFIG_PATH=..\%SOURCE_CONFIG_DIR%\target\classes\%CONFIG_FILE%
# And then: xcopy "%SOURCE_CONFIG_PATH%" "target\classes\"
# This implies SOURCE_CONFIG_PATH is relative to the original script's location, not the $CLONE_DIR
# Therefore, we need to construct the correct relative path from *within* $CLONE_DIR back to the source.
# Assuming the script is in dir X, and SOURCE_CONFIG_DIR is ../hapi-fhir-setup from X.
# So, hapi-fhir-setup is a sibling of X's parent.
# If CLONE_DIR is also in X, then from within CLONE_DIR, the path is ../ + original SOURCE_CONFIG_PATH
# For simplicity and robustness, let's use an absolute path or a more clearly defined relative path from the start.
# The original `SOURCE_CONFIG_PATH=..\%SOURCE_CONFIG_DIR%\target\classes\%CONFIG_FILE%` implies
# that `hapi-fhir-setup` is a sibling of the directory where the script *is being run from*.
# Let's assume the script is run from the root of FHIRFLARE-IG-Toolkit.
# And hapi-fhir-setup is also in the root, next to this script.
# Then SOURCE_CONFIG_PATH would be ./hapi-fhir-setup/target/classes/application.yaml
# And from within ./hapi-fhir-jpaserver/, the path would be ../hapi-fhir-setup/target/classes/application.yaml
# The original batch file sets SOURCE_CONFIG_PATH as "..\%SOURCE_CONFIG_DIR%\target\classes\%CONFIG_FILE%"
# And COPIES it to "target\classes\" *while inside CLONE_DIR*.
# This means the source path is relative to where the *cd %CLONE_DIR%* happened from.
# Let's make it relative to the script's initial execution directory.
INITIAL_SCRIPT_DIR=$(pwd)
ABSOLUTE_SOURCE_CONFIG_PATH="${INITIAL_SCRIPT_DIR}/../${SOURCE_CONFIG_DIR}/target/classes/${CONFIG_FILE}" # This matches the ..\ logic
echo "Source: $ABSOLUTE_SOURCE_CONFIG_PATH"
echo "Destination: target/classes/$CONFIG_FILE"
if [ ! -f "$ABSOLUTE_SOURCE_CONFIG_PATH" ]; then
echo "WARNING: Source configuration file not found at $ABSOLUTE_SOURCE_CONFIG_PATH."
echo "The script will continue, but the server might use default configuration."
else
cp "$ABSOLUTE_SOURCE_CONFIG_PATH" "target/classes/"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "WARNING: Failed to copy configuration file. Check if the source file exists and permissions." handle_error "Failed to clone repository. Check Git installation and network connection."
fi
echo "Repository cloned successfully."
echo
# --- Step 2: Navigate into the cloned directory ---
echo "Changing directory to $CLONE_DIR_HAPI..."
cd "$CLONE_DIR_HAPI" || handle_error "Failed to change directory to $CLONE_DIR_HAPI."
echo "Current directory: $(pwd)"
echo
# --- Step 3: Build the HAPI server using Maven ---
echo "===> Starting Maven build (Step 3)..."
mvn clean package -DskipTests=true -Pboot
if [ $? -ne 0 ]; then
echo "ERROR: Maven build failed."
cd ..
handle_error "Maven build process resulted in an error."
fi
echo "Maven build completed successfully."
echo
# --- Step 4: Copy the configuration file ---
echo "===> Starting file copy (Step 4)..."
echo "Copying configuration file..."
INITIAL_SCRIPT_DIR=$(pwd)
ABSOLUTE_SOURCE_CONFIG_PATH="${INITIAL_SCRIPT_DIR}/../${SOURCE_CONFIG_DIR}/target/classes/${CONFIG_FILE}"
echo "Source: $ABSOLUTE_SOURCE_CONFIG_PATH"
echo "Destination: target/classes/$CONFIG_FILE"
if [ ! -f "$ABSOLUTE_SOURCE_CONFIG_PATH" ]; then
echo "WARNING: Source configuration file not found at $ABSOLUTE_SOURCE_CONFIG_PATH."
echo "The script will continue, but the server might use default configuration." echo "The script will continue, but the server might use default configuration."
else else
echo "Configuration file copied successfully." cp "$ABSOLUTE_SOURCE_CONFIG_PATH" "target/classes/"
if [ $? -ne 0 ]; then
echo "WARNING: Failed to copy configuration file. Check if the source file exists and permissions."
echo "The script will continue, but the server might use default configuration."
else
echo "Configuration file copied successfully."
fi
fi fi
fi echo
echo
# --- Step 5: Navigate back to the parent directory --- # --- Step 5: Navigate back to the parent directory ---
echo "===> Changing directory back (Step 5)..." echo "===> Changing directory back (Step 5)..."
cd .. || handle_error "Failed to change back to the parent directory." cd .. || handle_error "Failed to change back to the parent directory."
echo "Current directory: $(pwd)" echo "Current directory: $(pwd)"
echo echo
;;
else # APP_MODE is "lite" "candle")
echo "Running Lite setup, skipping HAPI FHIR build..." echo "Running FHIR Candle server setup..."
# Ensure the hapi-fhir-jpaserver directory doesn't exist or is empty if Lite mode is chosen echo
if [ -d "$CLONE_DIR" ]; then
echo "Found existing HAPI directory ($CLONE_DIR) in Lite mode. Removing it..."
rm -rf "$CLONE_DIR"
fi
# Create empty target directories expected by Dockerfile COPY, even if not used
mkdir -p "${CLONE_DIR}/target/classes"
mkdir -p "${CLONE_DIR}/custom" # This was in the original batch, ensure it's here
# Create a placeholder empty WAR file and application.yaml to satisfy Dockerfile COPY
touch "${CLONE_DIR}/target/ROOT.war"
touch "${CLONE_DIR}/target/classes/application.yaml"
echo "Placeholder files and directories created for Lite mode build in $CLONE_DIR."
echo
fi
# === Modify docker-compose.yml to set APP_MODE === # --- Step 0: Clean up previous clone (optional) ---
echo "Updating docker-compose.yml with APP_MODE=$APP_MODE..." echo "Checking for existing directory: $CLONE_DIR_CANDLE"
if [ -d "$CLONE_DIR_CANDLE" ]; then
echo "Found existing directory, removing it..."
rm -rf "$CLONE_DIR_CANDLE"
if [ $? -ne 0 ]; then
handle_error "Failed to remove existing directory: $CLONE_DIR_CANDLE"
fi
echo "Existing directory removed."
else
echo "Directory does not exist, proceeding with clone."
fi
echo
# --- Step 1: Clone the FHIR Candle server repository ---
echo "Cloning repository: $REPO_URL_CANDLE into $CLONE_DIR_CANDLE..."
git clone "$REPO_URL_CANDLE" "$CLONE_DIR_CANDLE"
if [ $? -ne 0 ]; then
handle_error "Failed to clone repository. Check Git and Dotnet SDK installation and network connection."
fi
echo "Repository cloned successfully."
echo
# --- Step 2: Navigate into the cloned directory ---
echo "Changing directory to $CLONE_DIR_CANDLE..."
cd "$CLONE_DIR_CANDLE" || handle_error "Failed to change directory to $CLONE_DIR_CANDLE."
echo "Current directory: $(pwd)"
echo
# --- Step 3: Build the FHIR Candle server using Dotnet ---
echo "===> Starting Dotnet build (Step 3)..."
dotnet publish -c Release -f net9.0 -o publish
if [ $? -ne 0 ]; then
handle_error "Dotnet build failed. Check Dotnet SDK installation."
fi
echo "Dotnet build completed successfully."
echo
# --- Step 4: Navigate back to the parent directory ---
echo "===> Changing directory back (Step 4)..."
cd .. || handle_error "Failed to change back to the parent directory."
echo "Current directory: $(pwd)"
echo
;;
*) # APP_MODE is Lite, no SERVER_TYPE
echo "Running Lite setup, skipping server build..."
if [ -d "$CLONE_DIR_HAPI" ]; then
echo "Found existing HAPI directory in Lite mode. Removing it to avoid build issues..."
rm -rf "$CLONE_DIR_HAPI"
fi
if [ -d "$CLONE_DIR_CANDLE" ]; then
echo "Found existing Candle directory in Lite mode. Removing it to avoid build issues..."
rm -rf "$CLONE_DIR_CANDLE"
fi
mkdir -p "${CLONE_DIR_HAPI}/target/classes"
mkdir -p "${CLONE_DIR_HAPI}/custom"
touch "${CLONE_DIR_HAPI}/target/ROOT.war"
touch "${CLONE_DIR_HAPI}/target/classes/application.yaml"
mkdir -p "${CLONE_DIR_CANDLE}/publish"
touch "${CLONE_DIR_CANDLE}/publish/fhir-candle.dll"
echo "Placeholder files and directories created for Lite mode build."
echo
;;
esac
# === MODIFIED: Update docker-compose.yml to set APP_MODE and HAPI_FHIR_URL and DOCKERFILE ===
echo "Updating docker-compose.yml with APP_MODE=$APP_MODE and HAPI_FHIR_URL..."
DOCKER_COMPOSE_TMP="docker-compose.yml.tmp" DOCKER_COMPOSE_TMP="docker-compose.yml.tmp"
DOCKER_COMPOSE_ORIG="docker-compose.yml" DOCKER_COMPOSE_ORIG="docker-compose.yml"
HAPI_URL_TO_USE="https://fhir.hl7.org.au/aucore/fhir/DEFAULT/"
if [ -n "$CUSTOM_FHIR_URL_VAL" ]; then
HAPI_URL_TO_USE="$CUSTOM_FHIR_URL_VAL"
elif [ "$SERVER_TYPE" = "candle" ]; then
HAPI_URL_TO_USE="http://localhost:5826/fhir/${CANDLE_FHIR_VERSION}"
else
HAPI_URL_TO_USE="http://localhost:8080/fhir"
fi
DOCKERFILE_TO_USE="Dockerfile.lite"
if [ "$SERVER_TYPE" = "hapi" ]; then
DOCKERFILE_TO_USE="Dockerfile.hapi"
elif [ "$SERVER_TYPE" = "candle" ]; then
DOCKERFILE_TO_USE="Dockerfile.candle"
fi
cat << EOF > "$DOCKER_COMPOSE_TMP" cat << EOF > "$DOCKER_COMPOSE_TMP"
version: '3.8' version: '3.8'
services: services:
fhirflare: fhirflare:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: ${DOCKERFILE_TO_USE}
ports: ports:
EOF
if [ "$SERVER_TYPE" = "candle" ]; then
cat << EOF >> "$DOCKER_COMPOSE_TMP"
- "5000:5000" - "5000:5000"
- "8080:8080" # Keep port exposed, even if Tomcat isn't running useful stuff in Lite - "5001:5826"
EOF
else
cat << EOF >> "$DOCKER_COMPOSE_TMP"
- "5000:5000"
- "8080:8080"
EOF
fi
cat << EOF >> "$DOCKER_COMPOSE_TMP"
volumes: volumes:
- ./instance:/app/instance - ./instance:/app/instance
- ./static/uploads:/app/static/uploads - ./static/uploads:/app/static/uploads
- ./instance/hapi-h2-data/:/app/h2-data # Keep volume mounts consistent
- ./logs:/app/logs - ./logs:/app/logs
EOF
if [ "$SERVER_TYPE" = "hapi" ]; then
cat << EOF >> "$DOCKER_COMPOSE_TMP"
- ./instance/hapi-h2-data/:/app/h2-data # Keep volume mounts consistent
- ./hapi-fhir-jpaserver/target/ROOT.war:/usr/local/tomcat/webapps/ROOT.war
- ./hapi-fhir-jpaserver/target/classes/application.yaml:/usr/local/tomcat/conf/application.yaml
EOF
elif [ "$SERVER_TYPE" = "candle" ]; then
cat << EOF >> "$DOCKER_COMPOSE_TMP"
- ./fhir-candle/publish/:/app/fhir-candle-publish/
EOF
fi
cat << EOF >> "$DOCKER_COMPOSE_TMP"
environment: environment:
- FLASK_APP=app.py - FLASK_APP=app.py
- FLASK_ENV=development - FLASK_ENV=development
- NODE_PATH=/usr/lib/node_modules - NODE_PATH=/usr/lib/node_modules
- APP_MODE=${APP_MODE} - APP_MODE=${APP_MODE}
- APP_BASE_URL=http://localhost:5000 - APP_BASE_URL=http://localhost:5000
- HAPI_FHIR_URL=http://localhost:8080/fhir - HAPI_FHIR_URL=${HAPI_URL_TO_USE}
EOF
if [ "$SERVER_TYPE" = "candle" ]; then
cat << EOF >> "$DOCKER_COMPOSE_TMP"
- ASPNETCORE_URLS=http://0.0.0.0:5826
EOF
fi
cat << EOF >> "$DOCKER_COMPOSE_TMP"
command: supervisord -c /etc/supervisord.conf command: supervisord -c /etc/supervisord.conf
EOF EOF

View File

@ -34,3 +34,17 @@ stdout_logfile_backups=5
stderr_logfile=/app/logs/tomcat_err.log stderr_logfile=/app/logs/tomcat_err.log
stderr_logfile_maxbytes=10MB stderr_logfile_maxbytes=10MB
stderr_logfile_backups=5 stderr_logfile_backups=5
[program:candle]
command=dotnet /app/fhir-candle-publish/fhir-candle.dll
directory=/app/fhir-candle-publish
autostart=true
autorestart=true
startsecs=10
stopwaitsecs=10
stdout_logfile=/app/logs/candle.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
stderr_logfile=/app/logs/candle_err.log
stderr_logfile_maxbytes=10MB
stderr_logfile_backups=5