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
) )
REM Create empty target directories expected by Dockerfile COPY, even if not used echo Existing directory removed.
mkdir "%CLONE_DIR%\target\classes" 2> nul ) else (
mkdir "%CLONE_DIR%\custom" 2> nul echo Directory does not exist, proceeding with clone.
REM Create a placeholder empty WAR file to satisfy Dockerfile COPY )
echo. > "%CLONE_DIR%\target\ROOT.war" echo.
echo. > "%CLONE_DIR%\target\classes\application.yaml"
REM --- 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 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:
IF "%SERVER_TYPE%"=="candle" (
echo - "5000:5000" echo - "5000:5000"
echo - "8080:8080" # Keep port exposed, even if Tomcat isn't running useful stuff in Lite 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
IF "%SERVER_TYPE%"=="hapi" (
echo - ./instance/hapi-h2-data/:/app/h2-data # Keep volume mounts consistent 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
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 - 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,24 +64,89 @@ 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 "Running Hapi server setup..."
echo 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 fi
echo "Existing directory removed." echo "Existing directory removed."
else else
@ -73,8 +155,8 @@ if [ "$APP_MODE" = "standalone" ]; then
echo 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 if [ $? -ne 0 ]; then
handle_error "Failed to clone repository. Check Git installation and network connection." handle_error "Failed to clone repository. Check Git installation and network connection."
fi fi
@ -82,8 +164,8 @@ if [ "$APP_MODE" = "standalone" ]; then
echo echo
# --- Step 2: Navigate into the cloned directory --- # --- Step 2: Navigate into the cloned directory ---
echo "Changing directory to $CLONE_DIR..." echo "Changing directory to $CLONE_DIR_HAPI..."
cd "$CLONE_DIR" || handle_error "Failed to change directory to $CLONE_DIR." cd "$CLONE_DIR_HAPI" || handle_error "Failed to change directory to $CLONE_DIR_HAPI."
echo "Current directory: $(pwd)" echo "Current directory: $(pwd)"
echo echo
@ -101,34 +183,8 @@ if [ "$APP_MODE" = "standalone" ]; then
# --- Step 4: Copy the configuration file --- # --- Step 4: Copy the configuration file ---
echo "===> Starting file copy (Step 4)..." echo "===> Starting file copy (Step 4)..."
echo "Copying configuration file..." 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) INITIAL_SCRIPT_DIR=$(pwd)
ABSOLUTE_SOURCE_CONFIG_PATH="${INITIAL_SCRIPT_DIR}/../${SOURCE_CONFIG_DIR}/target/classes/${CONFIG_FILE}" # This matches the ..\ logic ABSOLUTE_SOURCE_CONFIG_PATH="${INITIAL_SCRIPT_DIR}/../${SOURCE_CONFIG_DIR}/target/classes/${CONFIG_FILE}"
echo "Source: $ABSOLUTE_SOURCE_CONFIG_PATH" echo "Source: $ABSOLUTE_SOURCE_CONFIG_PATH"
echo "Destination: target/classes/$CONFIG_FILE" echo "Destination: target/classes/$CONFIG_FILE"
@ -152,51 +208,157 @@ if [ "$APP_MODE" = "standalone" ]; then
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
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 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