mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-11 21:26:44 +00:00
A container cap had to be an absolute number, and docker refuses one above
the host's core count, so "use this machine" could only be written as a
number that breaks on a smaller machine. cpus now also takes a percentage,
read against the host's raw count: 100% is every CPU and lands exactly on the
ceiling docker accepts, 50% is half of it.
The share is read against that raw count rather than against the fair-share
default, because the two CPUs the resource lookup reserves exist to bound
what a service gets when it declares nothing. A service writing a percentage
overrides that default on purpose, and subtracting the reserve a second time
would count it twice and leave no way to name the whole machine.
A bare cpus: 0 is refused from here on. Docker reads a zero as uncapped
rather than as none, so the value most likely to be typed by mistake was also
the one that removed the limit; the error names the fix. No role declared
one: all 315 cpus values in the tree are plain numbers, the smallest 0.01.
Two lookups carry the resolution so that no caller repeats it or has to know
what a percentage is read against. lookup('cpus', app, service) replaces six
copies of lookup('config', ...) piped through the resolver; those six size
worker pools and thread counts from their own cpus, and left alone a
percentage would have given libretranslate a single thread and handed the
agent broker an uncapped container. lookup('webserver_resource', key)
replaces the two blocks that took the smaller of the proxy's value and the
app's, which were the same eight lines written twice for cpus and for
pids_limit.
resolve_cpus is no longer registered as a jinja filter. Nothing referenced it
from a template once the lookups existed, and keeping it would have left two
public ways to resolve one value.
Measured: 96 tests across the filter, both lookups and the container render
templates, including that a percentage resolves before the smaller of the two
is chosen, and that pids_limit stays an integer because nginx renders it
straight into worker_connections.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
54 lines
2.0 KiB
Python
54 lines
2.0 KiB
Python
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from ansible.errors import AnsibleError
|
|
|
|
from plugins.lookup.webserver_resource import PROXY_ROLE, LookupModule
|
|
|
|
RESOURCE = {"cpus": "0.5", "pids_limit": 512, "host_cpus": 20}
|
|
|
|
|
|
def _run(key, proxy, app, application_id="web-app-docs", service_name=""):
|
|
applications = {
|
|
PROXY_ROLE: {"services": {"openresty": {key: proxy}}},
|
|
application_id: {"services": {"docs": {key: app}}},
|
|
}
|
|
variables = {"application_id": application_id, "service_name": service_name}
|
|
with (
|
|
patch("plugins.lookup.webserver_resource.ApplicationsLookup") as apps,
|
|
patch("plugins.lookup.webserver_resource.ResourceLookup") as resource,
|
|
):
|
|
apps.return_value.run.return_value = [applications]
|
|
resource.return_value.run.side_effect = lambda terms, **_k: [RESOURCE[terms[0]]]
|
|
return LookupModule().run([key], variables=variables)
|
|
|
|
|
|
class TestWebserverResource(unittest.TestCase):
|
|
def test_the_tighter_of_the_two_wins(self):
|
|
self.assertEqual(_run("cpus", proxy="4", app="2"), [2.0])
|
|
self.assertEqual(_run("cpus", proxy="1", app="2"), [1.0])
|
|
|
|
def test_a_percentage_is_resolved_before_the_comparison(self):
|
|
"""95% of 20 is 19, so a literal 4 is the tighter of the pair."""
|
|
self.assertEqual(_run("cpus", proxy="4", app="95%"), [4.0])
|
|
|
|
def test_a_percentage_can_be_the_tighter_one(self):
|
|
self.assertEqual(_run("cpus", proxy="50%", app="16"), [10.0])
|
|
|
|
def test_pids_limit_stays_an_integer(self):
|
|
result = _run("pids_limit", proxy=1024, app=512)
|
|
self.assertEqual(result, [512])
|
|
self.assertIsInstance(result[0], int)
|
|
|
|
def test_an_unknown_key_is_refused(self):
|
|
with self.assertRaises(AnsibleError):
|
|
LookupModule().run(["mem_limit"], variables={})
|
|
|
|
def test_more_than_one_term_is_refused(self):
|
|
with self.assertRaises(AnsibleError):
|
|
LookupModule().run(["cpus", "pids_limit"], variables={})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|