Files
homelab/active/device_unifi/rmq_dns.py
ducoterra f2015e2c71
All checks were successful
Podman DDNS Image / build-and-push-ddns (push) Successful in 1m3s
checkpoint commit
2026-05-05 06:26:40 -04:00

137 lines
4.6 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
RabbitMQ setup & consumer using pika.
- Creates two **topic exchanges**: nic, reese
- For each exchange creates two queues: add, delete
- Binds the queues with routing keys “add” and “delete”
- Subscribes (consumes) from a **single** exchange/queue pair that is
supplied via a tiny config file (config.yaml).
Run:
python3 rabbit_demo.py
"""
import logging
import sys
from pathlib import Path
import pika # type: ignore
import yaml
# ----------------------------------------------------------------------
# 1⃣ Load configuration
# ----------------------------------------------------------------------
DEFAULT_CFG = """
rabbitmq:
host: "localhost"
port: 5672
virtual_host: "/"
username: "guest"
password: "guest"
# Which *exchange* (topic) you actually want to listen to.
# The program will create a temporary queue, bind it to this exchange
# with the routing key supplied in `routing_key`.
subscriber:
exchange: "nic" # ← change to “reese” or any other exchange
routing_key: "add" # ← could be “add”, “delete”, or any pattern
"""
CONFIG_PATH = Path("active/device_unifi/config.yaml")
if not CONFIG_PATH.exists():
CONFIG_PATH.write_text(DEFAULT_CFG)
with CONFIG_PATH.open() as f:
cfg = yaml.safe_load(f)
# ----------------------------------------------------------------------
# 2⃣ Build connection parameters
# ----------------------------------------------------------------------
cred = pika.PlainCredentials(cfg["rabbitmq"]["username"], cfg["rabbitmq"]["password"])
params = pika.ConnectionParameters(
host=cfg["rabbitmq"]["host"],
port=cfg["rabbitmq"]["port"],
virtual_host=cfg["rabbitmq"]["virtual_host"],
credentials=cred,
)
# ----------------------------------------------------------------------
# 3⃣ Helper to declare exchanges / queues
# ----------------------------------------------------------------------
def declare_topology(channel):
"""
Create the two topic exchanges and the four queues,
then bind each queue to its exchange with the appropriate routing key.
"""
exchanges = ["nic", "reese"]
routing_keys = ["add", "delete"]
for exch in exchanges:
channel.exchange_declare(exchange=exch, exchange_type="topic", durable=True)
for key in routing_keys:
queue_name = f"{exch}_{key}" # e.g. nic_add, reese_delete
channel.queue_declare(queue=queue_name, durable=True)
# bind queue to the exchange with the same routing key
channel.queue_bind(queue=queue_name, exchange=exch, routing_key=key)
logging.info(
f"Declared queue {queue_name} bound to {exch} with key '{key}'"
)
# ----------------------------------------------------------------------
# 4⃣ Consumer callback
# ----------------------------------------------------------------------
def on_message(ch, method, properties, body):
logging.info(
f"Received from exchange '{method.exchange}' "
f"routing_key='{method.routing_key}': {body!r}"
)
# Acknowledge the message
ch.basic_ack(delivery_tag=method.delivery_tag)
# ----------------------------------------------------------------------
# 5⃣ Main routine
# ----------------------------------------------------------------------
def main():
logging.basicConfig(
level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s"
)
with pika.BlockingConnection(params) as conn:
channel = conn.channel()
# 1⃣ Declare the static topology (exchanges + queues)
declare_topology(channel)
# 2⃣ Set up a *temporary* queue for the subscriber defined in config
result = channel.queue_declare(
queue="", exclusive=True
) # servergenerated name
tmp_queue = result.method.queue
exch = cfg["subscriber"]["exchange"]
rkey = cfg["subscriber"]["routing_key"]
channel.queue_bind(queue=tmp_queue, exchange=exch, routing_key=rkey)
logging.info(
f"Subscribed to exchange '{exch}' with routing_key '{rkey}' "
f"using temporary queue '{tmp_queue}'"
)
# 3⃣ Start consuming
channel.basic_consume(queue=tmp_queue, on_message_callback=on_message)
try:
logging.info("Waiting for messages. Press Ctrl+C to exit.")
channel.start_consuming()
except KeyboardInterrupt:
logging.info("Interrupted closing connection.")
channel.stop_consuming()
if __name__ == "__main__":
sys.exit(main())