Created
March 13, 2016 09:04
-
-
Save holly/4a5925c256c71fdf5116 to your computer and use it in GitHub Desktop.
script for dnsmasq master/slave
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
#!/usr/bin/env python3 | |
from argparse import ArgumentParser | |
from subprocess import Popen, PIPE, STDOUT | |
import shlex | |
import hashlib | |
import time | |
import warnings | |
import os, sys, io | |
import signal | |
import re | |
DELAY = 1 | |
DNSMASQ_ADDN_HOSTS = "/etc/dnsmasq.hosts.d" | |
DNSMASQ_RESTART_COMMAND = "sudo systemctl restart dnsmasq" | |
RSYNC_CMD = "/usr/bin/rsync" | |
RSYNC_OPTIONS = ["--delete", "-a", "-x", "--rsync-path", "sudo " + RSYNC_CMD]; | |
SSH_CMD = "/usr/bin/ssh" | |
SSH_OPTIONS = ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-o", "ConnectTimeout=30"] | |
REMOTE_COMMAND_TIMEOUT = 10 | |
VERSION = "1.0" | |
parser = ArgumentParser(description="foo") | |
parser.add_argument('--version', '-v', action='version', version='%(prog)s ' + VERSION) | |
parser.add_argument('--slave-servers', action='store', required=True, nargs='*', help='dnsmasq slave servers') | |
parser.add_argument('--ssh-user', '-u', action='store', default=os.environ.get("USER"), metavar='SSH_USER', help='dnsmasq server execute ssh account name') | |
parser.add_argument('--ssh-key', '-i', action='store', metavar='SSH_PRIVATE_KEY', help='dnsmasq server execute ssh key') | |
parser.add_argument('--remote-command-timeout', '-t', type=int, action='store', metavar='REMOTE_COMMAND_TIMEOUT', default=REMOTE_COMMAND_TIMEOUT, help='remote dnsmasq server execution timeout seconds') | |
parser.add_argument('--delay', action='store', type=int, metavar='DELAY SECONDS', default=DELAY, help='check delay seconds') | |
parser.add_argument('--dnsmasq-addn-hosts', action='store', metavar='DNSMASQ_ADDN_HOSTS', default=DNSMASQ_ADDN_HOSTS, help='dnsmasq dns server addn-hosts(file or directory)') | |
def checksum_file(path): | |
m = hashlib.md5() | |
with open(path) as f: | |
m.update(f.read().encode("utf-8")) | |
return m.hexdigest() | |
def addn_hosts_meta(addn_hosts): | |
meta = [] | |
if os.path.isfile(addn_hosts): | |
meta.append({ addn_hosts: checksum_file(addn_hosts) }) | |
elif os.path.isdir(addn_hosts): | |
for entry in os.listdir(addn_hosts): | |
if re.match('^.*\.(swp|bk|git)$', entry): | |
continue | |
path = os.path.join(addn_hosts, entry) | |
meta.append({ os.path.join(path): checksum_file(path) }) | |
else: | |
sys.exit("dnsmasq-addn-hosts has to be a file or directory") | |
return meta | |
def make_rsync_command(server, args): | |
# ssh option | |
ssh_opts = ["ssh"] | |
ssh_opts.extend(SSH_OPTIONS) | |
ssh_opts.append("-l") | |
ssh_opts.append(shlex.quote(args.ssh_user)) | |
if args.ssh_key: | |
ssh_opts.append("-i") | |
ssh_opts.append(shlex.quote(args.ssh_key)) | |
ssh_opts_str = " ".join(ssh_opts) | |
rsync_cmds = [RSYNC_CMD] | |
rsync_cmds.extend(RSYNC_OPTIONS) | |
rsync_cmds.append("-e") | |
rsync_cmds.append(ssh_opts_str) | |
addn_hosts = args.dnsmasq_addn_hosts | |
if os.path.isdir(addn_hosts) and addn_hosts[-1] != "/": | |
addn_hosts = addn_hosts + "/" | |
rsync_cmds.append(addn_hosts) | |
rsync_cmds.append(server + ':' + addn_hosts) | |
return rsync_cmds | |
def make_ssh_command(server, args, remote_command=None): | |
ssh_cmds = [SSH_CMD] | |
ssh_cmds.extend(SSH_OPTIONS) | |
ssh_cmds.append("-l") | |
ssh_cmds.append(shlex.quote(args.ssh_user)) | |
if args.ssh_key: | |
ssh_cmds.append("-i") | |
ssh_cmds.append(shlex.quote(args.ssh_key)) | |
ssh_cmds.append(server) | |
ssh_cmds.append(remote_command) | |
return ssh_cmds | |
def main(): | |
args = parser.parse_args() | |
addn_hosts = args.dnsmasq_addn_hosts | |
before_meta = addn_hosts_meta(addn_hosts) | |
while True: | |
time.sleep(args.delay) | |
after_meta = addn_hosts_meta(addn_hosts) | |
if before_meta == after_meta: | |
print("{0} is not updated. skip".format(addn_hosts)) | |
continue | |
# local(master) restart dnsmasq | |
p = Popen(shlex.split(DNSMASQ_RESTART_COMMAND), universal_newlines=True, stderr=STDOUT) | |
outs, errs = p.communicate(timeout=args.remote_command_timeout) | |
print("{0}: {1} execute command. returncode:{2}".format("localhost", DNSMASQ_RESTART_COMMAND, p.returncode)) | |
if p.returncode != 0: | |
sys.exit("dnsmasq master update failure. returncode:{0} message:{1}".format(p.returncode, errs)) | |
for server in args.slave_servers: | |
rsync_command = make_rsync_command(server, args) | |
ssh_command = make_ssh_command(server, args, DNSMASQ_RESTART_COMMAND) | |
for command in [rsync_command, ssh_command]: | |
p = Popen(command, universal_newlines=True, stderr=STDOUT) | |
outs, errs = p.communicate(timeout=args.remote_command_timeout) | |
print("{0}: {1} execute command. returncode:{2}".format(server, command[0], p.returncode)) | |
if p.returncode != 0: | |
sys.exit("dnsmasq slave update failure. returncode:{0} message:{1}".format(p.returncode, errs)) | |
before_meta = after_meta | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment