← Back to team overview

sts-sponsors team mailing list archive

[Merge] ~r00ta/maas:MAASENG-1785 into maas:sqlalchemy-spike

 

Jacopo Rota has proposed merging ~r00ta/maas:MAASENG-1785 into maas:sqlalchemy-spike.

Commit message:
Add MaasFastClient class

Requested reviews:
  MAAS Maintainers (maas-maintainers)

For more details, see:
https://code.launchpad.net/~r00ta/maas/+git/maas/+merge/443950

This MP aims to provide a MaasFastClient to interact with the maasfastserver application through a unix socket. 

For snap the unix socket path is configured through an env variable `MAAS_FAST_HTTP_SOCKET_PATH`. 
For deb, it leverages on the utility `get_maas_data_path` with the default filename `maasfast-http.sock`. If the env variable `MAAS_DATA` is not set, by default it ends up with `/var/lib/maas/maasfast-http.sock`.

The implementation leverages on `requests_unixsocket`, which is already used by pylxd.
-- 
Your team MAAS Maintainers is requested to review the proposed merge of ~r00ta/maas:MAASENG-1785 into maas:sqlalchemy-spike.
diff --git a/debian/control b/debian/control
index 1609b33..73296ae 100644
--- a/debian/control
+++ b/debian/control
@@ -89,6 +89,7 @@ Depends: bind9 (>= 1:9.10.3.dfsg.P2-5~),
          python3-mimeparse,
          python3-petname,
          python3-requests,
+         python3-requests-unixsocket,
          ubuntu-keyring,
          ${misc:Depends},
          ${python3:Depends}
diff --git a/required-packages/base b/required-packages/base
index c9ad2a7..3483df6 100644
--- a/required-packages/base
+++ b/required-packages/base
@@ -45,6 +45,7 @@ python3-pyparsing
 python3-pypureomapi
 python3-pyvmomi
 python3-requests
+python3-requests-unixsocket
 python3-seamicroclient
 python3-simplestreams
 python3-tempita
diff --git a/snap/local/tree/bin/run-regiond b/snap/local/tree/bin/run-regiond
index e7c86ea..27f7d1a 100755
--- a/snap/local/tree/bin/run-regiond
+++ b/snap/local/tree/bin/run-regiond
@@ -19,6 +19,7 @@ export MAAS_IMAGES_KEYRING_FILEPATH="/snap/maas/current/usr/share/keyrings/ubunt
 export MAAS_THIRD_PARTY_DRIVER_SETTINGS="$SNAP/etc/maas/drivers.yaml"
 export MAAS_HTTP_CONFIG_DIR="$SNAP_DATA/http"
 export MAAS_HTTP_SOCKET_PATH="$SNAP_DATA/maas-regiond-webapp.sock"
+export MAAS_FAST_HTTP_SOCKET_PATH="$SNAP_DATA/maasfast-http.sock"
 
 # ensure these dirs exist here since the region creates config files for other
 # services
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index fecac72..c7e259b 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -145,7 +145,7 @@ parts:
       - python3-pyrsistent # for jsonschema
       - python3-requests
       - python3-requests-toolbelt  # for pylxd
-      - python3-requests-unixsocket  # for pylxd
+      - python3-requests-unixsocket  # for pylxd and maasfastclient
       - python3-rfc3339 # for macaroonbakery
       - python3-seamicroclient
       - python3-simplestreams
