nixpkgs/nixos/tests/nominatim.nix
2025-07-09 16:17:56 +02:00

188 lines
5.2 KiB
Nix

{ pkgs, lib, ... }:
let
# Andorra - the smallest dataset in Europe (3.1 MB)
osmData = pkgs.fetchurl {
url = "https://web.archive.org/web/20250430211212/https://download.geofabrik.de/europe/andorra-latest.osm.pbf";
hash = "sha256-Ey+ipTOFUm80rxBteirPW5N4KxmUsg/pCE58E/2rcyE=";
};
in
{
name = "nominatim";
meta = {
maintainers = with lib.teams; [
geospatial
ngi
];
};
nodes = {
# nominatim - self contained host
nominatim =
{ config, pkgs, ... }:
{
# Nominatim
services.nominatim = {
enable = true;
hostName = "nominatim";
settings = {
NOMINATIM_IMPORT_STYLE = "admin";
};
ui = {
config = ''
Nominatim_Config.Page_Title='Test Nominatim instance';
Nominatim_Config.Nominatim_API_Endpoint='https://localhost/';
'';
};
};
# Disable SSL
services.nginx.virtualHosts.nominatim = {
forceSSL = false;
enableACME = false;
};
# Database
services.postgresql = {
enableTCPIP = true;
authentication = lib.mkForce ''
local all all trust
host all all 0.0.0.0/0 md5
host all all ::0/0 md5
'';
};
systemd.services.postgresql-setup.postStart = ''
psql --command "ALTER ROLE \"nominatim-api\" WITH PASSWORD 'password';"
'';
networking.firewall.allowedTCPPorts = [ config.services.postgresql.settings.port ];
};
# api - web API only
api =
{ config, pkgs, ... }:
{
# Database password
system.activationScripts = {
passwordFile.text = with config.services.nominatim.database; ''
mkdir -p /run/secrets
echo "${host}:${toString port}:${dbname}:${apiUser}:password" \
> /run/secrets/pgpass
chown nominatim-api:nominatim-api /run/secrets/pgpass
chmod 0600 /run/secrets/pgpass
'';
};
# Nominatim
services.nominatim = {
enable = true;
hostName = "nominatim";
settings = {
NOMINATIM_LOG_DB = "yes";
};
database = {
host = "nominatim";
passwordFile = "/run/secrets/pgpass";
extraConnectionParams = "application_name=nominatim;connect_timeout=2";
};
};
# Disable SSL
services.nginx.virtualHosts.nominatim = {
forceSSL = false;
enableACME = false;
};
};
};
testScript = ''
# Test nominatim host
nominatim.start()
nominatim.wait_for_unit("nominatim.service")
# Import OSM data
nominatim.succeed("""
cd /tmp
sudo -u nominatim \
NOMINATIM_DATABASE_WEBUSER=nominatim-api \
NOMINATIM_IMPORT_STYLE=admin \
nominatim import --continue import-from-file --osm-file ${osmData}
""")
nominatim.succeed("systemctl restart nominatim.service")
# Test CLI
nominatim.succeed("sudo -u nominatim-api nominatim search --query Andorra")
# Test web API
nominatim.succeed("curl 'http://localhost/status' | grep OK")
nominatim.succeed("""
curl "http://localhost/search?q=Andorra&format=geojson" | grep "Andorra"
curl "http://localhost/reverse?lat=42.5407167&lon=1.5732033&format=geojson"
""")
# Test UI
nominatim.succeed("""
curl "http://localhost/ui/search.html" \
| grep "<title>Nominatim Demo</title>"
""")
# Test api host
api.start()
api.wait_for_unit("nominatim.service")
# Test web API
api.succeed("""
curl "http://localhost/search?q=Andorra&format=geojson" | grep "Andorra"
curl "http://localhost/reverse?lat=42.5407167&lon=1.5732033&format=geojson"
""")
# Test format rewrites
# Redirect / to search
nominatim.succeed("""
curl --verbose "http://localhost" 2>&1 \
| grep "Location: http://localhost/ui/search.html"
""")
# Return text by default
nominatim.succeed("""
curl --verbose "http://localhost/status" 2>&1 \
| grep "Content-Type: text/plain"
""")
# Return JSON by default
nominatim.succeed("""
curl --verbose "http://localhost/search?q=Andorra" 2>&1 \
| grep "Content-Type: application/json"
""")
# Return XML by default
nominatim.succeed("""
curl --verbose "http://localhost/lookup" 2>&1 \
| grep "Content-Type: text/xml"
curl --verbose "http://localhost/reverse?lat=0&lon=0" 2>&1 \
| grep "Content-Type: text/xml"
""")
# Redirect explicitly requested HTML format
nominatim.succeed("""
curl --verbose "http://localhost/search?format=html" 2>&1 \
| grep "Location: http://localhost/ui/search.html"
curl --verbose "http://localhost/reverse?format=html" 2>&1 \
| grep "Location: http://localhost/ui/reverse.html"
""")
# Return explicitly requested JSON format
nominatim.succeed("""
curl --verbose "http://localhost/search?format=json" 2>&1 \
| grep "Content-Type: application/json"
curl --verbose "http://localhost/reverse?format=json" 2>&1 \
| grep "Content-Type: application/json"
""")
'';
}