from pymysql import connect from ipaddress import IPv4Network from randmac import RandMac from sys import stderr, argv from subprocess import run, PIPE DB_HOST = "" DB_USER = "" DB_PASS = "" DB_NAME = "" SSH_HOST = "" SSH_PORT = "" SSH_KEY = "" SSH_USER = "" DEFAULT_INTERFACE = "" debug = False if debug: print("DEBUG MOD ACTICATED !") def main(args): """ args: list List of IP prefix This function get from DB and routeur IPs and MACs, create insertion list and sent it """ # DB connection try: print("Connect to DB...") db = connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) cursor = db.cursor() except: print("Can't connect to DB !", file=stderr) exit(1) else: print("Connected to DB") # Get IPs from DB try: print("Get IPs...") cursor.execute("SELECT ip FROM mg_proxmox_addon_ip") ipRow = cursor.fetchall() ipRow = [i[0] for i in ipRow] except: print("Failt to get IPs !", file=stderr) exit(1) else: print("IPs get") # Get MACs from DB try: print("Get MACs...") cursor.execute("SELECT mac_address FROM mg_proxmox_addon_ip") macRow = cursor.fetchall() macRow = [i[0] for i in macRow] except: print("Fail to get MACs !", file=stderr) exit(1) else: print("MACs get") # Get IPs and MACs from routeur try: print("Get routeur IPs and MACs...") routeur = run(["ssh", "-i", SSH_KEY, "-o", "StrictHostKeyChecking no", f"{SSH_USER}@{SSH_HOST}", "-p", SSH_PORT, "/ip arp print"], stdout=PIPE).stdout.decode() except: print("Failt to get reouteur IPs and MACs !", file=stderr) exit(1) else: print("Routeur IPs and MACs get") cursor.close() # Get vlan give on the first arg vlan = args[0] if vlan != "null": try: vlan = int(vlan) except: print("Invalid vlan !", file=stderr) exit(1) del args[0] # Get list of ip, mac and subnet_mask to add out = [] for arg in args: out+=addIPs(arg, ipRow, macRow) # Insert the list print(f"Start insert of {len(out)} IPs") insertIPs(out, vlan, db, routeur) def addIPs(prefix: str, ipRow: [str], macRow: [str]) -> [(str, str, str, int)]: """ prefix: str The IPs prefix ipRow: list of str A list of IPs in the DB macRow: list of string A list of MACs in the DB return: List of tupple with IP, MAC, subnet_mask and cidr This function generate a lits of IPs and MACs to insert """ out = [] # Check if prefix is valid try: print(f"Get IPs for {prefix}") ips = IPv4Network(prefix) subnet_mask = ips.netmask cidr = ips.prefixlen except: print("Invalid IP prefix !", file=stderr) else: # For all ip in prefix for ip in ips.hosts(): # Check DB if str(ip) not in ipRow: # Random until not in DB mac = RandMac("00:00:00:00:00:00", True) while mac in macRow: mac = RandMac() # Append to shared list to avoid colisions ipRow.append(ip) macRow.append(mac) out.append((str(ip), str(mac), str(subnet_mask), int(cidr))) else: print(f"IP: {ip} already on DB !", file=stderr) print(f"Got {len(out)} IPs") return out def insertIPs(insert: [(str, str, str, int)], vlan, db, routeur): """ insert: List of tupple with IP, MAC and subnet_mask The list of IPs, MACs to insert db: MySQL DB object The DB to insert routeur: str A string content MACs and IPs content in routeur This function insert given IPs and MACs to SB and routeur (if necessary) """ cursor = db.cursor() # For every IP to insert gateway = insert[0][0] del insert[0] print(f"Use gateway: {gateway}") for i in insert: # Try insert into DB try: cmd = f"INSERT INTO mg_proxmox_addon_ip (ip, type, mac_address, subnet_mask, cidr, gateway, tag) VALUES ('{i[0]}', 'IPv4', {i[1]}, '{i[2]}', {i[3]}, '{gateway}', {vlan})" if debug: print(cmd) cursor.execute(cmd) except Exception as e: raise e print(f"Fail to insert values !\nIP: {i[0]}, Type: IPv4, MAC: {i[1]}, subnet_mask: {i[2]}", file=stderr) else: # Optional log #print(f"IP: {i[0]} of type IPv4 with MAC: {i[1]} on subnet_mask: {i[2]} add") # If IP and MAC ar not in the routeur, add them if ((i[0] not in routeur) or not (routeur[routeur.find(i[0]):5].replace(" ", ""))) and (i[1] not in routeur): if vlan != "null": interface = f"vlan{vlan}" else: interface = DEFAULT_INTERFACE cmd = ["ssh", "-i", SSH_KEY, "-o", "StrictHostKeyChecking no", f"{SSH_USER}@{SSH_HOST}", "-p", SSH_PORT, f"/ip arp add address={i[0]} mac-address={i[1]} interface={interface}".replace("'", "")] if debug: print(cmd) else: run(cmd) elif debug: print(f"Already on the routeur !\nIP: {i[0]}, Type: IPv4, MAC: {i[1]}, subnet_mask: {i[2]}", file=stderr) cursor.close() # Commit to the DB if debug: print("Commit DB...") else: try: print("Commit to DB...") db.commit() except: print("Fail to commit !", file=stderr) exit(1) else: print("Commited to DB") # Execution as a script handler if __name__ == "__main__": # Avoid file name on args if argv[0] == __file__: del argv[0] # Start main function main(argv)