Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
O
osrm-server-setup
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Bambang Adrian Sitompul
osrm-server-setup
Commits
59b40cbf
Commit
59b40cbf
authored
Oct 16, 2025
by
Bambang Adrian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(osrm): release v2.4 fixing bugs for motorcycle profile, and filepath
parent
b4677cf5
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
251 additions
and
766 deletions
+251
-766
scripts/install-osrm-ngpm.sh
+251
-766
No files found.
scripts/install-osrm-ngpm.sh
View file @
59b40cbf
...
...
@@ -2,102 +2,63 @@
#
# install-osrm-ngpm.sh
# OSRM + NGPM installer & manager (Rocky Linux 10)
# Final self-contained script (v
1.0.1 - Patched
)
# Final self-contained script (v
2.4 - Lua Profile Path Fix
)
#
set
-euo
pipefail
IFS
=
$'
\n\t
'
# -------------------------
# DEFAULTS
(internal variables use snake_case)
# DEFAULTS
# -------------------------
DEFAULT_WORK_DIR
=
"
${
HOME
}
/data/docker-data/osrm"
DEFAULT_MAP_DIR
=
"
${
DEFAULT_WORK_DIR
}
/dataset"
DEFAULT_PROFILE_DIR
=
"
${
DEFAULT_WORK_DIR
}
/profiles"
DEFAULT_PATCHED_DIR
=
"
${
DEFAULT_WORK_DIR
}
/patched-profiles"
DEFAULT_BACKUP_DIR
=
"
${
DEFAULT_WORK_DIR
}
/backup"
DEFAULT_LOG_DIR
=
"
${
DEFAULT_WORK_DIR
}
/logs"
DEFAULT_BACKEND_REGISTRY
=
"ghcr.io/project-osrm/osrm-backend"
DEFAULT_FRONTEND_REGISTRY
=
"ghcr.io/project-osrm/osrm-frontend"
DEFAULT_BACKEND_VERSION
=
"latest"
DEFAULT_FRONTEND_VERSION
=
"latest"
DEFAULT_MAP_SOURCE
=
"https://download.geofrik.de/asia/indonesia-latest.osm.pbf"
DEFAULT_MAP_SOURCE
=
"https://download.geof
ab
rik.de/asia/indonesia-latest.osm.pbf"
DEFAULT_NETWORK
=
"ngpm-network"
DEFAULT_PROFILES
=
"car"
DEFAULT_BACKEND_PORT
=
5000
DEFAULT_FRONTEND_PORT
=
9966
DEFAULT_BACKEND_DOMAIN
=
"
localhost
"
DEFAULT_FRONTEND_DOMAIN
=
"
localhost
"
DEFAULT_BACKEND_DOMAIN
=
"
osrm.example.com
"
DEFAULT_FRONTEND_DOMAIN
=
"
map.example.com
"
DEFAULT_BACKEND_PATH
=
"/osrm"
DEFAULT_API_VERSION
=
"v1"
DEFAULT_NO_FRONTEND
=
false
DEFAULT_NO_BACKEND
=
false
# -------------------------
# RUN-TIME VARIABLES
(overridden by CLI)
# RUN-TIME VARIABLES
# -------------------------
work_dir
=
"
${
DEFAULT_WORK_DIR
}
"
map_dir
=
"
${
DEFAULT_MAP_DIR
}
"
profile_dir
=
"
${
DEFAULT_PROFILE_DIR
}
"
patched_dir
=
"
${
DEFAULT_PATCHED_DIR
}
"
backup_dir
=
"
${
DEFAULT_BACKUP_DIR
}
"
log_dir
=
"
${
DEFAULT_LOG_DIR
}
"
backend_registry
=
"
${
DEFAULT_BACKEND_REGISTRY
}
"
frontend_registry
=
"
${
DEFAULT_FRONTEND_REGISTRY
}
"
backend_version
=
"
${
DEFAULT_BACKEND_VERSION
}
"
frontend_version
=
"
${
DEFAULT_FRONTEND_VERSION
}
"
map_name
=
"default"
map_source
=
"
${
DEFAULT_MAP_SOURCE
}
"
network_name
=
"
${
DEFAULT_NETWORK
}
"
profiles_csv
=
"
${
DEFAULT_PROFILES
}
"
network_name
=
"
${
DEFAULT_NETWORK
}
"
backend_port
=
"
${
DEFAULT_BACKEND_PORT
}
"
frontend_port
=
"
${
DEFAULT_FRONTEND_PORT
}
"
backend_domain
=
"
${
DEFAULT_BACKEND_DOMAIN
}
"
frontend_domain
=
"
${
DEFAULT_FRONTEND_DOMAIN
}
"
backend_path
=
"
${
DEFAULT_BACKEND_PATH
}
"
api_version
=
"
${
DEFAULT_API_VERSION
}
"
no_frontend
=
"
${
DEFAULT_NO_FRONTEND
}
"
no_backend
=
"
${
DEFAULT_NO_BACKEND
}
"
no_frontend
=
false
dry_run
=
false
print_config
=
false
yes_all
=
false
# update/remove flags (granular)
do_update_backend
=
false
do_update_frontend
=
false
do_update_map
=
false
do_update_profile
=
false
do_update_all
=
false
do_remove_backend
=
false
do_remove_frontend
=
false
do_remove_profile
=
false
do_remove_map
=
false
do_remove_all
=
false
do_purge
=
false
map_arg
=
""
# explicit --map-source given (URL or path) override var map_source
# derived
MAP_PATH
=
""
COMPOSE_FILE
=
""
LOGFILE
=
""
NGPM_HINTS
=
""
MAP_PATH
=
""
PROFILE_ARR
=()
# -------------------------
# Logging helpers
# -------------------------
timestamp
()
{
date
'+%Y-%m-%d %H:%M:%S'
;
}
logfile_init
()
{
mkdir
-p
"
${
log_dir
}
"
LOGFILE
=
"
${
log_dir
}
/osrm-installer-
$(
date
'+%Y%m%d_%H%M%S'
)
.log"
:
>
"
${
LOGFILE
}
"
}
_log
()
{
local
lvl
=
"
$1
"
;
shift
local
ts
;
ts
=
"
$(
timestamp
)
"
printf
"%s [%s] %s
\n
"
"
$ts
"
"
$lvl
"
"
$*
"
| tee
-a
"
${
LOGFILE
}
"
local
lvl
=
"
$1
"
;
shift
local
ts
;
ts
=
"
$(
timestamp
)
"
if
[[
-n
"
${
LOGFILE
:-}
"
]]
;
then
printf
"%s [%s] %s
\n
"
"
$ts
"
"
$lvl
"
"
$*
"
>>
"
${
LOGFILE
}
"
;
fi
printf
"%s [%s] %s
\n
"
"
$ts
"
"
$lvl
"
"
$*
"
}
info
()
{
_log
"INFO"
"
$*
"
;
}
success
()
{
_log
"SUCCESS"
"
$*
"
;
}
...
...
@@ -109,398 +70,183 @@ err() { _log "ERROR" "$*" >&2; }
# -------------------------
usage
()
{
cat
<<
EOF
install-osrm-ngpm.sh - OSRM + NGPM installer & manager (Rocky Linux 10
)
OSRM Installer & Manager v2.4 (Multi-Map Support
)
Usage:
$0
<command> [options]
$0
<command>
--map-name <name>
[options]
Commands:
install Install and run OSRM backend + frontend (unless disabled)
update <component> Update a specific component (backend, frontend, map, profile, all)
remove <component> Remove a specific component (backend, frontend, profile, all)
Install Options:
--map-source <url|path> Map URL or local file path (default:
${
DEFAULT_MAP_SOURCE
}
)
--profiles <csv> Profiles to enable (car,motorcycle,bike,foot). Default '
${
DEFAULT_PROFILES
}
'
--backend-domain <domain> Domain for backend URLs (default:
${
DEFAULT_BACKEND_DOMAIN
}
)
--frontend-domain <domain> Domain for frontend (default:
${
DEFAULT_FRONTEND_DOMAIN
}
)
--backend-port <port> Host start port for backend mapping (default:
${
DEFAULT_BACKEND_PORT
}
)
--frontend-port <port> Host port for frontend UI (default:
${
DEFAULT_FRONTEND_PORT
}
)
--no-frontend Do NOT install frontend (frontend is installed by default)
--no-backend Do NOT install backend
--dry-run Simulate steps
--yes Non-interactive (answer Yes to all prompts)
-h, --help Show this help
Update Command:
$0
update <backend|frontend|map|profile|all> [--map-source <url|path>]
Remove Command:
$0
remove <backend|frontend|profile|all> [--purge]
Examples:
Install default:
$0
install
Install with multiple profiles:
$0
install --profiles car,motorcycle,bike,foot
Update only map (local file):
$0
update map --map-source /data/osm/indonesia-latest.osm.pbf
Remove all components and data:
$0
remove all --purge
install Install a new OSRM instance.
update <component> Update a component (backend, frontend, map, profile, all).
remove Remove an OSRM instance.
Required Argument:
--map-name <name> A unique name for this map instance (e.g., 'indonesia').
Options:
--map-source <url|path> Map URL or local file path.
--profiles <csv> Profiles to enable (car,motorcycle,bike,foot).
--backend-port <port> Host start port for backend services.
--frontend-port <port> Host port for the frontend UI.
--no-frontend Do NOT install the frontend UI.
--purge Also delete all data directories on remove.
--dry-run Simulate steps without executing.
--yes Answer 'yes' to all prompts.
-h, --help Show this help message.
EOF
exit
0
}
# -------------------------
#
Parse args
#
Argument Parsing & Setup
# -------------------------
if
[
$#
-eq
0
]
;
then
usage
;
fi
command_name
=
"
$1
"
;
shift
||
true
# Sub-command for update/remove
sub_command
=
""
if
[[
"
${
command_name
}
"
==
"update"
||
"
${
command_name
}
"
==
"remove"
]]
;
then
if
[
$#
-gt
0
]
&&
!
[[
"
$1
"
=
~ ^--
]]
;
then
sub_command
=
"
$1
"
shift
parse_args
()
{
if
[
$#
-eq
0
]
;
then
usage
;
fi
command_name
=
"
$1
"
;
shift
||
true
sub_command
=
""
if
[[
"
${
command_name
}
"
==
"update"
]]
;
then
if
[
$#
-gt
0
]
&&
!
[[
"
$1
"
=
~ ^--
]]
;
then
sub_command
=
"
$1
"
;
shift
;
else
err
"Update command requires a component."
;
usage
;
fi
fi
fi
while
((
"$#"
))
;
do
case
"
$1
"
in
--work-dir
)
work_dir
=
"
${
2
/#\~/
$HOME
}
"
;
shift
2
;;
--map-source
)
map_source
=
"
${
2
}
"
;
map_arg
=
"
${
2
}
"
;
shift
2
;;
--map-dir
)
map_dir
=
"
${
2
/#\~/
$HOME
}
"
;
shift
2
;;
--profiles
)
profiles_csv
=
"
${
2
}
"
;
shift
2
;;
--profile-dir
)
profile_dir
=
"
${
2
/#\~/
$HOME
}
"
;
shift
2
;;
--backend-registry
)
backend_registry
=
"
$2
"
;
shift
2
;;
--frontend-registry
)
frontend_registry
=
"
$2
"
;
shift
2
;;
--backend-version
)
backend_version
=
"
$2
"
;
shift
2
;;
--frontend-version
)
frontend_version
=
"
$2
"
;
shift
2
;;
--backend-port
)
backend_port
=
"
$2
"
;
shift
2
;;
--frontend-port
)
frontend_port
=
"
$2
"
;
shift
2
;;
--network
)
network_name
=
"
$2
"
;
shift
2
;;
--backend-domain
)
backend_domain
=
"
$2
"
;
shift
2
;;
--frontend-domain
)
frontend_domain
=
"
$2
"
;
shift
2
;;
--backend-path
)
backend_path
=
"
$2
"
;
shift
2
;;
--api-version
)
api_version
=
"
$2
"
;
shift
2
;;
--no-frontend
)
no_frontend
=
true
;
shift
;;
--no-backend
)
no_backend
=
true
;
shift
;;
--dry-run
)
dry_run
=
true
;
shift
;;
--print-config
)
print_config
=
true
;
shift
;;
--purge
)
do_purge
=
true
;
shift
;;
--yes
)
yes_all
=
true
;
shift
;;
-h
|
--help
)
usage
;;
*
)
warn
"Unknown option:
$1
"
;
shift
;;
esac
done
# normalize & mkdirs
work_dir
=
"
${
work_dir
/#\~/
$HOME
}
"
map_dir
=
"
${
map_dir
/#\~/
$HOME
}
"
profile_dir
=
"
${
profile_dir
/#\~/
$HOME
}
"
patched_dir
=
"
${
patched_dir
/#\~/
$HOME
}
"
backup_dir
=
"
${
backup_dir
/#\~/
$HOME
}
"
log_dir
=
"
${
log_dir
/#\~/
$HOME
}
"
mkdir
-p
"
${
work_dir
}
"
"
${
map_dir
}
"
"
${
profile_dir
}
"
"
${
patched_dir
}
"
"
${
backup_dir
}
"
"
${
log_dir
}
"
COMPOSE_FILE
=
"
${
work_dir
}
/docker-compose.yml"
NGPM_HINTS
=
"
${
work_dir
}
/ngpm-config.txt"
logfile_init
# parse profiles csv -> array
IFS
=
','
read
-r
-a
PROFILE_ARR
<<<
"
$(
echo
"
${
profiles_csv
}
"
| tr
-d
'[:space:]'
)
"
if
[
"
${#
PROFILE_ARR
[@]
}
"
-eq
0
]
;
then
PROFILE_ARR
=(
car
)
;
fi
BACKEND_IMAGE
=
"
${
backend_registry
}
:
${
backend_version
}
"
FRONTEND_IMAGE
=
"
${
frontend_registry
}
:
${
frontend_version
}
"
info
"Command:
${
command_name
}
"
info
"Work dir:
${
work_dir
}
"
info
"Log dir:
${
log_dir
}
"
info
"Network:
${
network_name
}
"
info
"Backend image:
${
BACKEND_IMAGE
}
"
info
"Frontend image:
${
FRONTEND_IMAGE
}
"
info
"Profiles:
${
profiles_csv
}
"
info
"Dry run:
${
dry_run
}
"
[
-n
"
${
map_arg
}
"
]
&&
info
"Map source override:
${
map_arg
}
"
while
((
"$#"
))
;
do
case
"
$1
"
in
--map-name
)
map_name
=
"
$2
"
;
shift
2
;;
--work-dir
)
work_dir
=
"
${
2
/#\~/
$HOME
}
"
;
shift
2
;;
--map-source
)
map_source
=
"
$2
"
;
shift
2
;;
--profiles
)
profiles_csv
=
"
$2
"
;
shift
2
;;
--backend-port
)
backend_port
=
"
$2
"
;
shift
2
;;
--frontend-port
)
frontend_port
=
"
$2
"
;
shift
2
;;
--network
)
network_name
=
"
$2
"
;
shift
2
;;
--backend-domain
)
backend_domain
=
"
$2
"
;
shift
2
;;
--frontend-domain
)
frontend_domain
=
"
$2
"
;
shift
2
;;
--no-frontend
)
no_frontend
=
true
;
shift
;;
--dry-run
)
dry_run
=
true
;
shift
;;
--purge
)
do_purge
=
true
;
shift
;;
--yes
)
yes_all
=
true
;
shift
;;
-h
|
--help
)
usage
;;
*
)
err
"Unknown option:
$1
"
;
usage
;;
esac
done
if
[[
"
${
map_name
}
"
==
"default"
&&
"
${
command_name
}
"
!=
"install"
]]
;
then
err
"The --map-name argument is required."
;
usage
;
fi
work_dir
=
"
${
work_dir
/#\~/
$HOME
}
"
;
local
log_dir
=
"
${
work_dir
}
/logs"
;
mkdir
-p
"
${
work_dir
}
"
"
${
log_dir
}
"
LOGFILE
=
"
${
log_dir
}
/osrm-manager-
$(
date
'+%Y%m%d_%H%M%S'
)
.log"
:
>
"
${
LOGFILE
}
"
COMPOSE_FILE
=
"
${
work_dir
}
/docker-compose.
${
map_name
}
.yml"
IFS
=
','
read
-r
-a
PROFILE_ARR
<<<
"
$(
echo
"
${
profiles_csv
}
"
| tr
-d
'[:space:]'
)
"
if
[
"
${#
PROFILE_ARR
[@]
}
"
-eq
0
]
;
then
PROFILE_ARR
=(
car
)
;
fi
}
# -------------------------
# Helper
f
unctions
# Helper
F
unctions
# -------------------------
command_exists
()
{
command
-v
"
$1
"
>
/dev/null 2>&1
;
}
ensure_package
()
{
local
pkg
=
"
$1
"
if
command_exists
"
$pkg
"
;
then
info
"Dependency found:
${
pkg
}
"
return
0
fi
info
"Dependency missing:
${
pkg
}
"
if
[
"
$(
id
-u
)
"
-ne
0
]
;
then
warn
"Cannot auto-install
${
pkg
}
because script is not running as root. Please run: sudo dnf install -y
${
pkg
}
"
return
1
fi
info
"Attempting to install
${
pkg
}
via dnf..."
if
dnf install
-y
"
${
pkg
}
"
;
then
success
"Installed
${
pkg
}
"
return
0
else
warn
"Failed to auto-install
${
pkg
}
. Please install manually."
return
1
fi
}
prereqs_check
()
{
local
ok
=
0
if
!
command_exists docker
;
then
err
"docker not found. Please install docker and ensure the docker daemon is running."
ok
=
1
fi
if
!
docker compose version
>
/dev/null 2>&1
;
then
warn
"docker compose plugin not found. Attempting to install docker-compose-plugin via dnf (requires root)."
if
!
ensure_package docker-compose-plugin
;
then
err
"docker compose plugin not available. Please install docker compose manually."
ok
=
1
fi
fi
for
util
in
curl wget
tar
awk sed
;
do
if
!
command_exists
"
$util
"
;
then
info
"Utility
${
util
}
missing; attempting to install"
if
!
ensure_package
"
$util
"
;
then
warn
"Please install
${
util
}
manually."
ok
=
1
fi
fi
done
if
[
${
ok
}
-ne
0
]
;
then
err
"Prerequisite checks failed. Aborting."
exit
1
fi
info
"Running prerequisite checks..."
local
ok
=
0
if
!
command_exists docker
;
then
err
"Docker is not installed."
;
ok
=
1
;
fi
if
!
docker compose version
>
/dev/null 2>&1
;
then
err
"Docker Compose V2 plugin is not installed."
;
ok
=
1
;
fi
if
!
command_exists curl
;
then
err
"curl is not installed."
;
ok
=
1
;
fi
if
[
${
ok
}
-ne
0
]
;
then
err
"Prerequisite checks failed."
;
exit
1
;
fi
success
"All prerequisites are met."
}
# SELinux label detection for mounts
SELINUX_LABEL
=
""
if
command_exists sestatus
&&
sestatus 2>/dev/null |
grep
-qi
"SELinux status:.*enabled"
;
then
SELINUX_LABEL
=
":z"
info
"SELinux is enabled. Will append ':z' to bind mounts for context."
fi
# prompt helper
ask_confirm
()
{
local
prompt
=
"
$1
"
;
shift
if
[
"
${
yes_all
}
"
=
true
]
;
then
info
"[auto-yes]
${
prompt
}
-> yes"
return
0
fi
while
true
;
do
printf
"%s [y/N]: "
"
${
prompt
}
"
read
-r
yn
case
"
${
yn
}
"
in
[
Yy]
*
)
return
0
;;
[
Nn]
*
|
""
)
return
1
;;
*
)
echo
"Please answer y or n."
;;
esac
done
}
# -------------------------
# Map selection logic
# -------------------------
select_map
()
{
info
"Selecting map..."
local
map_target_source
=
"
${
map_arg
:-${
map_source
}}
"
if
[[
"
${
map_target_source
}
"
=
~ ^https?://
]]
;
then
MAP_PATH
=
"
${
map_dir
}
/
$(
basename
"
${
map_target_source
}
"
)
"
download_map_if_needed
"
${
map_target_source
}
"
"
${
MAP_PATH
}
"
return
0
fi
if
[
-f
"
${
map_target_source
}
"
]
;
then
MAP_PATH
=
"
$(
realpath
"
${
map_target_source
}
"
)
"
info
"Using user-provided local map:
${
MAP_PATH
}
"
return
0
fi
# Fallback to default if nothing works
local
default_file
=
"
${
map_dir
}
/
$(
basename
"
${
DEFAULT_MAP_SOURCE
}
"
)
"
if
[
-f
"
${
default_file
}
"
]
;
then
MAP_PATH
=
"
${
default_file
}
"
info
"Found existing default map:
${
MAP_PATH
}
"
return
0
fi
MAP_PATH
=
"
${
default_file
}
"
download_map_if_needed
"
${
DEFAULT_MAP_SOURCE
}
"
"
${
MAP_PATH
}
"
setup_selinux_flag
()
{
if
command_exists sestatus
&&
sestatus 2>/dev/null |
grep
-qi
"SELinux status:.*enabled"
;
then
SELINUX_LABEL
=
",z"
info
"SELinux is enabled. Appending ',z' to volume mounts."
fi
}
download_map_if_needed
()
{
local
url
=
"
$1
"
;
local
dest
=
"
$2
"
info
"Preparing map:
${
url
}
->
${
dest
}
"
if
[
-f
"
${
dest
}
"
]
;
then
info
"Map already exists at
${
dest
}
. Skipping download."
return
0
fi
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would download
${
url
}
to
${
dest
}
"
# Create a dummy file for dry-run to proceed
touch
"
${
dest
}
"
return
0
fi
mkdir
-p
"
$(
dirname
"
${
dest
}
"
)
"
info
"Downloading with curl..."
if
!
curl
-L
--fail
-o
"
${
dest
}
.tmp"
"
${
url
}
"
;
then
rm
-f
"
${
dest
}
.tmp"
err
"Download failed for
${
url
}
"
exit
1
fi
mv
"
${
dest
}
.tmp"
"
${
dest
}
"
success
"Map downloaded:
${
dest
}
"
ask_confirm
()
{
local
prompt
=
"
$1
"
if
[
"
${
yes_all
}
"
=
true
]
;
then
info
"[auto-yes]
${
prompt
}
-> yes"
;
return
0
;
fi
while
true
;
do
printf
"%s [y/N]: "
"
${
prompt
}
"
read
-r
yn
case
"
${
yn
}
"
in
[
Yy]
*
)
return
0
;;
[
Nn]
*
|
""
)
return
1
;;
*
)
echo
"Please answer y or n."
;;
esac
done
}
# -------------------------
# Profile generation & patching
# -------------------------
generate_profile_wrappers
()
{
info
"Generating profile wrappers in
${
profile_dir
}
(if missing)"
mkdir
-p
"
${
profile_dir
}
"
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
local
pf
=
"
${
profile_dir
}
/
${
profile
}
.lua"
if
[
-f
"
${
pf
}
"
]
;
then
info
"Profile exists:
${
pf
}
"
continue
# Core Logic
# -------------------------
download_map
()
{
info
"Preparing map from source:
${
map_source
}
"
local
map_instance_dir
=
"
${
work_dir
}
/
${
map_name
}
/dataset"
mkdir
-p
"
${
map_instance_dir
}
"
MAP_PATH
=
"
${
map_instance_dir
}
/
$(
basename
"
${
map_source
}
"
)
"
if
[[
-f
"
${
MAP_PATH
}
"
]]
;
then
info
"Map file already exists. Skipping download."
;
return
0
;
fi
if
[[
"
${
map_source
}
"
=
~ ^https?://
]]
;
then
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would download map to
${
MAP_PATH
}
"
;
return
0
;
fi
info
"Downloading map with curl..."
;
if
!
curl
-L
--fail
-o
"
${
MAP_PATH
}
.tmp"
"
${
map_source
}
"
;
then
rm
-f
"
${
MAP_PATH
}
.tmp"
;
err
"Download failed."
;
exit
1
;
fi
mv
"
${
MAP_PATH
}
.tmp"
"
${
MAP_PATH
}
"
;
success
"Map downloaded successfully."
elif
[[
-f
"
${
map_source
}
"
]]
;
then
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would copy local map to
${
MAP_PATH
}
"
;
return
0
;
fi
info
"Copying local map file..."
;
cp
-v
"
${
map_source
}
"
"
${
MAP_PATH
}
"
;
success
"Local map copied."
else
err
"Map source '
${
map_source
}
' is not a valid URL or an existing file."
;
exit
1
;
fi
case
"
${
profile
}
"
in
car|bicycle|bike|foot
)
info
"Generating wrapper for
${
profile
}
"
# This generic wrapper loads the built-in profile from the container
cat
>
"
${
pf
}
"
<<
LUA
-- wrapper: attempt to load builtin profile '
${
profile
}
'
local function load_builtin(name)
local cands = {"/opt/profiles/"..name..".lua", "/opt/"..name..".lua"}
for _,p in ipairs(cands) do
local f = io.open(p,"r"
)
if f then f:close(); return dofile(p) end
end
error("builtin profile not found: "..name)
end
return
load_builtin('
${
profile
}
')
}
generate_profiles
()
{
info
"Generating profile files for map instance '
${
map_name
}
'
"
local
profile_dir
=
"
${
work_dir
}
/
${
map_name
}
/profiles"
;
local
patched_dir
=
"
${
work_dir
}
/
${
map_name
}
/patched-profiles"
mkdir
-p
"
${
profile_dir
}
"
"
${
patched_dir
}
"
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
local
pf
=
"
${
profile_dir
}
/
${
profile
}
.lua"
if
[
!
-f
"
${
pf
}
"
]
;
then
case
"
${
profile
}
"
in
car|bicycle|bike|foot
)
info
"Generating wrapper for built-in profile:
${
profile
}
"
# --- FIX IS HERE (v2.4) ---
# The correct path inside the container is /opt/*.lua, not /opt/profiles/*.lua
cat
>
"
${
pf
}
"
<<
LUA
return
dofile('/opt/
${
profile
}
.lua
')
LUA
success
"Generated wrapper:
${
pf
}
"
;;
motorcycle
)
info
"Generating motorcycle wrapper based on car"
# FIX: This version correctly modifies the car profile without breaking its internal scope.
cat
>
"
${
pf
}
"
<<
'
LUA
'
-- motorcycle wrapper derived from car profile (v2 - Robust)
local function load_builtin(name)
local candidates = {
"/opt/profiles/" .. name .. ".lua",
"/opt/" .. name .. ".lua"
}
for _, path in ipairs(candidates) do
local f = io.open(path, "r")
if f then
f:close()
return dofile(path)
end
end
error("Built-in profile not found: " .. name)
end
-- Load the entire module returned by the car profile
local car_module = load_builtin('car')
-- Get the profile data table by calling its setup function
local profile_table = car_module.setup()
-- Modify the profile table in-place
profile_table.properties.max_speed = 100
profile_table.properties.u_turn_penalty = 60
profile_table.restrictions = profile_table.restrictions or {}
profile_table.restrictions["toll"] = "prohibited"
-- Redefine the setup function in the original module to return our modified profile
car_module.setup = function()
return profile_table
end
-- Return the entire, modified module. This preserves all functions
-- like process_node, process_way, etc. in their original context.
;;
motorcycle
)
info
"Generating custom 'motorcycle' profile based on 'car'"
# --- FIX IS HERE (v2.4) ---
cat
>
"
${
pf
}
"
<<
'
LUA
'
local car_module = dofile('/opt/car.lua')
local profile = car_module.setup()
profile.properties.max_speed = 100
profile.properties.u_turn_penalty = 60
profile.restrictions = profile.restrictions or {}
profile.restrictions["toll"] = "prohibited"
car_module.setup = function() return profile end
return car_module
LUA
success
"Generated motorcycle wrapper:
${
pf
}
"
;;
*
)
warn
"No generator for profile '
${
profile
}
'. Provide
${
pf
}
manually."
;;
esac
done
;;
*
)
warn
"No generator for profile '
${
profile
}
'."
;
continue
;;
esac
fi
;
cp
"
${
pf
}
"
"
${
patched_dir
}
/
${
profile
}
.lua"
done
;
success
"Profile generation complete."
}
create_patched_profiles
()
{
info
"Creating patched profiles in
${
patched_dir
}
(safe copies with arg fallback)"
mkdir
-p
"
${
patched_dir
}
"
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
local
src
=
"
${
profile_dir
}
/
${
profile
}
.lua"
local
dst
=
"
${
patched_dir
}
/
${
profile
}
.lua"
if
[
!
-f
"
${
src
}
"
]
;
then
warn
"Profile source not found:
${
src
}
(skipping patch)"
continue
fi
# This patch helps profiles find their own name if they rely on arg[0]
{
printf
'local arg = arg or {}\n'
printf
'arg[0] = arg[0] or "%s"\n'
"
${
profile
}
"
printf
'\n'
cat
"
${
src
}
"
}
>
"
${
dst
}
.tmp"
mv
"
${
dst
}
.tmp"
"
${
dst
}
"
info
"Patched profile written:
${
dst
}
"
done
}
# -------------------------
# Docker Compose generation (absolute host paths)
# -------------------------
generate_docker_compose
()
{
info
"Generating docker-compose.yml at
${
COMPOSE_FILE
}
"
mkdir
-p
"
$(
dirname
"
${
COMPOSE_FILE
}
"
)
"
local
selabel
=
"
${
SELINUX_LABEL
:-}
"
local
services
=
""
local
idx
=
0
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
idx
=
$((
idx+1
))
local
host_port
=
$((
backend_port
+
idx
-
1
))
local
pdata
=
"
${
work_dir
}
/
${
profile
}
-data"
mkdir
-p
"
${
pdata
}
"
services+
=
"
osrm-preprocess-
${
profile
}
:
image:
${
BACKEND_IMAGE
}
container_name: osrm-preprocess-
${
profile
}
info
"Generating Docker Compose file:
${
COMPOSE_FILE
}
"
local
map_instance_dir
=
"
${
work_dir
}
/
${
map_name
}
"
;
local
selabel
=
"
${
SELINUX_LABEL
:-}
"
;
local
services
=
""
;
local
idx
=
0
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
idx
=
$((
idx+1
))
;
local
host_port
=
$((
backend_port
+
idx
-
1
))
;
local
pdata
=
"
${
map_instance_dir
}
/
${
profile
}
-data"
;
mkdir
-p
"
${
pdata
}
"
services+
=
"
osrm-preprocess-
${
map_name
}
-
${
profile
}
:
image:
${
DEFAULT_BACKEND_REGISTRY
}
:
${
DEFAULT_BACKEND_VERSION
}
container_name: osrm-preprocess-
${
map_name
}
-
${
profile
}
command: >
sh -c
\"
osrm-extract -p /opt/custom_profiles/
${
profile
}
.lua /data/map.osm.pbf &&
osrm-partition /data/map.osrm &&
osrm-customize /data/map.osrm
\"
volumes:
-
${
patched_dir
}
:/opt/custom_profiles:ro
${
selabel
}
-
${
pdata
}
:/data
${
selabel
}
-
${
map_instance_dir
}
/patched-profiles
:/opt/custom_profiles:ro
${
selabel
}
-
${
pdata
}
:/data
:rw
${
selabel
}
networks:
-
${
network_name
}
osrm-routed-
${
profile
}
:
image:
${
BACKEND_IMAGE
}
container_name: osrm-routed-
${
profile
}
osrm-routed-
${
map_name
}
-
${
profile
}
:
image:
${
DEFAULT_BACKEND_REGISTRY
}
:
${
DEFAULT_BACKEND_VERSION
}
container_name: osrm-routed-
${
map_name
}
-
${
profile
}
restart: unless-stopped
depends_on:
- osrm-preprocess-
${
profile
}
command: osrm-routed --algorithm mld --max-table-size 10000 /data/map.osrm
command: osrm-routed --algorithm mld /data/map.osrm
volumes:
-
${
pdata
}
:/data:ro
${
selabel
}
ports:
...
...
@@ -508,27 +254,15 @@ generate_docker_compose() {
networks:
-
${
network_name
}
"
done
local
frontend_block
=
""
if
[
"
${
no_frontend
}
"
!=
true
]
;
then
local
backend_urls
=
""
local
idx2
=
0
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
idx2
=
$((
idx2+1
))
local
host_port
=
$((
backend_port
+
idx2
-
1
))
local
url
=
"http://
${
backend_domain
}
:
${
host_port
}${
backend_path
}
/
${
api_version
}
/
${
profile
}
"
if
[
-z
"
${
backend_urls
}
"
]
;
then
backend_urls
=
"
${
url
}
"
else
backend_urls
=
"
${
backend_urls
}
,
${
url
}
"
fi
done
frontend_block+
=
"
osrm-frontend:
image:
${
FRONTEND_IMAGE
}
container_name: osrm-frontend
local
frontend_block
=
""
;
if
[
"
${
no_frontend
}
"
!=
true
]
;
then
local
backend_urls
=
""
;
local
idx2
=
0
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
idx2
=
$((
idx2+1
))
;
local
host_port
=
$((
backend_port
+
idx2
-
1
))
;
local
url
=
"http://
${
backend_domain
}
:
${
host_port
}${
backend_path
}
/
${
api_version
}
/
${
profile
}
"
;
backend_urls+
=
"
${
url
}
,"
;
done
backend_urls
=
${
backend_urls
%,
}
frontend_block+
=
"
osrm-frontend-
${
map_name
}
:
image:
${
DEFAULT_FRONTEND_REGISTRY
}
:
${
DEFAULT_FRONTEND_VERSION
}
container_name: osrm-frontend-
${
map_name
}
restart: unless-stopped
environment:
- VITE_DEFAULT_BACKEND_URLS=
${
backend_urls
}
...
...
@@ -537,366 +271,117 @@ generate_docker_compose() {
networks:
-
${
network_name
}
"
fi
# FIX: Removed the obsolete 'version' attribute
cat
>
"
${
COMPOSE_FILE
}
"
<<
EOF
services:
${
services
}
${
frontend_block
}
fi
cat
>
"
${
COMPOSE_FILE
}
"
<<
EOF
services:
${
services
}${
frontend_block
}
networks:
${
network_name
}
:
external: true
name:
${
network_name
}
EOF
success
"docker-compose.yml written to
${
COMPOSE_FILE
}
"
}
# -------------------------
# Ensure docker network
# -------------------------
ensure_network
()
{
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would ensure docker network '
${
network_name
}
' exists"
return
0
fi
if
docker network inspect
"
${
network_name
}
"
>
/dev/null 2>&1
;
then
info
"Docker network '
${
network_name
}
' exists"
else
info
"Creating docker network '
${
network_name
}
'"
docker network create
"
${
network_name
}
"
fi
}
# -------------------------
# Pull images
# -------------------------
pull_images
()
{
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would pull images"
return
0
fi
info
"Pulling latest images..."
docker pull
"
${
BACKEND_IMAGE
}
"
||
warn
"docker pull backend failed"
if
[
"
${
no_frontend
}
"
!=
true
]
;
then
docker pull
"
${
FRONTEND_IMAGE
}
"
||
warn
"docker pull frontend failed"
fi
}
# -------------------------
# Preprocess sequential
# -------------------------
preprocess_sequential
()
{
info
"Starting sequential preprocessing for profiles:
${
profiles_csv
}
"
if
[
!
-f
"
${
MAP_PATH
}
"
]
;
then
err
"Map file not found at
${
MAP_PATH
}
. Cannot preprocess."
return
1
fi
local
any_failed
=
false
local
idx
=
0
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
idx
=
$((
idx+1
))
info
"=== Preprocessing (
${
idx
}
/
${#
PROFILE_ARR
[@]
}
):
${
profile
}
==="
local
pdata
=
"
${
work_dir
}
/
${
profile
}
-data"
mkdir
-p
"
${
pdata
}
"
safe_copy_map
"
${
MAP_PATH
}
"
"
${
pdata
}
/map.osm.pbf"
local
service_name
=
"osrm-preprocess-
${
profile
}
"
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would run preprocessing for
${
profile
}
"
continue
fi
# FIX: Use --exit-code-from for reliable error detection
info
"Running preprocessor container for '
${
profile
}
'... This may take a long time."
if
docker compose
-f
"
${
COMPOSE_FILE
}
"
up
--build
--exit-code-from
"
${
service_name
}
"
"
${
service_name
}
"
;
then
success
"Preprocessing for '
${
profile
}
' completed successfully."
else
err
"Preprocessing for '
${
profile
}
' FAILED. Check container logs above for details."
any_failed
=
true
if
!
ask_confirm
"Preprocessing for '
${
profile
}
' failed. Continue with other profiles?"
;
then
err
"Aborting installation due to preprocessing failure."
exit
1
fi
fi
# Clean up the one-shot container
docker compose
-f
"
${
COMPOSE_FILE
}
"
rm
-fsv
"
${
service_name
}
"
>
/dev/null 2>&1
||
true
done
if
[[
"
${
any_failed
}
"
==
"true"
]]
;
then
warn
"One or more preprocessing steps failed. The corresponding routing services will not be started."
fi
}
safe_copy_map
()
{
local
src
=
"
$1
"
;
local
dest
=
"
$2
"
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would copy
${
src
}
->
${
dest
}
"
return
0
fi
mkdir
-p
"
$(
dirname
"
${
dest
}
"
)
"
if
[
!
-f
"
${
src
}
"
]
;
then
err
"Map source file does not exist:
${
src
}
"
exit
1
fi
info
"Copying map to processing directory:
${
dest
}
"
cp
-f
"
${
src
}
"
"
${
dest
}
"
}
# -------------------------
# Start routed services
# -------------------------
start_routed_services
()
{
info
"Starting routed services..."
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would start routed containers via docker compose"
return
0
fi
local
services_to_start
=()
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
local
pdata
=
"
${
work_dir
}
/
${
profile
}
-data"
# Check if preprocessing was successful by looking for the output files
if
[
-f
"
${
pdata
}
/map.osrm"
]
;
then
services_to_start+
=(
"osrm-routed-
${
profile
}
"
)
else
warn
"Skipping 'osrm-routed-
${
profile
}
' because preprocessed data was not found in
${
pdata
}
"
fi
done
if
[
${#
services_to_start
[@]
}
-eq
0
]
;
then
err
"No successfully preprocessed profiles found. Cannot start any routing services."
return
1
fi
info
"Starting services:
${
services_to_start
[*]
}
"
docker compose
-f
"
${
COMPOSE_FILE
}
"
up
-d
--remove-orphans
"
${
services_to_start
[@]
}
"
success
"Routed services started."
}
# -------------------------
# Start frontend
# -------------------------
start_frontend
()
{
if
[
"
${
no_frontend
}
"
=
true
]
;
then
info
"Frontend installation skipped (--no-frontend)"
return
0
fi
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Would start osrm-frontend via docker compose"
return
0
fi
info
"Starting frontend service..."
docker compose
-f
"
${
COMPOSE_FILE
}
"
up
-d
--remove-orphans
osrm-frontend
success
"Frontend started on host port
${
frontend_port
}
"
success
"Docker Compose file written successfully."
}
# -------------------------
#
NGPM hint
s
#
Command Implementation
s
# -------------------------
generate_ngpm_hints
()
{
info
"Generating NGPM hints at
${
NGPM_HINTS
}
"
{
echo
"--- OSRM & NGPM (Nginx Proxy Manager) Configuration ---"
echo
"Date:
$(
date
)
"
echo
echo
"This file provides hints for configuring your public-facing domains in NGPM."
echo
"Ensure your NGPM container is connected to the '
${
network_name
}
' Docker network."
echo
echo
"BACKEND SERVICES:"
printf
"%-15s | %-25s | %-35s
\n
"
"Profile"
"Container Target"
"Public URL Example"
echo
"--------------------------------------------------------------------------------"
local
idx
=
0
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
idx
=
$((
idx+1
))
local
host_port
=
$((
backend_port
+
idx
-
1
))
local
container_target
=
"osrm-routed-
${
profile
}
:5000"
local
url_example
=
"https://
${
backend_domain
}${
backend_path
}
/
${
api_version
}
/
${
profile
}
"
printf
"%-15s | %-25s | %-35s
\n
"
"
${
profile
}
"
"
${
container_target
}
"
"
${
url_example
}
"
done
echo
if
[
"
${
no_frontend
}
"
!=
true
]
;
then
echo
"FRONTEND UI:"
printf
"%-15s | %-25s | %-35s
\n
"
"UI"
"osrm-frontend:9966"
"https://
${
frontend_domain
}
"
echo
"--------------------------------------------------------------------------------"
fi
}
>
"
${
NGPM_HINTS
}
"
success
"NGPM hints saved to
${
NGPM_HINTS
}
"
info
"--- NGPM Hints Preview ---"
cat
"
${
NGPM_HINTS
}
"
info
"------------------------"
}
# -------------------------
# Print config
# -------------------------
print_configuration
()
{
echo
"--- Installation Summary ---"
echo
"Work Directory:
${
work_dir
}
"
echo
"Docker Compose:
${
COMPOSE_FILE
}
"
echo
"Docker Network:
${
network_name
}
"
echo
"Map Source Used:
${
MAP_PATH
}
"
echo
"Profiles Active:
${
profiles_csv
}
"
echo
echo
"ACCESS POINTS:"
local
idx
=
0
run_install
()
{
info
"Starting OSRM installation for map instance: '
${
map_name
}
'"
if
[
-f
"
${
COMPOSE_FILE
}
"
]
&&
!
ask_confirm
"Instance '
${
map_name
}
' may exist. Re-running will recreate containers. Continue?"
;
then
info
"Installation aborted."
;
exit
0
;
fi
download_map
;
generate_profiles
;
generate_docker_compose
if
[
"
${
dry_run
}
"
=
true
]
;
then
warn
"[DRY RUN] Skipping network and container startup."
;
return
;
fi
info
"Ensuring Docker network '
${
network_name
}
' exists..."
;
docker network create
"
${
network_name
}
"
>
/dev/null 2>&1
||
info
"Network already exists."
info
"Pulling latest Docker images..."
;
docker pull
"
${
DEFAULT_BACKEND_REGISTRY
}
:
${
DEFAULT_BACKEND_VERSION
}
"
;
if
[[
"
${
no_frontend
}
"
!=
"true"
]]
;
then
docker pull
"
${
DEFAULT_FRONTEND_REGISTRY
}
:
${
DEFAULT_FRONTEND_VERSION
}
"
;
fi
info
"Starting data preprocessing..."
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
idx
=
$((
idx
+
1
))
local
host_port
=
$((
backend_port
+
idx
-
1
))
echo
" - Backend (
${
profile
}
): http://
${
backend_domain
}
:
${
host_port
}${
backend_path
}
/
${
api_version
}
/
${
profile
}
"
local
pdata_dir
=
"
${
work_dir
}
/
${
map_name
}
/
${
profile
}
-data"
info
"Preparing map file for profile '
${
profile
}
'..."
cp
-vf
"
${
MAP_PATH
}
"
"
${
pdata_dir
}
/map.osm.pbf"
local
service_name
=
"osrm-preprocess-
${
map_name
}
-
${
profile
}
"
info
"--- Processing profile:
${
profile
}
---"
if
docker compose
-f
"
${
COMPOSE_FILE
}
"
up
--build
--exit-code-from
"
${
service_name
}
"
"
${
service_name
}
"
;
then
success
"Preprocessing for '
${
profile
}
' completed."
else
err
"Preprocessing for '
${
profile
}
' FAILED. Check logs for details."
docker compose
-f
"
${
COMPOSE_FILE
}
"
rm
-fsv
"
${
service_name
}
"
>
/dev/null 2>&1
||
true
if
!
ask_confirm
"Continue with other profiles?"
;
then
err
"Aborting installation."
;
exit
1
;
fi
fi
docker compose
-f
"
${
COMPOSE_FILE
}
"
rm
-fsv
"
${
service_name
}
"
>
/dev/null 2>&1
||
true
done
if
[
"
${
no_frontend
}
"
!=
true
]
;
then
echo
" - Frontend UI: http://
${
frontend_domain
}
:
${
frontend_port
}
"
fi
echo
"--------------------------"
info
"Starting all services for instance '
${
map_name
}
'..."
;
docker compose
-f
"
${
COMPOSE_FILE
}
"
up
-d
--remove-orphans
success
"Installation for '
${
map_name
}
' completed!"
;
print_summary
}
# -------------------------
# Update logic
# -------------------------
run_update
()
{
info
"Update flow started for component:
${
sub_command
}
"
prereqs_check
info
"Starting update for instance '
${
map_name
}
', component '
${
sub_command
}
'"
if
[
!
-f
"
${
COMPOSE_FILE
}
"
]
;
then
err
"Instance '
${
map_name
}
' not found."
;
exit
1
;
fi
case
"
${
sub_command
}
"
in
backend
)
pull_images
start_routed_services
;;
frontend
)
pull_images
start_frontend
;;
map
)
select_map
preprocess_sequential
start_routed_services
;;
profile
)
generate_profile_wrappers
create_patched_profiles
preprocess_sequential
start_routed_services
backend|frontend|all
)
info
"Pulling latest images..."
;
docker pull
"
${
DEFAULT_BACKEND_REGISTRY
}
:
${
DEFAULT_BACKEND_VERSION
}
"
if
[[
"
${
sub_command
}
"
!=
"backend"
]]
;
then
docker pull
"
${
DEFAULT_FRONTEND_REGISTRY
}
:
${
DEFAULT_FRONTEND_VERSION
}
"
;
fi
info
"Recreating services..."
;
docker compose
-f
"
${
COMPOSE_FILE
}
"
up
-d
--remove-orphans
;;
all
)
pull_images
generate_profile_wrappers
create_patched_profiles
select_map
preprocess_sequential
start_routed_services
start_frontend
;;
*
)
err
"Invalid update component '
${
sub_command
}
'. Use one of: backend, frontend, map, profile, all."
exit
1
;;
esac
success
"Update flow completed."
}
# -------------------------
# Remove logic
# -------------------------
run_remove
()
{
info
"Remove flow started for component:
${
sub_command
}
"
if
[
!
-f
"
${
COMPOSE_FILE
}
"
]
;
then
warn
"Docker compose file not found at
${
COMPOSE_FILE
}
. Assuming components are already removed."
fi
local
services_to_remove
=()
case
"
${
sub_command
}
"
in
backend
)
map|profile
)
if
[[
"
${
sub_command
}
"
==
"map"
]]
;
then
download_map
;
fi
if
[[
"
${
sub_command
}
"
==
"profile"
]]
;
then
generate_profiles
;
fi
info
"Re-running preprocessing..."
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
services_to_remove+
=(
"osrm-routed-
${
profile
}
"
)
local
pdata_dir
=
"
${
work_dir
}
/
${
map_name
}
/
${
profile
}
-data"
info
"Preparing map file for profile '
${
profile
}
'..."
cp
-vf
"
${
MAP_PATH
}
"
"
${
pdata_dir
}
/map.osm.pbf"
local
service_name
=
"osrm-preprocess-
${
map_name
}
-
${
profile
}
"
docker compose
-f
"
${
COMPOSE_FILE
}
"
up
--build
--exit-code-from
"
${
service_name
}
"
"
${
service_name
}
"
||
err
"Preprocessing failed for
${
profile
}
"
docker compose
-f
"
${
COMPOSE_FILE
}
"
rm
-fsv
"
${
service_name
}
"
>
/dev/null 2>&1
||
true
done
info
"Restarting services..."
;
docker compose
-f
"
${
COMPOSE_FILE
}
"
up
-d
--remove-orphans
;;
frontend
)
services_to_remove+
=(
"osrm-frontend"
)
;;
profile
)
if
ask_confirm
"This will delete all profile files from
${
profile_dir
}
and
${
patched_dir
}
. Continue?"
;
then
rm
-rf
"
${
profile_dir
}
"
"
${
patched_dir
}
"
success
"Profile directories removed."
fi
return
;;
all
)
if
ask_confirm
"This will STOP and REMOVE ALL OSRM containers. Proceed?"
;
then
docker compose
-f
"
${
COMPOSE_FILE
}
"
down
-v
--remove-orphans
||
warn
"Could not stop all containers. They may not be running."
success
"All containers stopped and removed."
if
[[
"
${
do_purge
}
"
==
"true"
]]
;
then
if
ask_confirm
"PURGE active. This will DELETE the entire work directory:
${
work_dir
}
. THIS IS IRREVERSIBLE. Proceed?"
;
then
rm
-rf
"
${
work_dir
}
"
success
"Work directory purged."
fi
fi
fi
return
;;
*
)
err
"Invalid remove component '
${
sub_command
}
'. Use one of: backend, frontend, profile, all."
exit
1
;;
*
)
err
"Invalid update component."
;
exit
1
;;
esac
if
[
${#
services_to_remove
[@]
}
-gt
0
]
;
then
info
"Stopping and removing services:
${
services_to_remove
[*]
}
"
docker compose
-f
"
${
COMPOSE_FILE
}
"
rm
-fsv
"
${
services_to_remove
[@]
}
"
||
warn
"Failed to remove some services."
success
"Update for '
${
map_name
}
' completed."
}
run_remove
()
{
info
"Starting removal of OSRM instance: '
${
map_name
}
'"
if
[
!
-f
"
${
COMPOSE_FILE
}
"
]
;
then
warn
"Instance '
${
map_name
}
' not found."
;
fi
if
ask_confirm
"This will STOP and REMOVE all containers for instance '
${
map_name
}
'. Are you sure?"
;
then
if
[
-f
"
${
COMPOSE_FILE
}
"
]
;
then
docker compose
-f
"
${
COMPOSE_FILE
}
"
down
-v
||
warn
"Could not stop containers."
;
rm
-f
"
${
COMPOSE_FILE
}
"
;
fi
success
"All containers for '
${
map_name
}
' have been removed."
if
[[
"
${
do_purge
}
"
==
"true"
]]
;
then
info
"Purging data for removed services..."
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
if
[[
"
${
sub_command
}
"
==
"backend"
||
"
${
sub_command
}
"
==
"all"
]]
;
then
rm
-rf
"
${
work_dir
}
/
${
profile
}
-data"
info
"Purged
${
work_dir
}
/
${
profile
}
-data"
fi
done
local
instance_dir
=
"
${
work_dir
}
/
${
map_name
}
"
if
ask_confirm
"PURGE ENABLED. This will DELETE '
${
instance_dir
}
'. IRREVERSIBLE. Proceed?"
;
then
rm
-rf
"
${
instance_dir
}
"
;
success
"Instance data for '
${
map_name
}
' has been purged."
fi
fi
else
info
"Removal aborted by user."
;
fi
}
print_summary
()
{
echo
"--- Instance '
${
map_name
}
' Summary ---"
echo
"Compose File:
${
COMPOSE_FILE
}
"
;
echo
"Map Source:
${
MAP_PATH
}
"
;
echo
"Profiles:
${
profiles_csv
}
"
echo
;
echo
"ACCESS POINTS (Example):"
local
idx
=
0
for
profile
in
"
${
PROFILE_ARR
[@]
}
"
;
do
idx
=
$((
idx
+
1
))
;
local
host_port
=
$((
backend_port
+
idx
-
1
))
echo
" - Backend (
${
profile
}
): http://localhost:
${
host_port
}${
backend_path
}
/
${
api_version
}
/
${
profile
}
"
echo
" (NGPM Target: osrm-routed-
${
map_name
}
-
${
profile
}
:5000)"
done
if
[
"
${
no_frontend
}
"
!=
true
]
;
then
echo
" - Frontend UI: http://localhost:
${
frontend_port
}
"
;
echo
" (NGPM Target: osrm-frontend-
${
map_name
}
:9966)"
fi
success
"Remove flow completed.
"
echo
"--------------------------
"
}
# -------------------------
# Main
d
ispatcher
# Main
D
ispatcher
# -------------------------
case
"
${
command_name
}
"
in
install
)
info
"Install flow started"
prereqs_check
select_map
generate_profile_wrappers
create_patched_profiles
pull_images
generate_docker_compose
ensure_network
preprocess_sequential
start_routed_services
start_frontend
generate_ngpm_hints
main
()
{
parse_args
"
$@
"
prereqs_check
;
setup_selinux_flag
info
"Starting script execution."
;
info
"Command:
${
command_name
}
, Map Instance:
${
map_name
}
"
case
"
${
command_name
}
"
in
install
)
run_install
;;
update
)
run_update
;;
remove
)
run_remove
;;
*
)
err
"Unknown command:
${
command_name
}
"
;
usage
;;
esac
info
"Script execution finished."
}
success
"Install flow completed"
print_configuration
;;
update
)
run_update
;;
remove
)
run_remove
;;
*
)
err
"Unknown command:
${
command_name
}
"
usage
;;
esac
\ No newline at end of file
main
"
$@
"
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment