Compare commits

...

2 commits

Author SHA1 Message Date
bfc790355a it builds, but does it run?
All checks were successful
Build Docker Image on Commit / build-and-publish (push) Successful in 16m30s
2025-07-04 22:27:34 +01:00
d93ecd2627 add easy_install.sh 2025-07-04 22:12:40 +01:00
11 changed files with 1456 additions and 23 deletions

View file

@ -1 +1,125 @@
FROM alpine:3.12
# FreeTAKServer Docker Container
# Based on the easy_install.sh script from FreeTAKTeam/FreeTAKHub-Installation
# Licensed under the Eclipse Public License 2.0 (EPL-2.0)
FROM ubuntu:22.04
# Set environment variables to prevent interactive prompts
ENV DEBIAN_FRONTEND=noninteractive
ENV NEEDRESTART_SUSPEND=1
ENV TZ=UTC
# Set default installation parameters
ENV INSTALL_TYPE=latest
ENV PY3_VER=3.11
ENV STABLE_FTS_VERSION=2.0.66
ENV LEGACY_FTS_VERSION=1.9.9.6
ENV FTS_VENV=/opt/fts.venv
ENV REPO=https://github.com/FreeTAKTeam/FreeTAKHub-Installation.git
ENV BRANCH=main
ENV CFG_RPATH=core/configuration
# Create application directory
WORKDIR /opt/freetak
# Update system and install base dependencies
RUN apt-get update -qq && \
apt-get install -y --no-install-recommends \
software-properties-common \
curl \
wget \
git \
python3-pip \
python3-setuptools \
python${PY3_VER}-dev \
python${PY3_VER}-venv \
libpython${PY3_VER}-dev \
build-essential \
libssl-dev \
libffi-dev \
libxml2-dev \
libxslt1-dev \
libjpeg-dev \
libpng-dev \
zlib1g-dev \
sqlite3 \
libsqlite3-dev \
sudo \
openssh-client \
ca-certificates \
gnupg \
lsb-release && \
# Add Ansible PPA and install
add-apt-repository -y ppa:ansible/ansible && \
apt-get update -qq && \
apt-get install -y --no-install-recommends ansible && \
# Clean up apt cache
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Get latest FTS version from PyPI
RUN LATEST_FTS_VERSION=$(curl -s https://pypi.org/pypi/FreeTAKServer/json | python3 -c "import sys, json; print(json.load(sys.stdin)['info']['version'])") && \
echo "export LATEST_FTS_VERSION=${LATEST_FTS_VERSION}" >> /etc/environment
# Create Python virtual environment and install dependencies
RUN python${PY3_VER} -m venv ${FTS_VENV} && \
. ${FTS_VENV}/bin/activate && \
python3 -m pip install --upgrade pip && \
python3 -m pip install --force-reinstall jinja2 pyyaml psutil
# Clone FreeTAKHub-Installation repository
RUN git clone --branch ${BRANCH} ${REPO} /opt/FreeTAKHub-Installation
# Set working directory to the cloned repository
WORKDIR /opt/FreeTAKHub-Installation
# Create a non-root user for running the application
RUN useradd -m -u 1000 -s /bin/bash freetak && \
usermod -aG sudo freetak && \
echo "freetak ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
# Generate SSH key pair for the freetak user
RUN mkdir -p /home/freetak/.ssh && \
ssh-keygen -t rsa -f /home/freetak/.ssh/id_rsa -N "" && \
chown -R freetak:freetak /home/freetak/.ssh && \
chmod 700 /home/freetak/.ssh && \
chmod 600 /home/freetak/.ssh/id_rsa && \
chmod 644 /home/freetak/.ssh/id_rsa.pub
# Copy the virtual environment to be accessible by freetak user
RUN chown -R freetak:freetak ${FTS_VENV}
# Copy the scripts
COPY scripts/install_freetak.sh /opt/install_freetak.sh
COPY scripts/start_freetak.sh /opt/start_freetak.sh
COPY scripts/healthcheck.sh /opt/healthcheck.sh
COPY scripts/entrypoint.sh /opt/entrypoint.sh
# Make the scripts executable
RUN chmod +x /opt/install_freetak.sh /opt/start_freetak.sh /opt/healthcheck.sh /opt/entrypoint.sh
# Run the installation
RUN /opt/install_freetak.sh
# Set proper ownership
RUN chown -R freetak:freetak /opt/FreeTAKHub-Installation /opt/freetak /opt/*.sh
# Switch to freetak user
USER freetak
# Set the working directory
WORKDIR /opt/freetak
# Expose the default FreeTAKServer ports
# 8087 - Main server port
# 8080 - Web UI port
# 8443 - HTTPS port
# 19023 - FTS API port
EXPOSE 8087 8080 8443 19023
# Add healthcheck
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD /opt/healthcheck.sh
# Default command - use the entrypoint script
CMD ["/opt/entrypoint.sh"]

189
Readme.md
View file

@ -1,36 +1,181 @@
# README for Docker Image Build and Publish Workflows
# FreeTAKServer Docker Container
## Overview
This Docker container provides a complete FreeTAKServer installation based on the official FreeTAKTeam installation script. It includes all necessary components and dependencies to run FreeTAKServer in a containerized environment.
This repository contains two GitHub Actions workflows that automate the building and publishing of Docker images to an OCI registry.
## Features
### Workflows
- **All-in-one container**: Includes FreeTAKServer, Web UI, and Web Map
- **Multiple installation types**: Support for latest, stable, and legacy versions
- **Automated setup**: Based on the official FreeTAKHub-Installation scripts
- **Health checks**: Built-in container health monitoring
- **Persistent data**: Volume support for configuration and data persistence
1. **On Commit to Main**
- **Trigger:** Activates on commits to the `main` branch (tags are excluded).
- **Purpose:** Builds and publishes a Docker image for each commit.
## Quick Start
2. **On Tag Push**
- **Trigger:** Activates when a new tag is pushed.
- **Purpose:** Builds and publishes a Docker image for the tag and tags it as `latest`.
### Using Docker Compose (Recommended)
## Prerequisites
```bash
# Clone or navigate to the directory containing docker-compose.yml
docker-compose up -d
```
- **Secrets Needed:**
- `OCI_TOKEN`: Your OCI registry token.
- `OCI_USER`: Your OCI registry username.
### Using the Run Script
## How to Use
```bash
# Build and run with latest version (default)
./run.sh
1. **Clone the Repository:** Get a local copy of this repository.
2. **Modify Dockerfile:** Update the `Dockerfile` for your application.
3. **Push Changes:** Push changes to the `main` branch or create a new tag.
4. **Check Workflow Status:** View the Actions tab in Forgjo to monitor workflow runs.
# Build and run with stable version
./run.sh stable
## Notes
# Build and run with legacy version
./run.sh legacy
```
- Ensure your Docker environment is compatible with multi-platform builds if necessary.
### Manual Docker Commands
```bash
# Build the image
docker build -t freetak-server .
# Run the container
docker run -d \
--name freetak-server \
-p 8087:8087 \
-p 8080:8080 \
-p 8443:8443 \
-p 19023:19023 \
-e INSTALL_TYPE=latest \
freetak-server
```
## Installation Types
The container supports three installation types via the `INSTALL_TYPE` environment variable:
- **`latest`** (default): Installs the most recent version from PyPI
- **`stable`**: Installs the stable version (v2.0.66)
- **`legacy`**: Installs the legacy version (v1.9.9.6) with Python 3.8
## Exposed Ports
- **8087**: Main FreeTAKServer port
- **8080**: Web UI port
- **8443**: HTTPS port (if configured)
- **19023**: FTS API port
## Access Points
After the container is running, you can access:
- **Web UI**: http://localhost:8080
- **Main API**: http://localhost:8087
- **API Endpoint**: http://localhost:19023
## Project Structure
```
/docker/services/freetak/
├── Dockerfile # Main container definition
├── docker-compose.yml # Docker Compose configuration
├── run.sh # Quick start script
├── scripts/ # Container scripts directory
│ ├── install_freetak.sh # Installation script
│ ├── start_freetak.sh # Simple startup script
│ ├── entrypoint.sh # Main entrypoint with signal handling
│ ├── healthcheck.sh # Health check script
│ ├── dev-helper.sh # Development helper script
│ └── README.md # Scripts documentation
└── README.md # This file
```
## Configuration
The container includes:
- Python virtual environment at `/opt/fts.venv`
- FreeTAKHub-Installation repository at `/opt/FreeTAKHub-Installation`
- Configuration files based on the installation type
- Ansible playbooks for automated setup
## Environment Variables
- `INSTALL_TYPE`: Installation type (latest, stable, legacy)
- `TZ`: Timezone (default: UTC)
- `DEBIAN_FRONTEND`: Set to noninteractive for automated installation
- `PY3_VER`: Python version (automatically set based on install type)
- `FTS_VENV`: Virtual environment path
- `CFG_RPATH`: Configuration path (automatically set based on install type)
## Volumes
To persist data and configuration:
```yaml
volumes:
- freetak_data:/opt/freetak/data
- freetak_config:/opt/FreeTAKHub-Installation
```
## Health Checks
The container includes a built-in health check that monitors the FreeTAKServer process:
```bash
# Check container health
docker ps
# Look for "healthy" status
```
## Troubleshooting
### View Logs
```bash
docker logs freetak-server
```
### Access Container Shell
```bash
docker exec -it freetak-server /bin/bash
```
### Check Service Status
```bash
docker exec -it freetak-server /opt/healthcheck.sh
```
### Restart Container
```bash
docker restart freetak-server
```
## Building from Source
The Dockerfile is based on Ubuntu 22.04 and includes:
1. System dependencies (Python, Ansible, Git, etc.)
2. Python virtual environment setup
3. FreeTAKHub-Installation repository clone
4. Ansible playbook execution
5. Service configuration and startup scripts
## Security Notes
- The container runs as a non-root user (`freetak`)
- SSH keys are generated for internal use
- All dependencies are installed from official repositories
- The installation follows the official FreeTAKTeam procedures
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
This Docker container is based on the FreeTAKHub-Installation scripts, which are licensed under the Eclipse Public License 2.0 (EPL-2.0).
## Support
For issues related to FreeTAKServer itself, please refer to the [FreeTAKTeam GitHub repository](https://github.com/FreeTAKTeam/FreeTAKServer).
For Docker-specific issues, please check the container logs and ensure all required ports are available.

36
docker-compose.yml Normal file
View file

@ -0,0 +1,36 @@
version: '3.8'
services:
freetak:
build:
context: .
dockerfile: Dockerfile
container_name: freetak-server
ports:
- "8087:8087" # Main server port
- "8080:8080" # Web UI port
- "8443:8443" # HTTPS port
- "19023:19023" # FTS API port
environment:
- INSTALL_TYPE=latest # Options: latest, stable, legacy
- TZ=UTC
volumes:
- freetak_data:/opt/freetak/data
- freetak_config:/opt/FreeTAKHub-Installation
restart: unless-stopped
healthcheck:
test: ["CMD", "/opt/healthcheck.sh"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
- freetak_network
networks:
freetak_network:
driver: bridge
volumes:
freetak_data:
freetak_config:

655
freetak_install.sh Normal file
View file

@ -0,0 +1,655 @@
#!/usr/bin/env bash
#: Free TAK Server Installation Script
#: Original Author: John
#: Maintainers:
#: - Sypher
#: - nailshard
#:
#: This is an unmodified copy of a script from:
#: https://github.com/FreeTAKTeam/FreeTAKHub-Installation/blob/main/scripts/easy_install.sh
#:
#: Licensed under the Eclipse Public License 2.0 (EPL-2.0)
#: SPDX-License-Identifier: EPL-2.0
#: https://www.eclipse.org/legal/epl-2.0/
###############################################################################
# enforce failfast
set -o errexit
set -o nounset
set -o pipefail
# This disables Apt's "restart services" interactive dialog
export DEBIAN_FRONTEND=noninteractive
export NEEDRESTART_SUSPEND=1
NEEDRESTART=
# trap or catch signals and direct execution to cleanup
trap cleanup SIGINT SIGTERM ERR EXIT
DEFAULT_REPO="https://github.com/FreeTAKTeam/FreeTAKHub-Installation.git"
REPO=${REPO:-$DEFAULT_REPO}
DEFAULT_BRANCH="main"
BRANCH=${BRANCH:-$DEFAULT_BRANCH}
CBRANCH=${CBRANCH:-}
STABLE_OS_REQD="Ubuntu"
STABLE_OS_VER_REQD="22.04"
STABLE_CODENAME_REQD="jammy"
LEGACY_OS_REQD="Ubuntu"
LEGACY_OS_VER_REQD="20.04"
LEGACY_CODENAME_REQD="focal"
# the specific versions will be set later based on INSTALL_TYPE
DEFAULT_INSTALL_TYPE="latest"
INSTALL_TYPE="${INSTALL_TYPE:-$DEFAULT_INSTALL_TYPE}"
PY3_VER_LEGACY="3.8"
PY3_VER_STABLE="3.11"
STABLE_FTS_VERSION="2.0.66"
LEGACY_FTS_VERSION="1.9.9.6"
LATEST_FTS_VERSION=$(curl -s https://pypi.org/pypi/FreeTAKServer/json | python3 -c "import sys, json; print(json.load(sys.stdin)['info']['version'])")
FTS_VENV="${HOME}/fts.venv"
DRY_RUN=0
hsep="*********************"
#
###############################################################################
# Add coloration to output for highlighting or emphasizing words
###############################################################################
function setup_colors() {
if [[ -t 2 ]] && [[ -z "${NO_COLOR-}" ]] && [[ "${TERM-}" != "dumb" ]]; then
NOFORMAT='\033[0m'
RED='\033[0;31m'
GREEN='\033[0;32m'
# ORANGE='\033[0;33m' # unused
BLUE='\033[0;34m'
# PURPLE='\033[0;35m' # unused
# CYAN='\033[0;36m' # unused
YELLOW='\033[1;33m'
else
NOFORMAT=''
RED=''
GREEN=''
# ORANGE='' # unused
BLUE=''
# PURPLE='' # unused
# CYAN='' # unused
YELLOW=''
fi
}
###############################################################################
# Print out helpful message.
# Outputs:
# Writes usage message to stdout
###############################################################################
function usage() {
cat <<USAGE_TEXT
Usage: $(basename "${BASH_SOURCE[0]}") [<optional-arguments>]
Install Free TAK Server and components.
Available options:
-h, --help Print help
-v, --verbose Print script debug info
-c, --check Check for compatibility issues while installing
--core Install FreeTAKServer, UI, and Web Map
--latest [DEFAULT] Install latest version (v$LATEST_FTS_VERSION)
-s, --stable Install latest stable version (v$STABLE_FTS_VERSION)
-l, --legacy Install legacy version (v$LEGACY_FTS_VERSION)
--repo Replaces with specified ZT Installer repository [DEFAULT ${DEFAULT_REPO}]
--branch Use specified ZT Installer repository branch [DEFAULT main]
--dev-test Sets TEST Envar to 1
--dry-run Sets up dependencies but exits before running any playbooks
--ip-addr Explicitly set IP address (when http://ifconfig.me/ip is wrong)
USAGE_TEXT
exit
}
###############################################################################
# Cleanup here
###############################################################################
function cleanup() {
trap - SIGINT SIGTERM ERR EXIT
# script cleanup here
}
###############################################################################
# Echo a message
###############################################################################
function msg() {
echo >&2 -e "${1-}"
}
###############################################################################
# Exit gracefully
###############################################################################
function die() {
local msg=$1
local code=${2-1}
msg "$msg"
[[ $code -eq 0 ]] || echo -e "Exiting. Installation NOT successful."
# default exit status 1
exit "$code"
}
###############################################################################
# Parse parameters
###############################################################################
function parse_params() {
# The default 'apt verbosity' is verbose. Set it to quiet, since that's what our script assumes
# unset this later if we want verbosity
APT_VERBOSITY="-qq"
while true; do
case "${1-}" in
--help | -h)
usage
exit 0
shift
;;
--verbose | -v)
echo "Verbose output"
set -x
NO_COLOR=1
GIT_TRACE=true
GIT_CURL_VERBOSE=true
GIT_SSH_COMMAND="ssh -vvv"
unset APT_VERBOSITY # verbose is the default
ANSIBLE_VERBOSITY="-vvvvv"
shift
;;
--check | -c)
CHECK=1
shift
;;
--core)
CORE=1
shift
;;
--stable | -s)
INSTALL_TYPE="stable"
shift
;;
--latest)
INSTALL_TYPE="latest"
shift
;;
--legacy | -l)
INSTALL_TYPE="legacy"
shift
;;
-B)
echo "${RED}${hsep}${hsep}${hsep}"
echo -e "This option is not supported for public use.\n\
It will alter the version of this installer, which means:\n\
1. it may make breaking system alterations\n\
2. use at your own risk\n\
It is highly recommended that you do not continue\n\
unless you've selected this option for a specific reason"
echo "${hsep}${hsep}${hsep}${NOFORMAT}"
CBRANCH=$2
shift 2
;;
--repo)
REPO=$2
shift 2
if [[ -d ~/FreeTAKHub-Installation ]]
then rm -rf ~/FreeTAKHub-Installation
fi
;;
--branch)
BRANCH=$2
shift 2
;;
--dev-test)
TEST=1
shift
;;
--dry-run)
DRY_RUN=1
shift
;;
--ip-addr)
FTS_IP_CUSTOM=$2
shift 2
echo "Using the IP of ${FTS_IP_CUSTOM}"
;;
--no-color)
NO_COLOR=1
shift
;;
-?*)
die "ERROR: unknown option $1"
;;
*)
break
;;
esac
done
}
###############################################################################
# Update variables from defaults, user inputs or implied values
###############################################################################
function set_versions() {
case $INSTALL_TYPE in
latest)
export PY3_VER=$PY3_VER_STABLE
export FTS_VERSION=$LATEST_FTS_VERSION
export CFG_RPATH="core/configuration"
export OS_REQD=$STABLE_OS_REQD
export OS_VER_REQD=$STABLE_OS_VER_REQD
export CODENAME=$STABLE_CODENAME_REQD
;;
legacy)
export PY3_VER=$PY3_VER_LEGACY
export FTS_VERSION=$LEGACY_FTS_VERSION
export CFG_RPATH="controllers/configuration"
export OS_REQD=$LEGACY_OS_REQD
export OS_VER_REQD=$LEGACY_OS_VER_REQD
export CODENAME=$LEGACY_CODENAME_REQD
;;
stable)
export PY3_VER=$PY3_VER_STABLE
export FTS_VERSION=$STABLE_FTS_VERSION
export CFG_RPATH="core/configuration"
export OS_REQD=$STABLE_OS_REQD
export OS_VER_REQD=$STABLE_OS_VER_REQD
export CODENAME=$STABLE_CODENAME_REQD
;;
*)
die "Unsupport install type: $INSTALL_TYPE"
;;
esac
}
###############################################################################
# Do checks or skip unnecessary ones if non-interactive
###############################################################################
function do_checks() {
check_root
if [[ -n "${CHECK-}" ]]; then
check_os
# check_architecture
else
WEBMAP_FORCE_INSTALL="webmap_force_install=true"
fi
if [[ -n "${TEST-}" ]]; then
REPO="https://github.com/janseptaugust/FreeTAKHub-Installation.git"
fi
}
###############################################################################
# Check if script was ran as root. This script requires root execution.
###############################################################################
function check_root() {
echo -e -n "${BLUE}Checking if this script is running as root...${NOFORMAT}"
# check Effective User ID (EUID) for root user, which has an EUID of 0.
if [[ "$EUID" -ne 0 ]]; then
echo -e "${RED}ERROR${NOFORMAT}"
die "This script requires running as root. Use sudo before the command."
else
echo -e "${GREEN}Success!${NOFORMAT}"
fi
}
###############################################################################
# Check for supported operating system and warn user if not supported.
###############################################################################
function check_os() {
which apt-get >/dev/null
if [[ $? -ne 0 ]]; then
die "Could not locate apt... this installation method will not work"
fi
echo -e -n "${BLUE}Checking for supported OS...${NOFORMAT}"
# freedesktop.org and systemd
if [[ -f /etc/os-release ]]; then
. /etc/os-release
OS=${NAME:-unknown}
VER=${VERSION_ID:-unknown}
CODENAME=${VERSION_CODENAME}
# linuxbase.org
elif type lsb_release >/dev/null 2>&1; then
OS=$(lsb_release -si)
VER=$(lsb_release -sr)
# for some Debian-based distros
elif [[ -f /etc/lsb-release ]]; then
. /etc/lsb-release
OS=${DISTRIB_ID}
VER=${DISTRIB_RELEASE}
# older Debian-based distros
elif [[ -f /etc/debian_version ]]; then
OS=Debian
VER=$(cat /etc/debian_version)
# fallback
else
OS=$(uname -s)
VER=$(uname -r)
fi
# check for supported OS and version and warn if not supported
if [[ "${OS}" != "${OS_REQD}" ]] || [[ "${VER}" != "${OS_VER_REQD}" ]]; then
echo -e "${YELLOW}WARNING${NOFORMAT}"
echo "FreeTAKServer has only been tested on ${GREEN}${OS_REQD} ${OS_VER_REQD}${NOFORMAT}."
echo -e "This machine is currently running: ${YELLOW}${OS} ${VER}${NOFORMAT}"
echo "Errors may arise during installation or execution."
read -r -e -p "Do you want to continue? [y/n]: " PROCEED
# Default answer is "n" for NO.
DEFAULT="n"
# Set user-inputted value and apply default if user input is null.
PROCEED="${PROCEED:-${DEFAULT}}"
# Check user input to proceed or not.
if [[ "${PROCEED}" != "y" ]]; then
die "Answer was not y. Not proceeding."
else
echo -e "${GREEN}Proceeding...${NOFORMAT}"
fi
else
echo -e "${GREEN}Success!${NOFORMAT}"
echo -e "This machine is currently running: ${GREEN}${OS} ${VER}${NOFORMAT}"
echo -e "Selected install type is: ${GREEN}${DEFAULT_INSTALL_TYPE}"
fi
}
###############################################################################
# Check for supported architecture
###############################################################################
function check_architecture() {
echo -e -n "${BLUE}Checking for supported architecture...${NOFORMAT}"
# check for non-Intel-based architecture here
arch=$(uname --hardware-platform) # uname is non-portable, but we only target Ubuntu 20.04/22.04
if ! grep --ignore-case x86 <<<"${arch}" >/dev/null; then
echo -e "${YELLOW}WARNING${NOFORMAT}"
echo "Possible non-Intel architecture detected, ${name}"
echo "Non-intel architectures may cause problems. The web map might not install."
read -r -e -p "Do you want to force web map installation? [y/n]: " USER_INPUT
# Default answer is "n" for NO.
DEFAULT="n"
# Set user-inputted value and apply default if user input is null.
FORCE_WEBMAP_INSTALL_INPUT="${USER_INPUT:-${DEFAULT}}"
# Check user input to force install web map or not
if [[ "${FORCE_WEBMAP_INSTALL_INPUT}" != "y" ]]; then
echo -e "${YELLOW}WARNING${NOFORMAT}: installer may skip web map installation."
else
WEBMAP_FORCE_INSTALL="webmap_force_install=true"
echo -e "${YELLOW}WARNING${NOFORMAT}: forcing web map installation!"
fi
else # good architecture to install webmap
echo -e "${GREEN}Success!${NOFORMAT}"
echo "Intel architecture detected, ${name}"
fi
}
###############################################################################
# Download dependencies
###############################################################################
function download_dependencies() {
echo -e "${BLUE}Downloading dependencies...${NOFORMAT}"
echo -e "${BLUE}Adding the Ansible Personal Package Archive (PPA)...${NOFORMAT}"
# dpkg --list | grep -q needrestart && NEEDRESTART=1
# [[ 0 -eq $NEEDRESTART ]] || apt-get remove --yes needrestart
x=$(find /etc/apt/apt.conf.d -name "*needrestart*")
if [[ -f $x ]]; then
NEEDRESTART=$x
mv $x $HOME/nr-conf-temp
fi
# Some programs need predictable names for certain libraries, so symlink
x="pkg inst"
for y in $x; do
z=$(find /usr/lib -name apt_${y}.so)
if [[ -z $z ]]; then
z=$(find /usr/lib -name "apt_${y}.cpython*.so")
ln -sf $z $(dirname $z)/apt_${y}.so
fi
done
# Some Ubuntu installations do not have the software-properties-common
# package by default, so install it if not installed
which apt-add-repository >/dev/null || apt-get --yes install software-properties-common
apt-add-repository -y ppa:ansible/ansible
echo -e "${BLUE}Downloading package information from configured sources...${NOFORMAT}"
apt-get -y ${APT_VERBOSITY--qq} update
echo -e "${BLUE}Installing Ansible...${NOFORMAT}"
apt-get -y ${APT_VERBOSITY--qq} install ansible
echo -e "${BLUE}Installing Git...${NOFORMAT}"
apt-get -y ${APT_VERBOSITY--qq} install git
}
###############################################################################
# We can install the python virtual environment here including the python interpreter.
# This removes any need to deal with any circular requirement between
# the installer, Ansible, and its dependencies (e.g. jinja2) and
# the application being installed, FTS, and its dependencies.
###############################################################################
function install_python_environment() {
apt-get update
apt-get install -y python3-pip python3-setuptools
apt-get install -y python${PY3_VER}-dev python${PY3_VER}-venv libpython${PY3_VER}-dev
/usr/bin/python${PY3_VER} -m venv ${FTS_VENV}
source ${FTS_VENV}/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install --force-reinstall jinja2
python3 -m pip install --force-reinstall pyyaml
python3 -m pip install --force-reinstall psutil
deactivate
}
###############################################################################
# Handle git repository
###############################################################################
function handle_git_repository() {
echo -e -n "${BLUE}Checking for FreeTAKHub-Installation in home directory..."
cd ~
[[ -n $CBRANCH ]] && BRANCH=$CBRANCH
# check for FreeTAKHub-Installation repository
if [[ ! -d ~/FreeTAKHub-Installation ]]; then
echo -e "local working git tree NOT FOUND"
echo -e "Cloning the FreeTAKHub-Installation repository...${NOFORMAT}"
git clone --branch "${BRANCH}" ${REPO} ~/FreeTAKHub-Installation
cd ~/FreeTAKHub-Installation
else
echo -e "FOUND"
cd ~/FreeTAKHub-Installation
echo -e \
"Pulling latest from the FreeTAKHub-Installation repository...${NOFORMAT}"
git pull
git checkout "${BRANCH}"
fi
git pull
}
###############################################################################
# Add passwordless Ansible execution
###############################################################################
function add_passwordless_ansible_execution() {
echo -e \
"${BLUE}Adding passwordless Ansible execution for the current user...${NOFORMAT}"
# line to add
LINE="${USER} ALL=(ALL) NOPASSWD:/usr/bin/ansible-playbook"
# file to create for passwordless
FILE="/etc/sudoers.d/dont-prompt-${USER}-for-sudo-password"
# only add if non-existent
grep -qF -- "${LINE}" "${FILE}" || echo "${LINE}" >>"${FILE}"
}
###############################################################################
# Generate public and private keys
###############################################################################
function generate_key_pair() {
echo -e \
"${BLUE}Creating a public and private keys if non-existent...${NOFORMAT}"
# check for public and private keys
if [[ ! -e ${HOME}/.ssh/id_rsa.pub ]]; then
# generate keys
ssh-keygen -t rsa -f "${HOME}/.ssh/id_rsa" -N ""
fi
}
###############################################################################
# Run Ansible playbook to install
# https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#defining-variables-at-runtime
###############################################################################
function run_playbook() {
export CODENAME
export INSTALL_TYPE
export FTS_VERSION
env_vars="python3_version=$PY3_VER codename=$CODENAME itype=$INSTALL_TYPE"
env_vars="$env_vars fts_version=$FTS_VERSION cfg_rpath=$CFG_RPATH fts_venv=${FTS_VENV}"
[[ -n "${FTS_IP_CUSTOM:-}" ]] && env_vars="$env_vars fts_ip_addr_extra=$FTS_IP_CUSTOM"
[[ -n "${WEBMAP_FORCE_INSTALL:-}" ]] && env_vars="$env_vars $WEBMAP_FORCE_INSTALL"
[[ -n "${CORE:-}" ]] && pb=install_mainserver || pb=install_all
echo -e "${BLUE}Running Ansible Playbook ${GREEN}$pb${BLUE}...${NOFORMAT}"
ansible-playbook -u root ${pb}.yml \
--connection=local \
--inventory localhost, \
--extra-vars "$env_vars" \
${ANSIBLE_VERBOSITY-}
}
function cleanup() {
if [[ -n $NEEDRESTART ]]
then
cp $HOME/nr-conf-temp $NEEDRESTART
fi
}
###############################################################################
# MAIN BUSINESS LOGIC HERE
###############################################################################
setup_colors
parse_params "${@}"
set_versions
check_os
# do_checks
download_dependencies
[[ "$DEFAULT_INSTALL_TYPE" == "$INSTALL_TYPE" ]] && install_python_environment
handle_git_repository
add_passwordless_ansible_execution
generate_key_pair
[[ 0 -eq $DRY_RUN ]] || die "Dry run complete. Not running Ansible" 0
run_playbook
cleanup

44
run.sh Executable file
View file

@ -0,0 +1,44 @@
#!/bin/bash
# Build and run FreeTAKServer with different installation types
set -e
INSTALL_TYPE=${1:-latest}
CONTAINER_NAME="freetak-server"
IMAGE_NAME="freetak-server"
echo "Building FreeTAKServer Docker image with install type: $INSTALL_TYPE"
# Stop and remove existing container if it exists
if docker ps -a --format 'table {{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "Stopping and removing existing container..."
docker stop $CONTAINER_NAME || true
docker rm $CONTAINER_NAME || true
fi
# Build the Docker image
echo "Building Docker image..."
docker build -t $IMAGE_NAME .
# Run the container
echo "Starting FreeTAKServer container..."
docker run -d \
--name $CONTAINER_NAME \
-p 8087:8087 \
-p 8080:8080 \
-p 8443:8443 \
-p 19023:19023 \
-e INSTALL_TYPE=$INSTALL_TYPE \
-e TZ=UTC \
--restart unless-stopped \
$IMAGE_NAME
echo "FreeTAKServer is starting up..."
echo "Web UI will be available at: http://localhost:8080"
echo "Main server API at: http://localhost:8087"
echo "API endpoint at: http://localhost:19023"
echo ""
echo "Use 'docker logs $CONTAINER_NAME' to view the logs"
echo "Use 'docker exec -it $CONTAINER_NAME /bin/bash' to access the container"
echo ""
echo "To stop the container: docker stop $CONTAINER_NAME"

134
scripts/README.md Normal file
View file

@ -0,0 +1,134 @@
# FreeTAKServer Docker Scripts
This directory contains the scripts used by the FreeTAKServer Docker container. These scripts have been extracted from the Dockerfile for better maintainability and easier development.
## Scripts Overview
### `install_freetak.sh`
- **Purpose**: Installs FreeTAKServer using Ansible playbooks
- **Usage**: Called during Docker build process
- **Environment Variables**:
- `INSTALL_TYPE`: Installation type (latest, stable, legacy)
- `FTS_VENV`: Path to Python virtual environment
- `STABLE_FTS_VERSION`: Stable version number
- `LEGACY_FTS_VERSION`: Legacy version number
- `CFG_RPATH`: Configuration path
### `start_freetak.sh`
- **Purpose**: Simple startup script for FreeTAKServer
- **Usage**: Basic container startup (deprecated, use entrypoint.sh)
- **Environment Variables**:
- `FTS_VENV`: Path to Python virtual environment
- `CFG_RPATH`: Configuration path
### `entrypoint.sh`
- **Purpose**: Main entrypoint script with signal handling and logging
- **Usage**: Default container entrypoint
- **Features**:
- Graceful shutdown handling
- Proper signal forwarding
- Timestamped logging
- Dynamic configuration path detection
- Environment-based configuration
### `healthcheck.sh`
- **Purpose**: Health check script for Docker container
- **Usage**: Called by Docker healthcheck
- **Functionality**: Checks if FreeTAKServer process is running
### `dev-helper.sh`
- **Purpose**: Development helper script for validation and testing
- **Usage**: `./scripts/dev-helper.sh [validate|test|info|help]`
- **Features**:
- Script validation
- Syntax checking
- Information display
- Development workflow support
## Development Workflow
1. **Validate Scripts**: Ensure all scripts exist and are executable
```bash
./scripts/dev-helper.sh validate
```
2. **Test Syntax**: Check all scripts for syntax errors
```bash
./scripts/dev-helper.sh test
```
3. **View Information**: Display script information
```bash
./scripts/dev-helper.sh info
```
## Script Maintenance
### Adding New Scripts
1. Create the script in the `scripts/` directory
2. Make it executable: `chmod +x scripts/your-script.sh`
3. Add it to the Dockerfile `COPY` instruction
4. Update the `dev-helper.sh` script to include validation
### Modifying Existing Scripts
1. Edit the script file directly
2. Test syntax: `./scripts/dev-helper.sh test`
3. Rebuild the Docker image to apply changes
### Best Practices
- Always include proper error handling (`set -e`)
- Use descriptive variable names
- Add comments for complex logic
- Follow consistent formatting
- Test scripts before committing
## Environment Variables
The scripts use these key environment variables:
- `FTS_VENV`: Python virtual environment path (default: `/opt/fts.venv`)
- `INSTALL_TYPE`: Installation type - `latest`, `stable`, or `legacy`
- `CFG_RPATH`: Configuration path (auto-detected based on install type)
- `STABLE_FTS_VERSION`: Stable version number
- `LEGACY_FTS_VERSION`: Legacy version number
## Troubleshooting
### Script Not Executable
```bash
chmod +x scripts/script-name.sh
```
### Syntax Errors
```bash
bash -n scripts/script-name.sh
```
### Testing Individual Scripts
```bash
# Test in container context
docker run --rm -it freetak-server /bin/bash
# Then run: /opt/script-name.sh
```
### Debugging
Add `set -x` at the beginning of scripts to enable debug output.
## Integration with Dockerfile
The scripts are copied into the container during build:
```dockerfile
# Copy the scripts
COPY scripts/install_freetak.sh /opt/install_freetak.sh
COPY scripts/start_freetak.sh /opt/start_freetak.sh
COPY scripts/healthcheck.sh /opt/healthcheck.sh
COPY scripts/entrypoint.sh /opt/entrypoint.sh
# Make the scripts executable
RUN chmod +x /opt/*.sh
```
## License
These scripts are part of the FreeTAKServer Docker container project and follow the same licensing as the original FreeTAKHub-Installation project (Eclipse Public License 2.0).

160
scripts/dev-helper.sh Executable file
View file

@ -0,0 +1,160 @@
#!/bin/bash
# Development helper script for FreeTAKServer Docker container
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Function to check if script exists and is executable
check_script() {
local script_path="$1"
local script_name=$(basename "$script_path")
if [[ ! -f "$script_path" ]]; then
print_error "Script $script_name not found at $script_path"
return 1
fi
if [[ ! -x "$script_path" ]]; then
print_warning "Script $script_name is not executable, fixing..."
chmod +x "$script_path"
fi
print_success "Script $script_name is ready"
return 0
}
# Function to validate scripts
validate_scripts() {
print_status "Validating scripts..."
local scripts=(
"$PROJECT_DIR/scripts/install_freetak.sh"
"$PROJECT_DIR/scripts/start_freetak.sh"
"$PROJECT_DIR/scripts/healthcheck.sh"
"$PROJECT_DIR/scripts/entrypoint.sh"
)
local all_valid=true
for script in "${scripts[@]}"; do
if ! check_script "$script"; then
all_valid=false
fi
done
if [[ "$all_valid" == true ]]; then
print_success "All scripts are valid and executable"
else
print_error "Some scripts have issues"
exit 1
fi
}
# Function to test script syntax
test_syntax() {
print_status "Testing script syntax..."
local scripts=(
"$PROJECT_DIR/scripts/install_freetak.sh"
"$PROJECT_DIR/scripts/start_freetak.sh"
"$PROJECT_DIR/scripts/healthcheck.sh"
"$PROJECT_DIR/scripts/entrypoint.sh"
)
for script in "${scripts[@]}"; do
local script_name=$(basename "$script")
if bash -n "$script"; then
print_success "Syntax check passed for $script_name"
else
print_error "Syntax check failed for $script_name"
exit 1
fi
done
}
# Function to show script information
show_info() {
print_status "FreeTAKServer Docker Scripts Information"
echo
echo "Scripts directory: $PROJECT_DIR/scripts/"
echo
echo "Available scripts:"
echo " install_freetak.sh - Installs FreeTAKServer using Ansible"
echo " start_freetak.sh - Simple startup script"
echo " entrypoint.sh - Main entrypoint with signal handling"
echo " healthcheck.sh - Health check script"
echo
echo "Usage in Dockerfile:"
echo " COPY scripts/ /opt/scripts/"
echo " RUN chmod +x /opt/scripts/*.sh"
echo
}
# Function to show usage
usage() {
echo "Usage: $0 [COMMAND]"
echo
echo "Commands:"
echo " validate Validate all scripts exist and are executable"
echo " test Test script syntax"
echo " info Show information about scripts"
echo " help Show this help message"
echo
echo "If no command is provided, 'validate' is run by default."
}
# Main script logic
main() {
case "${1:-validate}" in
validate)
validate_scripts
;;
test)
validate_scripts
test_syntax
;;
info)
show_info
;;
help|--help|-h)
usage
;;
*)
print_error "Unknown command: $1"
usage
exit 1
;;
esac
}
# Change to project directory
cd "$PROJECT_DIR"
# Run main function
main "$@"

68
scripts/entrypoint.sh Executable file
View file

@ -0,0 +1,68 @@
#!/bin/bash
set -e
# Function to log messages with timestamp
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
# Function to handle signals for graceful shutdown
cleanup() {
log "Received shutdown signal, stopping FreeTAKServer..."
if [ -n "$FTS_PID" ]; then
kill -TERM "$FTS_PID" 2>/dev/null || true
wait "$FTS_PID" 2>/dev/null || true
fi
log "FreeTAKServer stopped"
exit 0
}
# Set up signal handlers
trap cleanup SIGTERM SIGINT
# Source the virtual environment
log "Activating Python virtual environment..."
source ${FTS_VENV}/bin/activate
# Set up environment variables based on install type
case ${INSTALL_TYPE} in
legacy)
export CFG_RPATH=controllers/configuration
log "Using legacy configuration path: ${CFG_RPATH}"
;;
*)
export CFG_RPATH=core/configuration
log "Using standard configuration path: ${CFG_RPATH}"
;;
esac
# Change to the configuration directory
CONFIG_DIR="/opt/FreeTAKHub-Installation/${CFG_RPATH}"
if [ -d "$CONFIG_DIR" ]; then
log "Changing to configuration directory: $CONFIG_DIR"
cd "$CONFIG_DIR"
else
log "WARNING: Configuration directory not found at $CONFIG_DIR"
log "Attempting to start from FreeTAKHub-Installation root..."
cd /opt/FreeTAKHub-Installation
fi
# Start FreeTAKServer
log "Starting FreeTAKServer (Install Type: ${INSTALL_TYPE})..."
log "Python version: $(python3 --version)"
log "Working directory: $(pwd)"
# Start the service in the background to allow signal handling
python3 -m FreeTAKServer.controllers.services.FTS &
FTS_PID=$!
log "FreeTAKServer started with PID: $FTS_PID"
log "FreeTAKServer is running. Use Ctrl+C to stop."
# Wait for the background process
wait "$FTS_PID"
# Deactivate virtual environment
deactivate
log "FreeTAKServer has stopped"

4
scripts/healthcheck.sh Executable file
View file

@ -0,0 +1,4 @@
#!/bin/bash
# Simple healthcheck - check if the FTS process is running
pgrep -f "FreeTAKServer" > /dev/null
exit $?

49
scripts/install_freetak.sh Executable file
View file

@ -0,0 +1,49 @@
#!/bin/bash
set -e
# Source the virtual environment
source ${FTS_VENV}/bin/activate
# Set up environment variables
export CODENAME=jammy
export INSTALL_TYPE=${INSTALL_TYPE:-latest}
export FTS_VERSION=${STABLE_FTS_VERSION}
export PY3_VER=${PY3_VER}
export CFG_RPATH=${CFG_RPATH}
export FTS_VENV=${FTS_VENV}
# Determine FTS version based on install type
case ${INSTALL_TYPE} in
latest)
export FTS_VERSION=$(curl -s https://pypi.org/pypi/FreeTAKServer/json | python3 -c "import sys, json; print(json.load(sys.stdin)[\"info\"][\"version\"])" 2>/dev/null || echo "${STABLE_FTS_VERSION}")
;;
stable)
export FTS_VERSION=${STABLE_FTS_VERSION}
;;
legacy)
export FTS_VERSION=${LEGACY_FTS_VERSION}
export PY3_VER=3.8
export CFG_RPATH=controllers/configuration
;;
esac
# Set up Ansible variables
env_vars="python3_version=${PY3_VER} codename=${CODENAME} itype=${INSTALL_TYPE}"
env_vars="${env_vars} fts_version=${FTS_VERSION} cfg_rpath=${CFG_RPATH} fts_venv=${FTS_VENV}"
env_vars="${env_vars} webmap_force_install=true"
# Run Ansible playbook
cd /opt/FreeTAKHub-Installation
echo "Installing FreeTAKServer with the following settings:"
echo " Version: ${FTS_VERSION}"
echo " Python: ${PY3_VER}"
echo " Install Type: ${INSTALL_TYPE}"
echo " Virtual Environment: ${FTS_VENV}"
ansible-playbook -u root install_all.yml \
--connection=local \
--inventory localhost, \
--extra-vars "${env_vars}" \
-v
deactivate

14
scripts/start_freetak.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
set -e
# Source the virtual environment
source ${FTS_VENV}/bin/activate
# Change to the configuration directory
cd /opt/FreeTAKHub-Installation/${CFG_RPATH}
# Start FreeTAKServer
echo "Starting FreeTAKServer..."
python3 -m FreeTAKServer.controllers.services.FTS
deactivate