2021-08-21 02:46:11 -04:00
|
|
|
#!/usr/bin/env python3
|
2018-10-03 19:42:42 -04:00
|
|
|
|
2018-11-21 20:26:58 -05:00
|
|
|
# dnsmasq-zookeeper-leases.py - DNSMASQ leases script for Zookeeper
|
|
|
|
# Part of the Parallel Virtual Cluster (PVC) system
|
|
|
|
#
|
2023-12-29 11:16:59 -05:00
|
|
|
# Copyright (C) 2018-2024 Joshua M. Boniface <joshua@boniface.me>
|
2018-11-21 20:26:58 -05:00
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
2021-03-25 16:57:17 -04:00
|
|
|
# the Free Software Foundation, version 3.
|
2018-11-21 20:26:58 -05:00
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
###############################################################################
|
2018-10-03 19:42:42 -04:00
|
|
|
import argparse
|
2020-11-07 12:29:32 -05:00
|
|
|
import os
|
|
|
|
import sys
|
2018-10-03 19:42:42 -04:00
|
|
|
import kazoo.client
|
|
|
|
import re
|
2019-03-17 13:57:09 -04:00
|
|
|
import yaml
|
2018-10-03 19:42:42 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
#
|
|
|
|
# Variables
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# General Functions
|
|
|
|
#
|
|
|
|
def get_zookeeper_key():
|
|
|
|
# Get the interface from environment (passed by dnsmasq)
|
2018-10-09 22:38:40 -04:00
|
|
|
try:
|
2021-11-06 03:02:43 -04:00
|
|
|
interface = os.environ["DNSMASQ_BRIDGE_INTERFACE"]
|
2019-03-17 13:57:09 -04:00
|
|
|
except Exception as e:
|
2021-11-06 03:02:43 -04:00
|
|
|
print(
|
|
|
|
"ERROR: DNSMASQ_BRIDGE_INTERFACE environment variable not found: {}".format(
|
|
|
|
e
|
|
|
|
),
|
|
|
|
file=sys.stderr,
|
|
|
|
)
|
2018-10-09 22:38:40 -04:00
|
|
|
exit(1)
|
2018-10-03 19:42:42 -04:00
|
|
|
# Get the ID of the interface (the digits)
|
2021-11-06 03:02:43 -04:00
|
|
|
network_vni = re.findall(r"\d+", interface)[0]
|
2018-10-03 19:42:42 -04:00
|
|
|
# Create the key
|
2021-11-06 03:02:43 -04:00
|
|
|
zookeeper_key = "/networks/{}/dhcp4_leases".format(network_vni)
|
2018-10-03 19:42:42 -04:00
|
|
|
return zookeeper_key
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
def get_lease_expiry():
|
|
|
|
try:
|
2021-11-06 03:02:43 -04:00
|
|
|
expiry = os.environ["DNSMASQ_LEASE_EXPIRES"]
|
2020-11-06 18:55:10 -05:00
|
|
|
except Exception:
|
2021-11-06 03:02:43 -04:00
|
|
|
expiry = "0"
|
2018-10-03 19:42:42 -04:00
|
|
|
return expiry
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
def get_client_id():
|
|
|
|
try:
|
2021-11-06 03:02:43 -04:00
|
|
|
client_id = os.environ["DNSMASQ_CLIENT_ID"]
|
2020-11-06 18:55:10 -05:00
|
|
|
except Exception:
|
2021-11-06 03:02:43 -04:00
|
|
|
client_id = "*"
|
2018-10-03 19:42:42 -04:00
|
|
|
return client_id
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
def connect_zookeeper():
|
|
|
|
# We expect the environ to contain the config file
|
|
|
|
try:
|
2023-11-26 14:18:13 -05:00
|
|
|
pvc_config_file = os.environ["PVC_CONFIG_FILE"]
|
2020-11-06 18:55:10 -05:00
|
|
|
except Exception:
|
2018-10-03 19:42:42 -04:00
|
|
|
# Default place
|
2023-11-26 14:18:13 -05:00
|
|
|
pvc_config_file = "/etc/pvc/pvc.conf"
|
2018-10-03 19:42:42 -04:00
|
|
|
|
2023-11-26 14:18:13 -05:00
|
|
|
with open(pvc_config_file, "r") as cfgfile:
|
2018-10-03 19:42:42 -04:00
|
|
|
try:
|
2023-08-31 00:16:19 -04:00
|
|
|
o_config = yaml.load(cfgfile, yaml.SafeLoader)
|
2019-03-17 13:57:09 -04:00
|
|
|
except Exception as e:
|
2021-11-06 03:02:43 -04:00
|
|
|
print(
|
|
|
|
"ERROR: Failed to parse configuration file: {}".format(e),
|
|
|
|
file=sys.stderr,
|
|
|
|
)
|
2018-10-03 19:42:42 -04:00
|
|
|
exit(1)
|
|
|
|
|
|
|
|
try:
|
2021-11-06 03:02:43 -04:00
|
|
|
zk_conn = kazoo.client.KazooClient(
|
2023-11-26 14:18:13 -05:00
|
|
|
hosts=o_config["cluster"]["coordinator_nodes"]
|
2021-11-06 03:02:43 -04:00
|
|
|
)
|
2018-10-03 19:42:42 -04:00
|
|
|
zk_conn.start()
|
2019-03-17 13:57:09 -04:00
|
|
|
except Exception as e:
|
2021-11-06 03:02:43 -04:00
|
|
|
print("ERROR: Failed to connect to Zookeeper: {}".format(e), file=sys.stderr)
|
2018-10-03 19:42:42 -04:00
|
|
|
exit(1)
|
|
|
|
|
|
|
|
return zk_conn
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
def read_data(zk_conn, key):
|
2021-11-06 03:02:43 -04:00
|
|
|
return zk_conn.get(key)[0].decode("ascii")
|
2018-10-03 19:42:42 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
def get_lease(zk_conn, zk_leases_key, macaddr):
|
2021-11-06 03:02:43 -04:00
|
|
|
expiry = read_data(zk_conn, "{}/{}/expiry".format(zk_leases_key, macaddr))
|
|
|
|
ipaddr = read_data(zk_conn, "{}/{}/ipaddr".format(zk_leases_key, macaddr))
|
|
|
|
hostname = read_data(zk_conn, "{}/{}/hostname".format(zk_leases_key, macaddr))
|
|
|
|
clientid = read_data(zk_conn, "{}/{}/clientid".format(zk_leases_key, macaddr))
|
2018-10-03 19:42:42 -04:00
|
|
|
return expiry, ipaddr, hostname, clientid
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
#
|
|
|
|
# Command Functions
|
|
|
|
#
|
|
|
|
def read_lease_database(zk_conn, zk_leases_key):
|
|
|
|
leases_list = zk_conn.get_children(zk_leases_key)
|
|
|
|
output_list = []
|
|
|
|
for macaddr in leases_list:
|
|
|
|
expiry, ipaddr, hostname, clientid = get_lease(zk_conn, zk_leases_key, macaddr)
|
2021-11-06 03:02:43 -04:00
|
|
|
data_string = "{} {} {} {} {}".format(
|
|
|
|
expiry, macaddr, ipaddr, hostname, clientid
|
|
|
|
)
|
|
|
|
print("Reading lease from Zookeeper: {}".format(data_string), file=sys.stderr)
|
|
|
|
output_list.append("{}".format(data_string))
|
2018-10-03 19:42:42 -04:00
|
|
|
|
|
|
|
# Output list
|
2021-11-06 03:02:43 -04:00
|
|
|
print("\n".join(output_list))
|
2019-06-25 22:31:04 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
def add_lease(zk_conn, zk_leases_key, expiry, macaddr, ipaddr, hostname, clientid):
|
2020-01-05 22:46:56 -05:00
|
|
|
if not hostname:
|
2021-11-06 03:02:43 -04:00
|
|
|
hostname = ""
|
2018-10-03 19:42:42 -04:00
|
|
|
transaction = zk_conn.transaction()
|
2021-11-06 03:02:43 -04:00
|
|
|
transaction.create("{}/{}".format(zk_leases_key, macaddr), "".encode("ascii"))
|
|
|
|
transaction.create(
|
|
|
|
"{}/{}/expiry".format(zk_leases_key, macaddr), expiry.encode("ascii")
|
|
|
|
)
|
|
|
|
transaction.create(
|
|
|
|
"{}/{}/ipaddr".format(zk_leases_key, macaddr), ipaddr.encode("ascii")
|
|
|
|
)
|
|
|
|
transaction.create(
|
|
|
|
"{}/{}/hostname".format(zk_leases_key, macaddr), hostname.encode("ascii")
|
|
|
|
)
|
|
|
|
transaction.create(
|
|
|
|
"{}/{}/clientid".format(zk_leases_key, macaddr), clientid.encode("ascii")
|
|
|
|
)
|
2018-10-03 19:42:42 -04:00
|
|
|
transaction.commit()
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
def del_lease(zk_conn, zk_leases_key, macaddr, expiry):
|
2021-11-06 03:02:43 -04:00
|
|
|
zk_conn.delete("{}/{}".format(zk_leases_key, macaddr), recursive=True)
|
2018-10-03 19:42:42 -04:00
|
|
|
|
2020-11-07 13:17:49 -05:00
|
|
|
|
2018-10-03 19:42:42 -04:00
|
|
|
#
|
|
|
|
# Instantiate the parser
|
|
|
|
#
|
2021-11-06 03:02:43 -04:00
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description="Store or retrieve dnsmasq leases in Zookeeper"
|
|
|
|
)
|
|
|
|
parser.add_argument("action", type=str, help="Action")
|
|
|
|
parser.add_argument("macaddr", type=str, help="MAC Address", nargs="?", default=None)
|
|
|
|
parser.add_argument("ipaddr", type=str, help="IP Address", nargs="?", default=None)
|
|
|
|
parser.add_argument("hostname", type=str, help="Hostname", nargs="?", default=None)
|
2018-10-03 19:42:42 -04:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
action = args.action
|
|
|
|
macaddr = args.macaddr
|
|
|
|
ipaddr = args.ipaddr
|
|
|
|
hostname = args.hostname
|
|
|
|
|
|
|
|
zk_conn = connect_zookeeper()
|
|
|
|
zk_leases_key = get_zookeeper_key()
|
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
if action == "init":
|
2018-10-03 19:42:42 -04:00
|
|
|
read_lease_database(zk_conn, zk_leases_key)
|
|
|
|
exit(0)
|
|
|
|
|
|
|
|
expiry = get_lease_expiry()
|
|
|
|
clientid = get_client_id()
|
|
|
|
|
|
|
|
#
|
|
|
|
# Choose action
|
|
|
|
#
|
2021-11-06 03:02:43 -04:00
|
|
|
print(
|
|
|
|
"Lease action - {} {} {} {}".format(action, macaddr, ipaddr, hostname),
|
|
|
|
file=sys.stderr,
|
|
|
|
)
|
|
|
|
if action == "add":
|
2018-10-03 19:42:42 -04:00
|
|
|
add_lease(zk_conn, zk_leases_key, expiry, macaddr, ipaddr, hostname, clientid)
|
2021-11-06 03:02:43 -04:00
|
|
|
elif action == "del":
|
2018-10-03 19:42:42 -04:00
|
|
|
del_lease(zk_conn, zk_leases_key, macaddr, expiry)
|
2021-11-06 03:02:43 -04:00
|
|
|
elif action == "old":
|
2018-10-03 19:42:42 -04:00
|
|
|
pass
|