-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from mattermost/CLD-8788
Try to fix module failure
- Loading branch information
Showing
3 changed files
with
103 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,26 @@ | ||
BUILD_TAG := v1.2.0 | ||
BUILD_TAG := v1.2.1 | ||
IMAGE_NAME ?= mattermost/pgbouncer-config-reload | ||
all: build-image scan push | ||
build-image: ## Build the docker image for mattermost-cloud | ||
@echo Building Mattermost-cloud Docker Image | ||
build-image: ## Build the docker image | ||
@echo Building Docker Image | ||
@if [ -z "$(DOCKER_USERNAME)" ] || [ -z "$(DOCKER_PASSWORD)" ]; then \ | ||
echo "DOCKER_USERNAME and/or DOCKER_PASSWORD not set. Skipping Docker login."; \ | ||
else \ | ||
echo $(DOCKER_PASSWORD) | docker login --username $(DOCKER_USERNAME) --password-stdin; \ | ||
fi | ||
docker buildx build \ | ||
--platform linux/amd64,linux/arm64 \ | ||
. -f build/Dockerfile -t $(IMAGE_NAME):$(BUILD_TAG) \ | ||
. -f Dockerfile -t $(IMAGE_NAME):$(BUILD_TAG) \ | ||
--no-cache \ | ||
--push | ||
|
||
build-image-locally: ## Build the docker image locally | ||
@echo Building Docker Image Locally | ||
docker buildx build \ | ||
--platform linux/arm64 \ | ||
. -f Dockerfile -t $(IMAGE_NAME):$(BUILD_TAG) \ | ||
--no-cache \ | ||
--load | ||
|
||
scan: | ||
docker scan --accept-license ${IMAGE_NAME}:${BUILD_TAG} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,18 @@ | ||
#!/usr/bin/env python3 | ||
""" | ||
Tools for monitoring changes configuration and reload pgbouncer | ||
Tools for monitoring changes to configuration and reloading pgbouncer. | ||
""" | ||
|
||
|
||
import configargparse | ||
import logging | ||
import pyinotify | ||
import psycopg2 | ||
import os | ||
import sys | ||
import signal | ||
import time | ||
|
||
from watchdog.observers import Observer | ||
from watchdog.events import FileSystemEventHandler | ||
|
||
__author__ = "kvelichko" | ||
__email__ = "[email protected]" | ||
|
@@ -21,114 +21,123 @@ | |
log = logging.getLogger('configmap-reload') | ||
|
||
|
||
class ConfigmapHandler(pyinotify.ProcessEvent): | ||
|
||
def __init__( | ||
self, | ||
host, | ||
port, | ||
user, | ||
password, | ||
database='pgbouncer', | ||
timeout=10 | ||
): | ||
class ConfigmapHandler(FileSystemEventHandler): | ||
""" | ||
A watchdog event handler to reload pgbouncer when relevant files change. | ||
""" | ||
def __init__(self, host, port, user, password, database='pgbouncer', timeout=10): | ||
""" | ||
:param host - pgbouncer hostname | ||
:param port - pgbouncer port | ||
:param user - pgbouncer admin user | ||
:param password - pgbouncer admin password | ||
:param database - pgbouncer admin database | ||
:param timeout - timeout before send reload to pgbouncer | ||
:param host: pgbouncer hostname | ||
:param port: pgbouncer port | ||
:param user: pgbouncer admin user | ||
:param password: pgbouncer admin password | ||
:param database: pgbouncer admin database | ||
:param timeout: wait time (seconds) before sending reload to pgbouncer | ||
""" | ||
super().__init__() | ||
self.host = host | ||
self.port = port | ||
self.user = user | ||
self.password = password | ||
self.database = database | ||
self.timeout = timeout | ||
|
||
def pgbouncer_reload(self): | ||
def on_created(self, event): | ||
""" | ||
Function for reload pgbouncer | ||
Triggered when a file/directory is created. | ||
If the created file's name starts with "..data", | ||
wait and then reload pgbouncer. | ||
""" | ||
if not event.is_directory: | ||
log.info(f"CREATE event: '{event.src_path}'") | ||
if os.path.basename(event.src_path).startswith('..data'): | ||
time.sleep(self.timeout) | ||
self.pgbouncer_reload() | ||
|
||
def pgbouncer_reload(self): | ||
""" | ||
Execute pgbouncer RELOAD. | ||
""" | ||
log.debug("Pgbouncer graceful reload starting...") | ||
connection = None | ||
log.debug("Pgbouncer gracefull reload starting...") | ||
cursor = None | ||
try: | ||
connection = psycopg2.connect( | ||
user=self.user, | ||
password=self.password, | ||
host=self.host, | ||
port=self.port, | ||
database=self.database | ||
) | ||
user=self.user, | ||
password=self.password, | ||
host=self.host, | ||
port=self.port, | ||
database=self.database | ||
) | ||
connection.set_isolation_level(0) | ||
cursor = connection.cursor() | ||
cursor.execute("RELOAD;") | ||
connection.commit() | ||
except (Exception, psycopg2.Error) as error: | ||
log.error("Failed to RELOAD pgbouncer: %s" % (error)) | ||
log.error(f"Failed to RELOAD pgbouncer: {error}") | ||
finally: | ||
if (connection): | ||
if cursor: | ||
cursor.close() | ||
if connection: | ||
connection.close() | ||
log.debug("Pgbouncer connection is closed") | ||
log.info("Pgbouncer gracefull reloaded.") | ||
|
||
def process_IN_CREATE(self, event): | ||
log.info("CREATE event: '%s'" % (event.pathname)) | ||
if os.path.basename(event.pathname).startswith('..data'): | ||
time.sleep(self.timeout) | ||
self.pgbouncer_reload() | ||
log.info("Pgbouncer gracefully reloaded.") | ||
|
||
|
||
def exit_signal_handler(signum, frame): | ||
""" | ||
Function for logging signals and interrupt program | ||
Handle termination signals to ensure clean shutdown. | ||
""" | ||
log.info("Signal '%s' received. Shutdown..." | ||
% (signal.Signals(signum).name)) | ||
log.info(f"Signal '{signal.Signals(signum).name}' received. Shutting down...") | ||
sys.exit() | ||
|
||
|
||
def run(args={}): | ||
def run(args): | ||
""" | ||
main function | ||
:param args - dict of arguments | ||
Main function that sets up the file observers and starts the watchdog loop. | ||
""" | ||
# watch manager | ||
wm = pyinotify.WatchManager() | ||
observer = Observer() | ||
|
||
event_handler = ConfigmapHandler( | ||
host=args.pgbouncer_host, | ||
port=args.pgbouncer_port, | ||
user=args.pgbouncer_user, | ||
password=args.pgbouncer_password, | ||
database=args.pgbouncer_database, | ||
timeout=int(args.pgbouncer_reload_timeout) | ||
) | ||
|
||
for path in args.config_path.split(";"): | ||
wm.add_watch(path, pyinotify.IN_CREATE, rec=True) | ||
|
||
# event handler | ||
eh = ConfigmapHandler( | ||
args.pgbouncer_host, | ||
args.pgbouncer_port, | ||
args.pgbouncer_user, | ||
args.pgbouncer_password, | ||
args.pgbouncer_database, | ||
int(args.pgbouncer_reload_timeout) | ||
) | ||
if os.path.isdir(path): | ||
log.info(f"Watching path: {path}") | ||
observer.schedule(event_handler, path, recursive=True) | ||
else: | ||
log.warning(f"Path '{path}' is not a directory or does not exist. Skipping...") | ||
|
||
# notifier | ||
observer.start() | ||
log.info("Entering event loop...") | ||
notifier = pyinotify.Notifier(wm, eh) | ||
notifier.loop() | ||
|
||
try: | ||
while True: | ||
time.sleep(1) | ||
except KeyboardInterrupt: | ||
pass | ||
finally: | ||
observer.stop() | ||
observer.join() | ||
|
||
|
||
def main(): | ||
p = configargparse.ArgParser( | ||
description='Tools for monitoring pgbouncer configurations' | ||
' files and gracefull reload it.' | ||
) | ||
description='Tool for monitoring pgbouncer configuration files and gracefully reloading them.' | ||
) | ||
p.add("-v", "--verbose", | ||
help='Verbosity (-v -vv -vvv)', | ||
action='count', | ||
env_var='VERBOSE', | ||
default=0) | ||
p.add("-c", "--config-path", | ||
help="Semicolons separated configuration path for watching. (Ex: /etc/pgbouncer;/etc/userlist)", | ||
help="Semicolon-separated paths to watch. (e.g. /etc/pgbouncer;/etc/userlist)", | ||
required=True, | ||
env_var='CONFIG_PATH') | ||
p.add("-H", "--pgbouncer-host", | ||
|
@@ -152,43 +161,45 @@ def main(): | |
default='pgbouncer', | ||
env_var='PGBOUNCER_DATABASE') | ||
p.add("-t", "--pgbouncer-reload-timeout", | ||
help="Timeout before reload configuration of pgbouncer " | ||
"(default: 10)", | ||
help="Timeout before reloading pgbouncer (default: 10)", | ||
default=10, | ||
env_var='PGBOUNCER_RELOAD_TIMEOUT') | ||
p.add("-j", "--json-log", | ||
action='store_true', | ||
help="Print logs as JSON", | ||
help="Enable JSON-formatted logs", | ||
default=False, | ||
env_var='LOG_JSON') | ||
|
||
args = p.parse_args() | ||
|
||
# Configure log | ||
handler = logging.StreamHandler() | ||
if args.json_log: | ||
from pythonjsonlogger import jsonlogger | ||
formatter = jsonlogger.JsonFormatter( | ||
fmt="%(asctime)s %(levelname)s %(message)s", | ||
datefmt="%Y-%m-%d %H:%M:%S") | ||
# Adjusted import for python-json-logger change | ||
from pythonjsonlogger.json import JsonFormatter | ||
formatter = JsonFormatter( | ||
fmt="%(asctime)s %(levelname)s %(message)s", | ||
datefmt="%Y-%m-%d %H:%M:%S" | ||
) | ||
handler.setFormatter(formatter) | ||
else: | ||
formatter = logging.Formatter( | ||
fmt='%(asctime)s\t%(levelname)s: %(message)s', | ||
datefmt="%Y-%m-%d %H:%M:%S") | ||
fmt='%(asctime)s\t%(levelname)s: %(message)s', | ||
datefmt="%Y-%m-%d %H:%M:%S" | ||
) | ||
handler.setFormatter(formatter) | ||
log.addHandler(handler) | ||
|
||
log.addHandler(handler) | ||
loglvl = logging.ERROR | ||
if args.verbose > 0: | ||
loglvl = 40 - 10*args.verbose | ||
loglvl = max(logging.ERROR - 10 * args.verbose, logging.DEBUG) | ||
log.setLevel(loglvl) | ||
|
||
# Configure interrupt signal handler | ||
# Configure interrupt signal handlers | ||
signal.signal(signal.SIGINT, exit_signal_handler) | ||
signal.signal(signal.SIGTERM, exit_signal_handler) | ||
|
||
log.info("Initialization complete...") | ||
|
||
run(args) | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
psycopg2 >= 2.9.1 | ||
psycopg2 >= 2.9.10 | ||
python-json-logger >= 2.0.2 | ||
configargparse >= 1.5.2 | ||
pyinotify >= 0.9.6 | ||
watchdog >= 3.0.0 |