]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
node-proxy: implement http_query() helper function
authorGuillaume Abrioux <gabrioux@ibm.com>
Wed, 25 Oct 2023 15:07:09 +0000 (15:07 +0000)
committerGuillaume Abrioux <gabrioux@ibm.com>
Thu, 25 Jan 2024 15:07:20 +0000 (15:07 +0000)
so we can drop the dependency to `requests` and
use same helper function from both reporter.py and redfish_client.py

Signed-off-by: Guillaume Abrioux <gabrioux@ibm.com>
src/cephadm/cephadmlib/node_proxy/main.py
src/cephadm/cephadmlib/node_proxy/redfish_client.py
src/cephadm/cephadmlib/node_proxy/reporter.py
src/cephadm/cephadmlib/node_proxy/util.py

index 82f941a085125d8dc93343ca24c5897d524db642..e9c99f0983dcb1bb0df0745e7b776e52b54a66ff 100644 (file)
@@ -219,7 +219,10 @@ class NodeProxy(Thread):
         try:
             self.reporter_agent = Reporter(self.system,
                                            self.__dict__['cephx'],
-                                           f"https://{self.__dict__['mgr_target_ip']}:{self.__dict__['mgr_target_port']}/node-proxy/data")
+                                           reporter_scheme=self.__dict__.get('reporter_scheme', 'https'),
+                                           reporter_hostname=self.__dict__['mgr_target_ip'],
+                                           reporter_port=self.__dict__['mgr_target_port'],
+                                           reporter_endpoint=self.__dict__.get('reporter_endpoint', '/node-proxy/data'))
         except RuntimeError:
             self.log.logger.error("Can't initialize the reporter.")
             raise
index 3046a634c58e50607f3928e6a3bb8c9707e39182..4107fb57c8f094f7434dc311ae8920408ab3dd2b 100644 (file)
@@ -1,10 +1,9 @@
-import ssl
 import json
-from urllib.error import URLError
-from urllib.request import urlopen, Request
+from urllib.error import HTTPError, URLError
 from .baseclient import BaseClient
-from .util import Logger
+from .util import Logger, http_req
 from typing import Dict, Any, Tuple, Optional
+from http.client import HTTPMessage
 
 
 class RedFishClient(BaseClient):
@@ -18,14 +17,16 @@ class RedFishClient(BaseClient):
         super().__init__(host, username, password)
         self.log: Logger = Logger(__name__)
         self.log.logger.info(f"Initializing redfish client {__name__}")
-        self.host: str = f"https://{host}:{str(port)}"
+        self.host: str = host
+        self.port: int = port
+        self.url: str = f"https://{self.host}:{self.port}"
         self.token: str = ''
         self.location: str = ''
 
     def login(self) -> None:
         if not self.is_logged_in():
             self.log.logger.info("Logging in to "
-                                 f"{self.host} as '{self.username}'")
+                                 f"{self.url} as '{self.username}'")
             idrac_credentials = json.dumps({"UserName": self.username,
                                             "Password": self.password})
             headers = {"Content-Type": "application/json"}
@@ -35,19 +36,19 @@ class RedFishClient(BaseClient):
                                                            headers=headers,
                                                            endpoint='/redfish/v1/SessionService/Sessions/')
                 if _status_code != 201:
-                    self.log.logger.error(f"Can't log in to {self.host} as '{self.username}': {_status_code}")
+                    self.log.logger.error(f"Can't log in to {self.url} as '{self.username}': {_status_code}")
                     raise RuntimeError
             except URLError as e:
-                msg = f"Can't log in to {self.host} as '{self.username}': {e}"
+                msg = f"Can't log in to {self.url} as '{self.username}': {e}"
                 self.log.logger.error(msg)
                 raise RuntimeError
             self.token = _headers['X-Auth-Token']
             self.location = _headers['Location']
 
     def is_logged_in(self) -> bool:
-        self.log.logger.debug(f"Checking token validity for {self.host}")
+        self.log.logger.debug(f"Checking token validity for {self.url}")
         if not self.location or not self.token:
-            self.log.logger.debug(f"No token found for {self.host}.")
+            self.log.logger.debug(f"No token found for {self.url}.")
             return False
         headers = {"X-Auth-Token": self.token}
         try:
@@ -55,7 +56,7 @@ class RedFishClient(BaseClient):
                                                        endpoint=self.location)
         except URLError as e:
             self.log.logger.error("Can't check token "
-                                  f"validity for {self.host}: {e}")
+                                  f"validity for {self.url}: {e}")
             raise RuntimeError
         return _status_code == 200
 
@@ -65,7 +66,7 @@ class RedFishClient(BaseClient):
                                                 headers={"X-Auth-Token": self.token},
                                                 endpoint=self.location)
         except URLError:
-            self.log.logger.error(f"Can't log out from {self.host}")
+            self.log.logger.error(f"Can't log out from {self.url}")
             return {}
 
         response_str = _data
@@ -88,25 +89,24 @@ class RedFishClient(BaseClient):
               headers: Dict[str, str] = {},
               method: Optional[str] = None,
               endpoint: str = '',
-              timeout: int = 10) -> Tuple[Dict[str, str], str, int]:
-        url = f'{self.host}{endpoint}'
+              timeout: int = 10) -> Tuple[HTTPMessage, str, int]:
         _headers = headers.copy() if headers else {}
         if self.token:
             _headers['X-Auth-Token'] = self.token
         if not _headers.get('Content-Type') and method in ['POST', 'PUT', 'PATCH']:
             _headers['Content-Type'] = 'application/json'
-        # ssl_ctx = ssl.create_default_context()
-        # ssl_ctx.check_hostname = True
-        # ssl_ctx.verify_mode = ssl.CERT_REQUIRED
-        ssl_ctx = ssl._create_unverified_context()
-        _data = bytes(data, 'ascii') if data else None
         try:
