diff --git a/oci/catalog/apps/rqlite.json b/oci/catalog/apps/rqlite.json index 22e8bb93..f3e49063 100644 --- a/oci/catalog/apps/rqlite.json +++ b/oci/catalog/apps/rqlite.json @@ -32,7 +32,7 @@ "documentation": "https://rqlite.io/docs/", "repository": "https://github.com/rqlite/rqlite", "tips": [ - "This profile runs one node. Port 4001 is the HTTP API; port 4002 is reserved for Raft cluster traffic. The database file is persisted under /rqlite/file." + "This profile runs one node. Port 4001 is the HTTP API; port 4002 is reserved for Raft cluster traffic. The image default starts rqlited with its data directory at /rqlite/file/data, persisted by the mounted /rqlite/file volume." ], "mini_changelog": [], "display_version": null, @@ -97,7 +97,7 @@ "related_services": [], "restart": "unless-stopped", "stop_grace_period": null, - "original_compose": "{\n \"name\": \"rqlite\",\n \"services\": {\n \"rqlite\": {\n \"image\": \"ghcr.io/rqlite/rqlite:latest\",\n \"restart\": \"unless-stopped\",\n \"ports\": [\n \"4001:4001/tcp\",\n \"4002:4002/tcp\"\n ],\n \"volumes\": [\n \"./file:/rqlite/file\"\n ],\n \"command\": [\n \"/rqlite/file\"\n ]\n }\n }\n}" + "original_compose": "{\n \"name\": \"rqlite\",\n \"services\": {\n \"rqlite\": {\n \"image\": \"ghcr.io/rqlite/rqlite:latest\",\n \"restart\": \"unless-stopped\",\n \"ports\": [\n \"4001:4001/tcp\",\n \"4002:4002/tcp\"\n ],\n \"volumes\": [\n \"./file:/rqlite/file\"\n ]\n }\n }\n}" }, "compose_stack": { "project_name": "rqlite", @@ -124,9 +124,6 @@ ], "volumes": [ "./file:/rqlite/file" - ], - "command": [ - "/rqlite/file" ] } } @@ -361,11 +358,6 @@ } ], "installer_profile": { - "runtime": { - "command": [ - "/rqlite/file" - ] - }, "startup_healthcheck": { "scheme": "http", "port": 4001, diff --git a/oci/catalog/curated/rqlite.json b/oci/catalog/curated/rqlite.json index 22e8bb93..f3e49063 100644 --- a/oci/catalog/curated/rqlite.json +++ b/oci/catalog/curated/rqlite.json @@ -32,7 +32,7 @@ "documentation": "https://rqlite.io/docs/", "repository": "https://github.com/rqlite/rqlite", "tips": [ - "This profile runs one node. Port 4001 is the HTTP API; port 4002 is reserved for Raft cluster traffic. The database file is persisted under /rqlite/file." + "This profile runs one node. Port 4001 is the HTTP API; port 4002 is reserved for Raft cluster traffic. The image default starts rqlited with its data directory at /rqlite/file/data, persisted by the mounted /rqlite/file volume." ], "mini_changelog": [], "display_version": null, @@ -97,7 +97,7 @@ "related_services": [], "restart": "unless-stopped", "stop_grace_period": null, - "original_compose": "{\n \"name\": \"rqlite\",\n \"services\": {\n \"rqlite\": {\n \"image\": \"ghcr.io/rqlite/rqlite:latest\",\n \"restart\": \"unless-stopped\",\n \"ports\": [\n \"4001:4001/tcp\",\n \"4002:4002/tcp\"\n ],\n \"volumes\": [\n \"./file:/rqlite/file\"\n ],\n \"command\": [\n \"/rqlite/file\"\n ]\n }\n }\n}" + "original_compose": "{\n \"name\": \"rqlite\",\n \"services\": {\n \"rqlite\": {\n \"image\": \"ghcr.io/rqlite/rqlite:latest\",\n \"restart\": \"unless-stopped\",\n \"ports\": [\n \"4001:4001/tcp\",\n \"4002:4002/tcp\"\n ],\n \"volumes\": [\n \"./file:/rqlite/file\"\n ]\n }\n }\n}" }, "compose_stack": { "project_name": "rqlite", @@ -124,9 +124,6 @@ ], "volumes": [ "./file:/rqlite/file" - ], - "command": [ - "/rqlite/file" ] } } @@ -361,11 +358,6 @@ } ], "installer_profile": { - "runtime": { - "command": [ - "/rqlite/file" - ] - }, "startup_healthcheck": { "scheme": "http", "port": 4001, diff --git a/oci/tests/test_rqlite_profile.py b/oci/tests/test_rqlite_profile.py index e33884df..f4192f40 100644 --- a/oci/tests/test_rqlite_profile.py +++ b/oci/tests/test_rqlite_profile.py @@ -1,4 +1,4 @@ -"""The rqlite data directory is a positional argument to rqlited.""" +"""rqlite uses its image default command and persists the default data directory.""" import json from pathlib import Path @@ -8,24 +8,41 @@ ROOT = Path(__file__).resolve().parents[1] class RqliteProfileTests(unittest.TestCase): - def test_persistent_data_directory_is_passed_positionally(self): + def test_default_startup_persists_default_data_directory(self): curated = json.loads((ROOT / "catalog/curated/rqlite.json").read_text()) app = json.loads((ROOT / "catalog/apps/rqlite.json").read_text()) self.assertEqual(curated, app) - data_dir = "/rqlite/file" - self.assertEqual(curated["proxmox"]["installer_profile"]["runtime"]["command"], [data_dir]) - self.assertEqual(curated["compose_stack"]["services"][0]["compose"]["command"], [data_dir]) + # The official image's default `run` entrypoint starts rqlited and + # uses DATA_DIR=/rqlite/file/data. Avoid an override: positional + # non-flag arguments are executed literally by its entrypoint. + compose_service = curated["compose_stack"]["services"][0]["compose"] original_compose = json.loads(curated["container_contract"]["original_compose"]) - self.assertEqual(original_compose["services"]["rqlite"]["command"], [data_dir]) + self.assertNotIn("runtime", curated["proxmox"]["installer_profile"]) + image_policy = curated["proxmox"]["image_metadata_policy"] + self.assertEqual(image_policy["entrypoint"], "import-from-oci-image") + self.assertEqual(image_policy["cmd"], "import-from-oci-image") + for config in (compose_service, original_compose["services"]["rqlite"]): + self.assertNotIn("command", config) + image = curated["container_contract"]["image"] self.assertEqual(image["reference"], "ghcr.io/rqlite/rqlite:latest") self.assertEqual(image["registry"], "ghcr.io") self.assertEqual(image["repository"], "ghcr.io/rqlite/rqlite") self.assertEqual(original_compose["services"]["rqlite"]["image"], image["reference"]) - mounted_paths = [volume["container_path"] for volume in curated["container_contract"]["volumes"]] - self.assertIn(data_dir, mounted_paths) + mounts = [ + volume["container_path"] + for volume in curated["container_contract"]["volumes"] + ] + self.assertIn("/rqlite/file", mounts) + self.assertTrue( + any( + path == "/rqlite/file/data" + or "/rqlite/file/data".startswith(path.rstrip("/") + "/") + for path in mounts + ) + ) if __name__ == "__main__":