#!/usr/bin/ruby require 'yaml'; $config = YAML::load( File.open( 'Hosts' ) ) $NAMESPACE=$config['namespace'] def sys(command) puts "} #{command}" system(command) or throw "Command '#{command}' failed" end def getFilesMD5(host, ssh_hostname) cmd = ssh_hostname ? "ssh -4 root@#{ssh_hostname} /bin/ls -1 /etc/openvpn" : "ls -1 #{$NAMESPACE}-#{host}" puts "| " + cmd f = IO.popen( cmd, aModeString="r" ); files = f.readlines.delete_if{|e| not e =~ /^#{$NAMESPACE}[.-]/ }.collect{|e| e.chomp} f.close md5 = {} if (files.length > 0) cmd = ssh_hostname ? "ssh -4 root@#{ssh_hostname} 'cd /etc/openvpn && md5sum " + files.join(' ') + "'" : "cd #{$NAMESPACE}-#{host} && md5sum " + files.join(' ') puts "| " + cmd f = IO.popen( cmd, aModeString="r" ); f.each_line{ |l| l.chomp! (h,file) = l.split(/\s+/,2) unless file STDERR.puts "Could not split '#{l}' into hash and filename - cmd was '#{cmd}'" next end md5[file] = h } f.close end return md5 end hosts = ARGV if hosts.size == 0 hosts = $config['hosts'].keys end hosts.each{ |hostname| puts "Pushing to #{hostname}." throw "Host #{hostname} not in config" unless $config['hosts'][hostname] ssh_hostnames = $config['hosts'][hostname]['ssh_hostname'] unless ssh_hostnames STDERR.puts "*** #{hostname} has no ssh_hostname!" next end ssh_hostname = nil ssh_hostnames.delete(' ').split(',').each{ |host| if not system("ping -W2 -c3 #{host}") STDERR.puts "*** #{host} is not reachable!" next else ssh_hostname = host break end } unless ssh_hostname STDERR.puts "*** no reachable host found for #{hostname}!" next end remote = getFilesMD5(hostname, ssh_hostname) local = getFilesMD5(hostname, nil) delete = [] copy = [] stop = [] restart = [] do_iptables = nil do_ip6tables = nil do_quagga = nil do_ferm = nil remote.each_pair{|f,h| if ! local.has_key?(f) delete << f if f =~ /\.conf$/ stop << f.gsub(/\.conf$/, '') end end } local.each_pair{|f,h| if ! remote.has_key?(f) || local[f] != remote[f] copy << f if f =~ /\.iptables\.sh$/ do_iptables = f elsif f =~ /\.ip6tables\.sh$/ do_ip6tables = f elsif f =~ /\.ferm$/ do_ferm = f elsif f =~ /\.quagga\.(bgpd|zebra|daemons)$/ do_quagga = true elsif f =~ /\.conf$/ restart << f.gsub(/\.conf$/, '') end end } dir = "#{$NAMESPACE}-#{hostname}/" sys("scp -4 "+copy.collect{|f| dir+f }.join(' ')+" root@#{ssh_hostname}:/etc/openvpn/") if copy.size > 0 commands = [] commands << "[ -e /etc/ferm/ferm.conf ] || sh ./#{do_iptables} &&\n" if do_iptables commands << "[ -e /etc/ferm/ferm.conf ] || sh ./#{do_ip6tables} &&\n" if do_ip6tables commands << "(! [ -e /etc/ferm/ferm.conf ] || ferm /etc/ferm/ferm.conf ) &&\n" if do_ferm #commands << "/etc/init.d/openvpn stop "+stop.join(' ')+" &&\n" if stop.size > 0 #commands << "/etc/init.d/openvpn restart "+restart.join(' ')+" && \n" if restart.size > 0 commands << "([ -e /bin/systemctl ] && systemctl daemon-reload || true ) && \n" commands << "service openvpn restart && \n" if restart.size > 0 or stop.size > 0 commands << "rm "+delete.join(' ')+" &&\n" if delete.size > 0 command = "cd /etc/openvpn && \n"; command << commands.join('') command << "echo 'all done'" sys("ssh -4 root@#{ssh_hostname} '#{command}'") if commands.size > 0 if (do_quagga) sys("ssh -4 root@#{ssh_hostname} 'cp -a /etc/openvpn/#{$NAMESPACE}.quagga.bgpd /etc/quagga/bgpd.conf && cp -a /etc/openvpn/#{$NAMESPACE}.quagga.zebra /etc/quagga/zebra.conf && cp -a /etc/openvpn/#{$NAMESPACE}.quagga.daemons /etc/quagga/daemons && chmod 640 /etc/quagga/bgpd.conf /etc/quagga/zebra.conf && chgrp quagga /etc/quagga/bgpd.conf /etc/quagga/zebra.conf && if [ -e /etc/init.d/quagga ]; then service quagga restart; else service bgpd stop; service zebra stop; sleep 1 ; service zebra start; sleep 0.5; service bgpd start ; fi'") end }