-            req = Request(url, _data, headers=_headers, method=method)
-            with urlopen(req, context=ssl_ctx, timeout=timeout) as response:
-                response_str = response.read()
-                response_headers = response.headers
-        except URLError as e:
+            (response_headers,
+             response_str,
+             response_status) = http_req(hostname=self.host,
+                                         port=self.port,
+                                         endpoint=endpoint,
+                                         headers=_headers,
+                                         method=method,
+                                         data=data,
+                                         timeout=timeout)
+
+            return response_headers, response_str, response_status
+        except (HTTPError, URLError) as e:
             self.log.logger.debug(f"{e}")
             raise
-
-        return response_headers, response_str, response.status
index 5089dd13197981ec2b17f9b71ee2b341a366cf8f..aa0ecdf93f987351164b7c57e6f21a26cb2055bc 100644 (file)
@@ -1,18 +1,32 @@
 from threading import Thread
-import requests
 import time
-from .util import Logger
+import json
+from .util import Logger, http_req
+from urllib.error import HTTPError, URLError
 from typing import Dict, Any
 
 
 class Reporter:
-    def __init__(self, system: Any, cephx: Dict[str, Any], observer_url: str) -> None:
+    def __init__(self,
+                 system: Any,
+                 cephx: Dict[str, Any],
+                 reporter_scheme: str = 'https',
+                 reporter_hostname: str = '',
+                 reporter_port: int = 443,
+                 reporter_endpoint: str = '/node-proxy/data') -> None:
         self.system = system
-        self.observer_url = observer_url
+        self.data: Dict[str, Any] = {}
         self.finish = False
         self.cephx = cephx
+        self.data['cephx'] = self.cephx
+        self.reporter_scheme: str = reporter_scheme
+        self.reporter_hostname: str = reporter_hostname
+        self.reporter_port: int = reporter_port
+        self.reporter_endpoint: str = reporter_endpoint
         self.log = Logger(__name__)
-        self.log.logger.info(f'Observer url set to {self.observer_url}')
+        self.reporter_url: str = (f"{reporter_scheme}:{reporter_hostname}:"
+                                  f"{reporter_port}{reporter_endpoint}")
+        self.log.logger.info(f'Reporter url set to {self.reporter_url}')
 
     def stop(self) -> None:
         self.finish = True
@@ -36,15 +50,18 @@ class Reporter:
                 self.log.logger.info('data ready to be sent to the mgr.')
                 if not self.system.get_system() == self.system.previous_data:
                     self.log.logger.info('data has changed since last iteration.')
-                    self.data = {}
-                    self.data['cephx'] = self.cephx
                     self.data['patch'] = self.system.get_system()
                     try:
                         # TODO: add a timeout parameter to the reporter in the config file
-                        self.log.logger.info(f"sending data to {self.observer_url}")
-                        r = requests.post(f"{self.observer_url}", json=self.data, timeout=5, verify=False)
-                    except (requests.exceptions.RequestException,
-                            requests.exceptions.ConnectionError) as e:
+                        self.log.logger.info(f"sending data to {self.reporter_url}")
+                        http_req(hostname=self.reporter_hostname,
+                                 port=self.reporter_port,
+                                 method='POST',
+                                 headers={'Content-Type': 'application/json'},
+                                 endpoint=self.reporter_endpoint,
+                                 scheme=self.reporter_scheme,
+                                 data=json.dumps(self.data))
+                    except (HTTPError, URLError) as e:
                         self.log.logger.error(f"The reporter couldn't send data to the mgr: {e}")
                         # Need to add a new parameter 'max_retries' to the reporter if it can't
                         # send the data for more than x times, maybe the daemon should stop altogether
index 40b01f0c7640f32a052bbb89b07107cb0b1e7697..da46ebabda0dde3c180674271a29c2d704179a2e 100644 (file)
@@ -3,7 +3,10 @@ import yaml
 import os
 import time
 import re
-from typing import Dict, List, Callable, Any
+import ssl
+from urllib.error import HTTPError, URLError
+from urllib.request import urlopen, Request
+from typing import Dict, List, Callable, Any, Optional, MutableMapping, Tuple
 
 
 class Logger:
@@ -98,3 +101,38 @@ def retry(exceptions: Any = Exception, retries: int = 20, delay: int = 1) -> Cal
             return f(*args, **kwargs)
         return _retry
     return decorator
+
+
+def http_req(hostname: str = '',
+             port: int = 443,
+             method: Optional[str] = None,
+             headers: MutableMapping[str, str] = {},
+             data: Optional[str] = None,
+             endpoint: str = '/',
+             scheme: str = 'https',
+             ssl_verify: bool = False,
+             timeout: Optional[int] = None,
+             ssl_ctx: Optional[Any] = None) -> Tuple[Any, Any, Any]:
+
+    if not ssl_ctx:
+        ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+        if not ssl_verify:
+            ssl_ctx.check_hostname = False
+            ssl_ctx.verify_mode = ssl.CERT_NONE
+        else:
+            ssl_ctx.verify_mode = ssl.CERT_REQUIRED
+
+    url: str = f'{scheme}://{hostname}:{str(port)}{endpoint}'
+    _data = bytes(data, 'ascii') if data else None
+
+    try:
+        req = Request(url, _data, headers, method=method)
+        with urlopen(req, context=ssl_ctx, timeout=timeout) as response:
+            response_str = response.read()
+            response_headers = response.headers
+            response_code = response.code
+        return response_headers, response_str.decode(), response_code
+    except (HTTPError, URLError) as e:
+        print(f'{e}')
+        # handle error here if needed
+        raise