From 4773081cd484cd8903b736e865efafddbeb13b1c Mon Sep 17 00:00:00 2001 From: Adam Dyess Date: Mon, 9 Dec 2024 19:31:15 -0600 Subject: [PATCH] chore: update charm libraries --- .../lib/charms/grafana_agent/v0/cos_agent.py | 3 +- .../lib/charms/operator_libs_linux/v2/snap.py | 45 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/charms/worker/k8s/lib/charms/grafana_agent/v0/cos_agent.py b/charms/worker/k8s/lib/charms/grafana_agent/v0/cos_agent.py index cc4da25a..1ea79a62 100644 --- a/charms/worker/k8s/lib/charms/grafana_agent/v0/cos_agent.py +++ b/charms/worker/k8s/lib/charms/grafana_agent/v0/cos_agent.py @@ -22,7 +22,6 @@ Using the `COSAgentProvider` object only requires instantiating it, typically in the `__init__` method of your charm (the one which sends telemetry). -The constructor of `COSAgentProvider` has only one required and ten optional parameters: ```python def __init__( @@ -253,7 +252,7 @@ class _MetricsEndpointDict(TypedDict): LIBID = "dc15fa84cef84ce58155fb84f6c6213a" LIBAPI = 0 -LIBPATCH = 11 +LIBPATCH = 12 PYDEPS = ["cosl", "pydantic"] diff --git a/charms/worker/k8s/lib/charms/operator_libs_linux/v2/snap.py b/charms/worker/k8s/lib/charms/operator_libs_linux/v2/snap.py index 9d09a78d..d84b7d8d 100644 --- a/charms/worker/k8s/lib/charms/operator_libs_linux/v2/snap.py +++ b/charms/worker/k8s/lib/charms/operator_libs_linux/v2/snap.py @@ -64,6 +64,7 @@ import socket import subprocess import sys +import time import urllib.error import urllib.parse import urllib.request @@ -83,7 +84,7 @@ # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 7 +LIBPATCH = 8 # Regex to locate 7-bit C1 ANSI sequences @@ -332,7 +333,7 @@ def get(self, key: Optional[str], *, typed: bool = False) -> Any: return self._snap("get", [key]).strip() - def set(self, config: Dict[str, Any], *, typed: bool = False) -> str: + def set(self, config: Dict[str, Any], *, typed: bool = False) -> None: """Set a snap configuration value. Args: @@ -340,11 +341,9 @@ def set(self, config: Dict[str, Any], *, typed: bool = False) -> str: typed: set to True to convert all values in the config into typed values while configuring the snap (set with typed=True). Default is not to convert. """ - if typed: - kv = [f"{key}={json.dumps(val)}" for key, val in config.items()] - return self._snap("set", ["-t"] + kv) - - return self._snap("set", [f"{key}={val}" for key, val in config.items()]) + if not typed: + config = {k: str(v) for k, v in config.items()} + self._snap_client._put_snap_conf(self._name, config) def unset(self, key) -> str: """Unset a snap configuration value. @@ -770,7 +769,33 @@ def _request( headers["Content-Type"] = "application/json" response = self._request_raw(method, path, query, headers, data) - return json.loads(response.read().decode())["result"] + response = json.loads(response.read().decode()) + if response["type"] == "async": + return self._wait(response["change"]) + return response["result"] + + def _wait(self, change_id: str, timeout=300) -> JSONType: + """Wait for an async change to complete. + + The poll time is 100 milliseconds, the same as in snap clients. + """ + deadline = time.time() + timeout + while True: + if time.time() > deadline: + raise TimeoutError(f"timeout waiting for snap change {change_id}") + response = self._request("GET", f"changes/{change_id}") + status = response["status"] + if status == "Done": + return response.get("data") + if status == "Doing": + time.sleep(0.1) + continue + if status == "Wait": + logger.warning("snap change %s succeeded with status 'Wait'", change_id) + return response.get("data") + raise SnapError( + f"snap change {response.get('kind')!r} id {change_id} failed with status {status}" + ) def _request_raw( self, @@ -818,6 +843,10 @@ def get_installed_snap_apps(self, name: str) -> List: """Query the snap server for apps belonging to a named, currently installed snap.""" return self._request("GET", "apps", {"names": name, "select": "service"}) + def _put_snap_conf(self, name: str, conf: Dict[str, Any]): + """Set the configuration details for an installed snap.""" + return self._request("PUT", f"snaps/{name}/conf", body=conf) + class SnapCache(Mapping): """An abstraction to represent installed/available packages.