mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 11:46:35 +00:00
The file was named after the application, so an app served on several domains (SeaweedFS filer/master, Stalwart mail/webmail) overwrote it once per domain on every deploy. The last domain won its dashboard iframe host and Matomo site id for all others, and every deploy reloaded OpenResty for the flip-flop. The file is now <domain>.lua, the naming store-i18n already uses, and its path comes from lookup('nginx', 'files.lua', domain) for writer, reader and the Matomo reinjection. The reinjection stats the live domain's file instead of globbing leftovers.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
273 lines
9.4 KiB
Python
273 lines
9.4 KiB
Python
import unittest
|
|
import unittest.mock as mock
|
|
from unittest.mock import patch
|
|
|
|
from ansible.errors import AnsibleError
|
|
|
|
from plugins.lookup.nginx import LookupModule
|
|
|
|
|
|
class _FakeTlsResolveLookup:
|
|
"""
|
|
Minimal fake lookup plugin compatible with the NEW call style:
|
|
- run([domain, "protocols.web"], variables=...)
|
|
"""
|
|
|
|
def __init__(self, protocol: str):
|
|
self._protocol = protocol
|
|
|
|
def run(self, terms, variables=None, **kwargs):
|
|
if len(terms) != 2 or terms[1] != "protocols.web":
|
|
raise AssertionError(f"Unexpected terms passed to tls: {terms}")
|
|
|
|
if kwargs.get("want"):
|
|
raise AssertionError(f"Unexpected want kwarg passed to tls: {kwargs}")
|
|
|
|
return [self._protocol]
|
|
|
|
|
|
class TestNginxPathsLookup(unittest.TestCase):
|
|
def setUp(self):
|
|
self.plugin = LookupModule()
|
|
self.plugin._loader = mock.MagicMock()
|
|
self.applications = {"svc-prx-openresty": {"docker": {"volumes": {}}}}
|
|
self.variables = {
|
|
"applications": self.applications,
|
|
}
|
|
|
|
def _fake_get(self, applications, app_id, key, strict=True):
|
|
if key == "volumes.www.path":
|
|
return "/opt/mock/www"
|
|
if key == "volumes.nginx.path":
|
|
return "/opt/mock/nginx"
|
|
raise KeyError(key)
|
|
|
|
def _loader_get(self, tls=None):
|
|
def _get(name, *a, **k):
|
|
if name == "applications":
|
|
return mock.MagicMock(run=lambda *_a, **_k: [self.applications])
|
|
if name == "tls":
|
|
if tls is None:
|
|
raise AssertionError(
|
|
"tls must not be called when protocol override is set"
|
|
)
|
|
return tls
|
|
raise AssertionError(f"Unexpected lookup requested: {name}")
|
|
|
|
return _get
|
|
|
|
def _run(self, terms, **kwargs):
|
|
with (
|
|
patch(
|
|
"plugins.lookup.nginx.get",
|
|
side_effect=self._fake_get,
|
|
),
|
|
patch(
|
|
"plugins.lookup.nginx.get_canonical_volumes",
|
|
return_value={},
|
|
),
|
|
patch("plugins.lookup.nginx.lookup_loader") as loader_mock,
|
|
):
|
|
loader_mock.get.side_effect = self._loader_get()
|
|
return self.plugin.run(terms, variables=self.variables, **kwargs)[0]
|
|
|
|
def test_files_configuration_projection(self):
|
|
out = self._run(["files.configuration"])
|
|
self.assertEqual(out, "/opt/mock/nginx/nginx.conf")
|
|
|
|
def test_directories_configuration_projection(self):
|
|
out = self._run(["directories.configuration.base"])
|
|
self.assertEqual(out, "/opt/mock/nginx/conf.d/")
|
|
|
|
def test_directories_configuration_http_includes(self):
|
|
out = self._run(["directories.configuration.http_includes"])
|
|
self.assertEqual(
|
|
out,
|
|
[
|
|
"/opt/mock/nginx/conf.d/global/",
|
|
"/opt/mock/nginx/conf.d/maps/",
|
|
"/opt/mock/nginx/conf.d/servers/http/",
|
|
"/opt/mock/nginx/conf.d/servers/https/",
|
|
],
|
|
)
|
|
|
|
def test_directories_data_projection(self):
|
|
out = self._run(["directories.data"])
|
|
self.assertEqual(out["www"], "/opt/mock/www/")
|
|
self.assertEqual(out["html"], "/opt/mock/www/public_html/")
|
|
self.assertEqual(out["files"], "/opt/mock/www/public_files/")
|
|
self.assertEqual(out["cdn"], "/opt/mock/www/public_cdn/")
|
|
self.assertEqual(out["global"], "/opt/mock/www/global/")
|
|
self.assertEqual(out["well_known"], "/usr/share/nginx/well-known/")
|
|
|
|
def test_directories_cache_projection(self):
|
|
out = self._run(["directories.cache"])
|
|
self.assertEqual(out["general"], "/tmp/cache_nginx_general/")
|
|
self.assertEqual(out["image"], "/tmp/cache_nginx_image/")
|
|
|
|
def test_directories_ensure_projection(self):
|
|
ensure = self._run(["directories.ensure"])
|
|
self.assertIsInstance(ensure, list)
|
|
|
|
self.assertIn({"path": "/tmp/cache_nginx_general/", "mode": "0700"}, ensure)
|
|
self.assertIn({"path": "/tmp/cache_nginx_image/", "mode": "0700"}, ensure)
|
|
|
|
ensure_paths = self._run(["directories.ensure_paths"])
|
|
self.assertIsInstance(ensure_paths, list)
|
|
self.assertEqual(ensure_paths, [d["path"] for d in ensure])
|
|
|
|
self.assertNotIn("/usr/share/nginx/well-known/", ensure_paths)
|
|
|
|
def test_canonical_dict_supplies_volume_paths(self):
|
|
canonical = {
|
|
"www": {"type": "volume", "path": "/opt/canonical/www"},
|
|
"nginx": {"type": "volume", "path": "/opt/canonical/nginx"},
|
|
}
|
|
with (
|
|
patch(
|
|
"plugins.lookup.nginx.get",
|
|
side_effect=AssertionError(
|
|
"get() must not be called when canonical paths are present"
|
|
),
|
|
),
|
|
patch(
|
|
"plugins.lookup.nginx.get_canonical_volumes",
|
|
return_value=canonical,
|
|
),
|
|
patch("plugins.lookup.nginx.lookup_loader") as loader_mock,
|
|
):
|
|
loader_mock.get.side_effect = self._loader_get()
|
|
out = self.plugin.run(["files.configuration"], variables=self.variables)[0]
|
|
self.assertEqual(out, "/opt/canonical/nginx/nginx.conf")
|
|
|
|
def test_domain_uses_tls_when_no_override(self):
|
|
fake_tls = _FakeTlsResolveLookup("https")
|
|
|
|
with (
|
|
patch(
|
|
"plugins.lookup.nginx.get",
|
|
side_effect=self._fake_get,
|
|
),
|
|
patch(
|
|
"plugins.lookup.nginx.get_canonical_volumes",
|
|
return_value={},
|
|
),
|
|
patch("plugins.lookup.nginx.lookup_loader") as loader_mock,
|
|
):
|
|
loader_mock.get.side_effect = self._loader_get(tls=fake_tls)
|
|
out = self.plugin.run(
|
|
["files.domain", "example.com"], variables=self.variables
|
|
)[0]
|
|
|
|
self.assertEqual(
|
|
out,
|
|
"/opt/mock/nginx/conf.d/servers/https/example.com.conf",
|
|
)
|
|
|
|
def test_domain_protocol_override_http(self):
|
|
with (
|
|
patch(
|
|
"plugins.lookup.nginx.get",
|
|
side_effect=self._fake_get,
|
|
),
|
|
patch(
|
|
"plugins.lookup.nginx.get_canonical_volumes",
|
|
return_value={},
|
|
),
|
|
patch("plugins.lookup.nginx.lookup_loader") as loader_mock,
|
|
):
|
|
loader_mock.get.side_effect = self._loader_get()
|
|
out = self.plugin.run(
|
|
["files.domain", "example.com"],
|
|
variables=self.variables,
|
|
protocol="http",
|
|
)[0]
|
|
|
|
self.assertEqual(
|
|
out,
|
|
"/opt/mock/nginx/conf.d/servers/http/example.com.conf",
|
|
)
|
|
|
|
def test_invalid_protocol_override_raises(self):
|
|
with (
|
|
patch(
|
|
"plugins.lookup.nginx.get",
|
|
side_effect=self._fake_get,
|
|
),
|
|
patch(
|
|
"plugins.lookup.nginx.get_canonical_volumes",
|
|
return_value={},
|
|
),
|
|
patch("plugins.lookup.nginx.lookup_loader") as loader_mock,
|
|
self.assertRaises(AnsibleError),
|
|
):
|
|
loader_mock.get.side_effect = self._loader_get()
|
|
self.plugin.run(
|
|
["files.domain", "example.com"],
|
|
variables=self.variables,
|
|
protocol="ftp",
|
|
)
|
|
|
|
def test_files_lua_is_one_file_per_domain(self):
|
|
with (
|
|
patch(
|
|
"plugins.lookup.nginx.get",
|
|
side_effect=self._fake_get,
|
|
),
|
|
patch(
|
|
"plugins.lookup.nginx.get_canonical_volumes",
|
|
return_value={},
|
|
),
|
|
patch("plugins.lookup.nginx.lookup_loader") as loader_mock,
|
|
):
|
|
loader_mock.get.side_effect = self._loader_get()
|
|
out = self.plugin.run(
|
|
["files.lua", "filer.example.com"],
|
|
variables=self.variables,
|
|
protocol="https",
|
|
)[0]
|
|
|
|
self.assertEqual(out, "/opt/mock/nginx/conf.d/lua/filer.example.com.lua")
|
|
|
|
def test_files_lua_without_domain_raises(self):
|
|
with (
|
|
patch(
|
|
"plugins.lookup.nginx.get",
|
|
side_effect=self._fake_get,
|
|
),
|
|
patch(
|
|
"plugins.lookup.nginx.get_canonical_volumes",
|
|
return_value={},
|
|
),
|
|
patch("plugins.lookup.nginx.lookup_loader") as loader_mock,
|
|
self.assertRaises(AnsibleError),
|
|
):
|
|
loader_mock.get.side_effect = self._loader_get()
|
|
self.plugin.run(["files.lua"], variables=self.variables)
|
|
|
|
def test_invalid_usage_raises(self):
|
|
with (
|
|
patch(
|
|
"plugins.lookup.nginx.get",
|
|
side_effect=self._fake_get,
|
|
),
|
|
patch(
|
|
"plugins.lookup.nginx.get_canonical_volumes",
|
|
return_value={},
|
|
),
|
|
patch("plugins.lookup.nginx.lookup_loader") as loader_mock,
|
|
):
|
|
loader_mock.get.side_effect = self._loader_get()
|
|
|
|
with self.assertRaises(AnsibleError):
|
|
self.plugin.run([], variables=self.variables)
|
|
|
|
with self.assertRaises(AnsibleError):
|
|
self.plugin.run(
|
|
["files.domain", "example.com", "extra"], variables=self.variables
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|