diff --git a/src/maasserver/utils/fast_client.py b/src/maasserver/utils/fast_client.py
new file mode 100644
index 0000000..2ee34d7
--- /dev/null
+++ b/src/maasserver/utils/fast_client.py
@@ -0,0 +1,38 @@
+import os
+import urllib.parse
+
+import requests_unixsocket
+
+from provisioningserver.path import get_maas_data_path
+
+
+class MaasFastClient:
+    def __init__(self):
+        self.session = requests_unixsocket.Session()
+        self.socket_path = self._read_socket_path()
+
+    def _read_socket_path(self):
+        socket_path = os.getenv(
+            "MAAS_FAST_HTTP_SOCKET_PATH",
+            get_maas_data_path("maasfast-http.sock"),
+        )
+        return "http+unix://" + urllib.parse.quote_plus(socket_path)
+
+    def _build_url(self, url):
+        return self.socket_path + url
+
+    def get(self, path, **kwargs):
+        url = self._build_url(path)
+        return self.session.get(url, **kwargs)
+
+    def post(self, path, **kwargs):
+        url = self._build_url(path)
+        return self.session.post(url, **kwargs)
+
+    def put(self, path, **kwargs):
+        url = self._build_url(path)
+        return self.session.put(url, **kwargs)
+
+    def delete(self, path, **kwargs):
+        url = self._build_url(path)
+        return self.session.delete(url, **kwargs)
diff --git a/src/maasserver/utils/tests/test_fast_client.py b/src/maasserver/utils/tests/test_fast_client.py
new file mode 100644
index 0000000..80d41f2
--- /dev/null
+++ b/src/maasserver/utils/tests/test_fast_client.py
@@ -0,0 +1,75 @@
+import os
+import unittest
+from unittest.mock import patch
+
+from maasserver.utils.fast_client import MaasFastClient
+
+
+class BaseFastClientTests:
+    def __init__(self):
+        self.client = None
+        self.encoded_socket_path = None
+
+    def test_build_url(self):
+        url = self.client._build_url("/endpoint")
+        assert url == f"http+unix://{self.encoded_socket_path}/endpoint"
+
+    @patch("requests_unixsocket.Session.get")
+    def test_get(self, mock_session_get):
+        self.client.get("/endpoint")
+        mock_session_get.assert_called_with(
+            f"http+unix://{self.encoded_socket_path}/endpoint"
+        )
+
+    @patch("requests_unixsocket.Session.post")
+    def test_post(self, mock_session_post):
+        kwargs = {
+            "json": {"key": "value"},
+        }
+        self.client.post("/endpoint", **kwargs)
+        mock_session_post.assert_called_with(
+            f"http+unix://{self.encoded_socket_path}/endpoint", **kwargs
+        )
+
+    @patch("requests_unixsocket.Session.put")
+    def test_put(self, mock_session_put):
+        kwargs = {
+            "json": {"key": "value"},
+        }
+        self.client.put("/endpoint", **kwargs)
+        mock_session_put.assert_called_with(
+            f"http+unix://{self.encoded_socket_path}/endpoint", **kwargs
+        )
+
+    @patch("requests_unixsocket.Session.delete")
+    def test_delete(self, mock_session_delete):
+        self.client.delete("/endpoint")
+        mock_session_delete.assert_called_with(
+            f"http+unix://{self.encoded_socket_path}/endpoint"
+        )
+
+
+class SnapMaasFastClientTests(unittest.TestCase, BaseFastClientTests):
+    @patch.dict(
+        os.environ,
+        {
+            "MAAS_FAST_HTTP_SOCKET_PATH": "/var/snap/maas/common/fastapi_unix_socket.sock"
+        },
+        clear=True,
+    )
+    def setUp(self):
+        self.encoded_socket_path = (
+            "%2Fvar%2Fsnap%2Fmaas%2Fcommon%2Ffastapi_unix_socket.sock"
+        )
+        self.client = MaasFastClient()
+
+
+class DebMaasFastClientTests(unittest.TestCase, BaseFastClientTests):
+    @patch("os.getenv")
+    @patch("provisioningserver.path.get_maas_data_path")
+    def setUp(self, mock_os, mock_get_maas_data_path):
+        mock_get_maas_data_path.return_value = (
+            "/var/lib/maas/maasfast-http.sock"
+        )
+        self.encoded_socket_path = "%2Fvar%2Flib%2Fmaas%2Fmaasfast-http.sock"
+        self.client = MaasFastClient()
diff --git a/utilities/check-imports b/utilities/check-imports
index 50c05bb..df6d7a1 100755
--- a/utilities/check-imports
+++ b/utilities/check-imports
@@ -309,6 +309,7 @@ RegionControllerRule = Rule(
     Allow("psycopg2|psycopg2.**"),
     Allow("pytz.UTC"),
     Allow("requests|requests.**"),
+    Allow("requests_unixsocket|requests_unixsocket.**"),
     Allow("simplestreams.**"),
     Allow("tempita"),
     Allow("twisted.**"),

Follow ups