-
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.
- Loading branch information
Showing
10 changed files
with
200 additions
and
63 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,2 +1,2 @@ | ||
dotfiles_url: "{{ lookup('env', 'DOTFILES_URL') }}" | ||
dotfiles_url: "{{ lookup('env', 'DOTFILES_URL', default='https://github.com/ilude/dotfiles.git') }}" | ||
dotfiles_path: "{{ lookup('env', 'HOME') + '/.dotfiles' }}" |
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
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
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
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,70 +1,38 @@ | ||
import docker | ||
import time | ||
import signal | ||
import sys | ||
import re | ||
from docker_monitor import DockerMonitor | ||
|
||
# Create a Docker client instance | ||
client = docker.from_env() | ||
monitor = None | ||
|
||
# Define a function to extract FQDNs from Traefik labels | ||
|
||
def signal_handler(received_signal: signal.Signals, frame): | ||
print(f"\nReceived signal: {signal.Signals(received_signal).name}, stopping event listener...") | ||
if monitor: | ||
monitor.stop() | ||
sys.exit(0) | ||
|
||
def extract_fqdns_from_labels(labels): | ||
traefik_host_labels = {k: v for k, v in labels.items() if k.startswith('traefik.http.routers.')} | ||
fqdns = [] | ||
for label_key, label_value in traefik_host_labels.items(): | ||
match = re.search(r'rule=Host\(`(.+?)`\)', label_value) | ||
if match: | ||
fqdn = match.group(1) | ||
fqdns.append(fqdn) | ||
return fqdns | ||
|
||
# Define a callback function to handle events | ||
|
||
|
||
def event_callback(event): | ||
if event['Action'] == 'start': | ||
container_name = event['Actor']['Attributes']['name'] | ||
container = client.containers.get(container_name) | ||
labels = container.labels | ||
fqdns = extract_fqdns_from_labels(labels) | ||
|
||
if fqdns: | ||
print(f"Container {container_name} started with Traefik FQDNs: {', '.join(fqdns)}") | ||
else: | ||
print(f"Container {container_name} started without Traefik host labels.") | ||
|
||
elif event['Action'] == 'stop': | ||
print(f"Container {event['Actor']['Attributes']['name']} stopped.") | ||
|
||
# Define a signal handler function | ||
|
||
def main(): | ||
# Set up signal handlers | ||
signal.signal(signal.SIGTERM, signal_handler) | ||
signal.signal(signal.SIGINT, signal_handler) | ||
|
||
def signal_handler(signal, frame): | ||
print("Received signal, stopping event listener...") | ||
sys.exit(0) | ||
# Create a DockerMonitor instance | ||
global monitor | ||
monitor = DockerMonitor() | ||
|
||
# Start the event listener in a separate thread | ||
event_thread = monitor.start() | ||
|
||
# Set up signal handlers | ||
signal.signal(signal.SIGTERM, signal_handler) | ||
signal.signal(signal.SIGINT, signal_handler) | ||
try: | ||
# Keep the main thread alive | ||
while True: | ||
pass | ||
except KeyboardInterrupt: | ||
print("Keyboard interrupt received, stopping event listener...") | ||
monitor.stop() | ||
|
||
# Get running containers with Traefik labels on startup | ||
print("Fetching running containers with Traefik labels...") | ||
running_containers = client.containers.list(filters={'status': 'running'}) | ||
for container in running_containers: | ||
labels = container.labels | ||
fqdns = extract_fqdns_from_labels(labels) | ||
if fqdns: | ||
print(f"Container {container.name} is running with Traefik FQDNs: {', '.join(fqdns)}") | ||
|
||
# Start listening for events | ||
print("Listening for Docker events...") | ||
try: | ||
for event in client.events(decode=True): | ||
event_callback(event) | ||
# Flush the output buffer to ensure the message is printed immediately | ||
time.sleep(0.1) | ||
except KeyboardInterrupt: | ||
print("Keyboard interrupt received, stopping event listener...") | ||
if __name__ == "__main__": | ||
main() |
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 |
---|---|---|
@@ -0,0 +1,45 @@ | ||
from enum import Enum | ||
from typing import Set | ||
from jinja2 import Environment, FileSystemLoader | ||
|
||
|
||
class docker: | ||
class ActionType(Enum): | ||
START = 1 | ||
STOP = 2 | ||
|
||
class Event: | ||
def __init__(self, fqdn_name: str, action_type): | ||
self._fqdn_name = fqdn_name | ||
self._action_type = action_type | ||
|
||
@property | ||
def fqdn_name(self) -> str: | ||
return self._fqdn_name | ||
|
||
@property | ||
def action_type(self): | ||
return self._action_type | ||
|
||
|
||
class CorefileGenerator: | ||
def __init__(self, template_path: str): | ||
self.template_path = template_path | ||
self.active_fqdns: Set[str] = set() | ||
self.env = Environment(loader=FileSystemLoader('/path/to/templates')) | ||
|
||
def process_event(self, event: docker.Event): | ||
fqdn_name = event.fqdn_name | ||
action_type = event.action_type | ||
|
||
if action_type == docker.ActionType.START: | ||
self.active_fqdns.add(fqdn_name) | ||
elif action_type == docker.ActionType.STOP: | ||
self.active_fqdns.discard(fqdn_name) | ||
|
||
def generate_corefile(self, output_path: str): | ||
template = self.env.get_template('Corefile.template') | ||
corefile_content = template.render(active_fqdns=self.active_fqdns) | ||
|
||
with open(output_path, 'w') as corefile: | ||
corefile.write(corefile_content) |
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 |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import os | ||
import docker | ||
import re | ||
import threading | ||
from typing import Set | ||
|
||
|
||
class DockerMonitor: | ||
is_manager: bool = False | ||
host_ip: str | ||
active_names: Set[str] = set() | ||
_stop_event = threading.Event() | ||
|
||
def __init__(self): | ||
self.client = docker.from_env() | ||
self.host_ip = os.environ.get('HOSTIP', '127.0.0.1') | ||
self.get_running_containers_with_traefik_labels() | ||
|
||
def update_core_dns(self, host_ip, fqdns): | ||
print("Updating CoreDNS with new FQDNs...") | ||
|
||
def extract_fqdns_from_labels(self, container, action): | ||
labels = container.labels | ||
traefik_host_labels = {k: v for k, v in labels.items() if k.startswith('traefik.http.routers.')} | ||
onetime_enabled = any(label.startswith('onetime.enabled=false') for label in labels) | ||
if not onetime_enabled: | ||
return False | ||
|
||
changed = False | ||
for _, label_value in traefik_host_labels.items(): | ||
match = re.search(r'rule=Host\(`(.+?)`\)', label_value) | ||
if match and match.group(1).strip() not in self.active_names: | ||
fqdn = match.group(1).strip() | ||
if action == 'start' and fqdn not in self.active_names: | ||
self.active_names.add(fqdn) | ||
changed = True | ||
if action == 'stop' and fqdn in self.active_names: | ||
self.active_names.discard(fqdn) | ||
changed = True | ||
return changed | ||
|
||
def event_callback(self, event): | ||
container_name = event['Actor']['Attributes']['name'] | ||
container = self.client.containers.get(container_name) | ||
changed = self.extract_fqdns_from_labels(container, event['Action']) | ||
if changed: | ||
self.update_core_dns(self.host_ip, self.active_names) | ||
|
||
def get_running_containers_with_traefik_labels(self): | ||
for container in self.client.containers.list(filters={'status': 'running'}): | ||
if 'coredns' in container.image.tags: | ||
self.is_manager = True | ||
next | ||
self.extract_fqdns_from_labels(container, 'start') | ||
self.update_core_dns(self.host_ip, self.active_names) | ||
|
||
def start(self): | ||
print("Listening for Docker events...") | ||
event_thread = threading.Thread(target=self.event_loop) | ||
event_thread.start() | ||
return event_thread | ||
|
||
def stop(self): | ||
self._stop_event.set() | ||
|
||
def event_loop(self): | ||
while not self._stop_event.is_set(): | ||
try: | ||
events = self.client.events(decode=True) | ||
for event in events: | ||
if self._stop_event.is_set(): | ||
break | ||
self.event_callback(event) | ||
events.close() | ||
except KeyboardInterrupt: | ||
self.stop() | ||
break |
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 |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import os | ||
import sys | ||
from watchdog.observers import Observer | ||
from watchdog.events import FileSystemEventHandler | ||
|
||
|
||
class ReloadHandler(FileSystemEventHandler): | ||
def on_any_event(self, event): | ||
if event.is_directory: | ||
return | ||
elif event.event_type == 'created': | ||
print(f"Created file: {event.src_path}") | ||
elif event.event_type == 'modified': | ||
print(f"Modified file: {event.src_path}") | ||
self.reload() | ||
|
||
def reload(self): | ||
python = sys.executable | ||
args = sys.argv[:] | ||
print(f"Reloading {' '.join(args)}") | ||
args.insert(0, python) | ||
os.execvp(python, args) | ||
|
||
|
||
def start_observer(paths): | ||
observer = Observer() | ||
event_handler = ReloadHandler() | ||
for path in paths: | ||
observer.schedule(event_handler, path, recursive=True) | ||
observer.start() | ||
return observer | ||
|
||
|
||
if __name__ == "__main__": | ||
paths = ['.'] | ||
observer = start_observer(paths) | ||
try: | ||
while True: | ||
pass | ||
except KeyboardInterrupt: | ||
observer.stop() | ||
observer.join() |
Empty file.
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,3 +1,4 @@ | ||
docker | ||
python-dotenv | ||
pyyaml | ||
watchdog |