diff options
Diffstat (limited to 'events')
-rw-r--r-- | events/src/eventsapiconf.py.in | 1 | ||||
-rw-r--r-- | events/src/peer_eventsapi.py | 48 | ||||
-rw-r--r-- | events/src/utils.py | 94 |
3 files changed, 114 insertions, 29 deletions
diff --git a/events/src/eventsapiconf.py.in b/events/src/eventsapiconf.py.in index 08a3602f567..687eaa39c00 100644 --- a/events/src/eventsapiconf.py.in +++ b/events/src/eventsapiconf.py.in @@ -26,6 +26,7 @@ UUID_FILE = "@GLUSTERD_WORKDIR@/glusterd.info" PID_FILE = "@localstatedir@/run/glustereventsd.pid" AUTO_BOOL_ATTRIBUTES = ["force", "push-pem", "no-verify"] AUTO_INT_ATTRIBUTES = ["ssh-port"] +CERTS_DIR = "@GLUSTERD_WORKDIR@/events" # Errors ERROR_SAME_CONFIG = 2 diff --git a/events/src/peer_eventsapi.py b/events/src/peer_eventsapi.py index 3a6a0eb4496..d72fdbe99c4 100644 --- a/events/src/peer_eventsapi.py +++ b/events/src/peer_eventsapi.py @@ -27,7 +27,7 @@ from gluster.cliutils import (Cmd, node_output_ok, node_output_notok, sync_file_to_peers, GlusterCmdException, output_error, execute_in_peers, runcli, set_common_args_func) -from events.utils import LockedOpen, get_jwt_token +from events.utils import LockedOpen, get_jwt_token, save_https_cert from events.eventsapiconf import (WEBHOOKS_FILE_TO_SYNC, WEBHOOKS_FILE, @@ -47,7 +47,8 @@ from events.eventsapiconf import (WEBHOOKS_FILE_TO_SYNC, ERROR_PARTIAL_SUCCESS, ERROR_ALL_NODES_STATUS_NOT_OK, ERROR_SAME_CONFIG, - ERROR_WEBHOOK_SYNC_FAILED) + ERROR_WEBHOOK_SYNC_FAILED, + CERTS_DIR) def handle_output_error(err, errcode=1, json_output=False): @@ -405,12 +406,43 @@ class NodeWebhookTestCmd(Cmd): if hashval: http_headers["Authorization"] = "Bearer " + hashval - try: - resp = requests.post(args.url, headers=http_headers) - except requests.ConnectionError as e: - node_output_notok("{0}".format(e)) - except requests.exceptions.InvalidSchema as e: - node_output_notok("{0}".format(e)) + urldata = requests.utils.urlparse(args.url) + parts = urldata.netloc.split(":") + domain = parts[0] + # Default https port if not specified + port = 443 + if len(parts) == 2: + port = int(parts[1]) + + cert_path = os.path.join(CERTS_DIR, args.url.replace("/", "_").strip()) + verify = True + while True: + try: + resp = requests.post(args.url, headers=http_headers, + verify=verify) + # Successful webhook push + break + except requests.exceptions.SSLError as e: + # If verify is equal to cert path, but still failed with + # SSLError, Looks like some issue with custom downloaded + # certificate, Try with verify = false + if verify == cert_path: + verify = False + continue + + # If verify is instance of bool and True, then custom cert + # is required, download the cert and retry + try: + save_https_cert(domain, port, cert_path) + verify = cert_path + except Exception: + verify = False + + # Done with collecting cert, continue + continue + except Exception as e: + node_output_notok("{0}".format(e)) + break if resp.status_code != 200: node_output_notok("{0}".format(resp.status_code)) diff --git a/events/src/utils.py b/events/src/utils.py index 5130720d529..851543e8f3b 100644 --- a/events/src/utils.py +++ b/events/src/utils.py @@ -23,7 +23,8 @@ from eventsapiconf import (LOG_FILE, WEBHOOKS_FILE, DEFAULT_CONFIG_FILE, CUSTOM_CONFIG_FILE, - UUID_FILE) + UUID_FILE, + CERTS_DIR) import eventtypes @@ -195,11 +196,33 @@ def get_jwt_token(secret, event_type, event_ts, jwt_expiry_time_seconds=60): return jwt.encode(payload, secret, algorithm='HS256') +def save_https_cert(domain, port, cert_path): + import ssl + + # Cert file already available for this URL + if os.path.exists(cert_path): + return + + cert_data = ssl.get_server_certificate((domain, port)) + with open(cert_path, "w") as f: + f.write(cert_data) + + def publish_to_webhook(url, token, secret, message_queue): # Import requests here since not used in any other place import requests http_headers = {"Content-Type": "application/json"} + urldata = requests.utils.urlparse(url) + parts = urldata.netloc.split(":") + domain = parts[0] + # Default https port if not specified + port = 443 + if len(parts) == 2: + port = int(parts[1]) + + cert_path = os.path.join(CERTS_DIR, url.replace("/", "_").strip()) + while True: hashval = "" event_type, event_ts, message_json = message_queue.get() @@ -212,26 +235,55 @@ def publish_to_webhook(url, token, secret, message_queue): if hashval: http_headers["Authorization"] = "Bearer " + hashval - try: - resp = requests.post(url, headers=http_headers, data=message_json) - except requests.ConnectionError as e: - logger.warn("Event push failed to URL: {url}, " - "Event: {event}, " - "Status: {error}".format( - url=url, - event=message_json, - error=e)) - continue - finally: - message_queue.task_done() - - if resp.status_code != 200: - logger.warn("Event push failed to URL: {url}, " - "Event: {event}, " - "Status Code: {status_code}".format( - url=url, - event=message_json, - status_code=resp.status_code)) + verify = True + while True: + try: + resp = requests.post(url, headers=http_headers, + data=message_json, + verify=verify) + # Successful webhook push + message_queue.task_done() + if resp.status_code != 200: + logger.warn("Event push failed to URL: {url}, " + "Event: {event}, " + "Status Code: {status_code}".format( + url=url, + event=message_json, + status_code=resp.status_code)) + break + except requests.exceptions.SSLError as e: + # If verify is equal to cert path, but still failed with + # SSLError, Looks like some issue with custom downloaded + # certificate, Try with verify = false + if verify == cert_path: + logger.warn("Event push failed with certificate, " + "ignoring verification url={0} " + "Error={1}".format(url, e)) + verify = False + continue + + # If verify is instance of bool and True, then custom cert + # is required, download the cert and retry + try: + save_https_cert(domain, port, cert_path) + verify = cert_path + except Exception as ex: + verify = False + logger.warn("Unable to get Server certificate, " + "ignoring verification url={0} " + "Error={1}".format(url, ex)) + + # Done with collecting cert, continue + continue + except Exception as e: + logger.warn("Event push failed to URL: {url}, " + "Event: {event}, " + "Status: {error}".format( + url=url, + event=message_json, + error=e)) + message_queue.task_done() + break def plugin_webhook(message): |