From dcc1c5a927a4f4728f23c33de06ae41563ae103d Mon Sep 17 00:00:00 2001 From: Alberto Donato Date: Tue, 2 Nov 2021 17:59:35 +0100 Subject: [PATCH 1/2] Add a Client.server_clustered property Signed-off-by: Alberto Donato --- pylxd/client.py | 9 ++++++--- pylxd/tests/test_client.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/pylxd/client.py b/pylxd/client.py index bc65006b..aae49637 100644 --- a/pylxd/client.py +++ b/pylxd/client.py @@ -391,9 +391,8 @@ def __init__( ) as e: raise exceptions.ClientConnectionFailed(str(e)) - if ( - self.project not in (None, "default") - and "projects" not in self.host_info["api_extensions"] + if self.project not in (None, "default") and not self.has_api_extension( + "projects" ): raise exceptions.ClientConnectionFailed( "Remote server doesn't handle projects" @@ -416,6 +415,10 @@ def __init__( def trusted(self): return self.host_info["auth"] == "trusted" + @property + def server_clustered(self): + return self.host_info["environment"].get("server_clustered", False) + @property def resources(self): if self._resource_cache is None: diff --git a/pylxd/tests/test_client.py b/pylxd/tests/test_client.py index cea8bdc7..1dab0cf3 100644 --- a/pylxd/tests/test_client.py +++ b/pylxd/tests/test_client.py @@ -160,6 +160,34 @@ def test_connection_trusted(self): self.assertTrue(an_client.trusted) + def test_server_clustered_false_no_info(self): + """Client.server_clustered is False if the info is not available in metadata.""" + response = mock.MagicMock(status_code=200) + response.json.return_value = {"metadata": {"environment": {}}} + self.get.return_value = response + a_client = client.Client() + self.assertFalse(a_client.server_clustered) + + def test_server_clustered_false(self): + """Client.server_clustered is False if not clustered.""" + response = mock.MagicMock(status_code=200) + response.json.return_value = { + "metadata": {"environment": {"server_clustered": False}} + } + self.get.return_value = response + a_client = client.Client() + self.assertFalse(a_client.server_clustered) + + def test_server_clustered_true(self): + """Client.server_clustered is True if clustered.""" + response = mock.MagicMock(status_code=200) + response.json.return_value = { + "metadata": {"environment": {"server_clustered": True}} + } + self.get.return_value = response + a_client = client.Client() + self.assertTrue(a_client.server_clustered) + def test_authenticate(self): """A client is authenticated.""" response = mock.MagicMock(status_code=200) From ac0119c52cc0fe2fdf61a0faed44343b7ffedf78 Mon Sep 17 00:00:00 2001 From: Alberto Donato Date: Tue, 2 Nov 2021 18:25:42 +0100 Subject: [PATCH 2/2] set the instance location to None if the server is not clustered Signed-off-by: Alberto Donato --- pylxd/models/instance.py | 6 ++++++ pylxd/models/tests/test_instance.py | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pylxd/models/instance.py b/pylxd/models/instance.py index ace719e8..b21b7cd2 100644 --- a/pylxd/models/instance.py +++ b/pylxd/models/instance.py @@ -69,6 +69,12 @@ class Instance(model.Model): _endpoint = "instances" + def __setattr__(self, name, value): + if name == "location" and not self.client.server_clustered: + # LXD reports "none" as location when not in a cluster + value = None + super().__setattr__(name, value) + @property def api(self): return self.client.api[self._endpoint][self.name] diff --git a/pylxd/models/tests/test_instance.py b/pylxd/models/tests/test_instance.py index 61a895d1..9166341c 100644 --- a/pylxd/models/tests/test_instance.py +++ b/pylxd/models/tests/test_instance.py @@ -83,10 +83,13 @@ def test_create(self): self.assertEqual(config["name"], an_new_instance.name) - def test_create_remote(self): + def test_create_remote_location(self): """A new instance is created at target.""" config = {"name": "an-new-remote-instance"} + # the server must be in a cluster for the location to be set + self.client.host_info["environment"]["server_clustered"] = True + an_new_remote_instance = models.Instance.create( self.client, config, wait=True, target="an-remote" ) @@ -94,6 +97,13 @@ def test_create_remote(self): self.assertEqual(config["name"], an_new_remote_instance.name) self.assertEqual("an-remote", an_new_remote_instance.location) + def test_create_location_none(self): + config = {"name": "an-new-remote-instance"} + + instance = models.Instance.create(self.client, config, wait=True) + + self.assertIsNone(instance.location) + def test_exists(self): """A instance exists.""" name = "an-instance"