From 0056d3f87102e50a1c35c05bdfa25124c387440f Mon Sep 17 00:00:00 2001 From: Pete Vander Giessen Date: Mon, 28 Nov 2016 16:36:50 -0500 Subject: [PATCH] Added Placement parser. Interim workaround for https://bugs.launchpad.net/juju/+bug/1645480, where the websocket API will not accept the placement string that the planner generates. --- .gitignore | 2 ++ juju/application.py | 3 ++- juju/placement.py | 41 ++++++++++++++++++++++++++++++++++++ tests/unit/test_placement.py | 20 ++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 juju/placement.py create mode 100644 tests/unit/test_placement.py diff --git a/.gitignore b/.gitignore index 9bde928..f8abe96 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ *.sw[mnop] .venv/ *.pyc +*.py~ docs/_build/ __pycache__/ .tox/ *.egg-info/ .cache/ +.\#* diff --git a/juju/application.py b/juju/application.py index 4a98622..df309b3 100644 --- a/juju/application.py +++ b/juju/application.py @@ -3,6 +3,7 @@ import logging from . import model from .client import client +from .placement import parse as parse_placement log = logging.getLogger(__name__) @@ -83,7 +84,7 @@ class Application(model.ModelEntity): result = await app_facade.AddUnits( application=self.name, - placement=to, + placement=[parse_placement(to)], num_units=count, ) diff --git a/juju/placement.py b/juju/placement.py new file mode 100644 index 0000000..62cd570 --- /dev/null +++ b/juju/placement.py @@ -0,0 +1,41 @@ +# +# This module allows us to parse a machine placement directive into a +# Placement object suitable for passing through the websocket API. +# +# Once https://bugs.launchpad.net/juju/+bug/1645480 is addressed, this +# module should be deprecated. +# + +MACHINE_SCOPE = "#" + +from .client import client + +def parse(directive): + """ + Given a string in the format `scope:directive`, or simply `scope` + or `directive`, return a Placement object suitable for passing + back over the websocket API. + + """ + if directive == "": + # Handle null case + return None + + if type(directive) in [dict, client.Placement]: + # We've been handed something that we can simply hand back to + # the api. (Forwards compatibility) + return directive + + if ":" in directive: + # Planner has given us a scope and directive in string form + scope, directive = directive.split(":") + return client.Placement(scope=scope, directive=directive) + + if directive.isdigit(): + # Planner has given us a machine id (we rely on juju core to + # verify its validity.) + return client.Placement(scope=MACHINE_SCOPE, directive=directive) + + # Planner has probably given us a container type. Leave it up to + # juju core to verify that it is valid. + return client.Placement(scope=directive) diff --git a/tests/unit/test_placement.py b/tests/unit/test_placement.py new file mode 100644 index 0000000..793266d --- /dev/null +++ b/tests/unit/test_placement.py @@ -0,0 +1,20 @@ +# +# Test our placement helper +# + +import unittest + +from juju import placement +from juju.client import client + +class TestPlacement(unittest.TestCase): + + def test_parse_both_specified(self): + res = placement.parse("foo:bar") + self.assertEqual(res.scope, "foo") + self.assertEqual(res.directive, "bar") + + def test_parse_machine(self): + res = placement.parse("22") + self.assertEqual(res.scope, "#") + self.assertEqual(res.directive, "22") -- 2.17.1