Setting up RSync

what i'm basically trying to do is set up a system where i have a management server that has the "master configurations" for bind, mailscanner rules, sendmail rules (mailertable, access, and such) and a few other static files, and a bunch of slave servers that all run the same configuration where if the management server is changed, the slaves will be updated to reflect that within a decent amount of time.  i've been reading alot and it looks like RSync and some scripting (which i'm looking forward to learning) is probably my best bet for doing this.  all of the boxes that are slaves are running RHEL3 ES and the master is running redhat 9 (it will be RHEL3 in about six months probably) and rsync was installed on all of them already and all of the default locations for those services are still there.

anyways, from what little i've read, they say that i should set up the management server to be an RSync server that runs in deamon mode.  so i set up a rsyncd.conf file in my /etc/ dir that looks like the below:
motd file = /etc/rsyncd.motd
log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
syslog facility = daemon
socket options = SO_KEEPALIVE
max connections = 25
uid = nobody
gid = nogroup


[testing]
        path = /etc/rsync/test
        comment = For RSync testing purposes only
        read only = true
        auth users = authorized_account1,authorized_account2
        secrets file = /etc/rsyncd.secrets
        list = yes

i stole the config from another site that had a guide that i couldn't get to work for me so if there is stuff in there that doesn't make sense, thats probably why.  i also created a rsyncd.motd and put some text in there and a rsyncd.secrets file that basically has those usernames and passwords like the guide stated.  just to be clear, all of these servers are on a lan behind a few firewalls so i'm not too concerned about security but if it works with or without it, i'll take it.  i didn't create any of the other files but did type in the 'rsync --daemon' command which redhat took without complaint so i'm assuming its running in daemon mode now.

i logged into one of the slave servers and did the below command:
rsync -avz root@10.10.10.12:/testing/file1 /etc/rsync/testing
(/etc/rsync/testing is a directory on the local box while file1 is a file in /etc/rsync/test on the master server which is remote)
and i get teh following error:

master1.mydomain.com: Connection refused
rsync: connection unexpectedly closed (0 bytes read so far)
rsync error: error in rsync protocol data stream (code 12) at io.c(165)

so i'm a little lost as to what i missed or what is going on.  this is a very new technology to me so until i get it down once and figure out how its supposed to look, i'm probably going to be lost on it.

Also, once i get this server up, am i correct in assuming i can get the master server (via a script) to push config files down to the slave systems when the master system's files change?  also, can i (via rsync or script) remotely run commands like "makemap hash" on the remote systems?  obviously if i'm trying to sync mailertable's, they'll have to compile after being downloaded.  thoughts?
LVL 1
onsite_techAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jlevieCommented:
In my opinion you are going about this the wrong way. Whenever i do something like this I use a "pull" method, typically implemented with perl scripts run from a crontab. For a given file the process works like

1) Use scp to copy the file from the master to the slave, giving the received file a temp name. For example:

    scp master:/path-to-node's/mailertable /etc/mail/mailertable.tmp

2) Compare the current and copied file to see if they are different. If so rename the copied file to the correct name and then take the appropriate action.

andy20Commented:
As jlevie says you may be going about this wrongly, however I've recently implemented an rsync system here, whereby my master server runs rsync in daemon then nightly another machine runs to pull the master config down, but it only pulls the changed files, hence why rsync is a good way of doing this, as it skips having to make perl scripts to compare, etc, etc.

Anyway, your problem, is there a firewall running on the master? If so, make sure it is permitting port 873 tcp/udp, as that would explain the refusal message.

Also in your /etc/rsyncd.conf file try putting in
   hosts allow = 192.168.0.13
into the [testing]
section (change the IP to your slave machine), and see if that helps.
Then check in /var/log/syslog or /var/log/messages or /var/log/rsyncd.log on your master to see if rsync threw an error out.
uglyrockCommented:
Hi there

now i haven't tried to setup this kind of arrangement before, but if i were to do this, here's what I would do

1.) List out all the config files that you want to be Rsync'd across the cluster
2.) Create a cluster-conf.d directory in /etc
3.) move all the configs to /etc/cluster-conf.d
4.) Create symlinks from the original files to the cluster-conf.d directory (Better still once done I would script this in Bash)
5.) Now you have your master server set-up, you can use your bash script to replicate it on the other servers. :-)

The
Rsync bit....

So now you can just call Rsync when ever you need it to Sync the files to the relevant servers

rsync -a -e ssh /etc/clust-conf.d root@your.remote.server

Now if you want this to happen automatically you will have to setup some pre-shared ssh keys.

Now lets assume you have got 40 servers, you can easily script this into a loop, reading the host list from a file.

The final thing of course is that although you have updated the configs, they may not be re-read by the service until it  restarts. However,  you can script round this by testing the modification time of the file in the /etc/clust-conf.d directory and taking appropriate action, either Rsync to the slaves if its the master server or restarting the services if its a slave.

I know this is a bit thin on details, so if you need more help let me know

Hope this helps
Uglyrock
Exploring SharePoint 2016

Explore SharePoint 2016, the web-based, collaborative platform that integrates with Microsoft Office to provide intranets, secure document management, and collaboration so you can develop your online and offline capabilities.

decoleurCommented:
on top of confirming that your firewall on your master machine is not getting in your way I would check to make sure that rsync is running on your master machine by typing something like (i think the rsync daemon goes by rsyncd):

/sbin/service/ rsyncd status

you can also add it to automatically start by typing something like

/sbin/chkconfig --levels 2345 rsyncd on

and confirm this by typing

/sbin/chkconfig --list
or
/sbin/chkconfig --list rsyncd

you might try to disable your firewall while you test your rsync config, as well.

HTH

-t
onsite_techAuthor Commented:
will scp require any configuration?  it seems more and more like an active scripting solution might be the best approach so if scp is that easy then i will be very happy.

one quick Q though, how does authentication work with that?  i haven't tried it yet as that project has been pushed down on my project pool until probably sometime next month but i'm eager to see how it works.
decoleurCommented:
scp is part of the OpenSSH package, it relies on port 22 just like ssh and uses the sshd_config... just remember to set premitrootlogin to no, and you should be fine.

it is a piece of cake

scp source destination

to push from local machine to remote

scp /path/to/source remoteUser@remoteHost:/path/to/destination

to pull from remote site to local host

scp remoteUser@remoteHost:/path/to/source /path/to/destination

to move from one remote host to another :)

scp remoteUser1@remoteHost1:/path/to/source remoteUser2@remoteHost2/path/to/destination

hope this helps

-t

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
onsite_techAuthor Commented:
i set up a neat little open-ended script that basically uses PHP via command line in combination with scp and ssh to do push based updates from my primary servers to the other boxes, so the stuff you guys gave me worked great.  in case anyone is curious, here is the script (ignore the bad code, or optimize it on your end.  i was rushed for time so its not as clean as i would like and i'm also a server admin not a developer so everything leans more towards "it works" then "it works clean and efficiently").

the script is broken up into 3 files.  

The updater.php file is the core engine that runs the push to the remote systems and executes the commands on those boxes.  this part of the script should almost never need to change (when you modify the script to update different files) and is instead called by a 'template' script that tells it what to update (so you can use the same updater.php file to update the named.conf files or the mailscanner rules or the access.db files on the remote systems, and just have a different single template file for each type of update you want to do.  here is the updater.php script

<?
//Name:         updater.php
//Author:      
//Purpose:      This script is the engine that handles the actual
//              updating of the requested files.  it throws scp
//              commands against the shell to push the files remote
//              and then runs any commands later on if it needs to

Function Update($To_Hosts,$From_Dirs,$To_Dirs){
if(!isset($From_Dirs) || !isset($To_Dirs) || !isset($To_Hosts)){
        Colorize($cred);
        echo "\nConfiguration Incomplete or Empty.  Check your script\n";
        DeColorize();
        exit;
}

foreach ($To_Hosts as $x => $arrVal){
         echo "Updating Remote Host - "; Colorize("'\E[1;34m'"); echo $To_Hosts[$x]; Colorize("'\E[1;30m'"); echo "\n";
        foreach ($From_Dirs as $y => $arrVal2){
               $myRun =  "scp -rp " . $From_Dirs[$y] .
               " root@" . $To_Hosts[$x] . ":" . $To_Dirs[$y] . "\n";
                echo "        Updating Remote Path - " . $From_Dirs[$y] .
                "...";
                 system($myRun,$retval);
                if($retval <> 0 ){

                        Colorize("'\E[1;31m'");
                        echo "Failure";
                        Colorize("'\E[1;30m'");
                }else{
                        Colorize("'\E[1;32m'");
                        echo "Success";
                        Colorize("'\E[1;30m'");
                }
                echo "\n";

        }

}
} //End Update Function

Function Executor($commander){
        echo "               Executing Command - " . $commander . "\n";
        system($commander,$retval);
                if($retval <> 0 ){

                        Colorize("'\E[1;31m'");
                        echo "Failure";
                        Colorize("'\E[1;30m'");
                }else{
                        Colorize("'\E[1;32m'");
                        echo "Success";
                        Colorize("'\E[1;30m'");
                }
        echo "\n";
}
?>

The Colorize Funtion in the updater.php script is actually pointing to another (The second of our three) php file that handles colors.  since i wanted it to be a little pretty and have very basic knowledge of changing colors in the bash shell, i set up the colors.php file to basically handle changing colors from the standard text to a blue or red or what have you.  the code is below:

<?
//Name:         colors.php
//Author:      
//Purpose:      This file defines color constants for use in scripting.  it uses constants so you can throw down
//                   Colorize($clightblue) instead of throwing down Colorize("'\E[1;34m'");.  a little more freindly.

$cblack = "'\E[0;30m'";
$cblue = "'\E[0;34m'";
$cgreen = "'\E[0;32m'";
$ccyan = "'\E[0;36m'";
$cred = "'\E[0;31m'";
$cpurple = "'\E[0;35m'";
$cbrown = "'\E[0;33m'";
$clightgray = "'\E[0;37m'";
$cdarkgray = "'\E[1;30m'";
$clightblue = "'\E[1;34m'";
$clightgreen = "'\E[1;32m'";
$clightcyan = "'\E[1;36m'";
$clightred = "'\E[1;31m'";
$clightpurple = "'\E[1;35m'";
$cyellow = "'\E[1;33m'";
$cwhite = "'\E[1;37m'";
$nocolor = "tput sgr0";

Function Colorize($mycolor){
        Decolorize();
        system("echo -en " . $mycolor);
}

Function DeColorize(){
        system("tput sgr0");
}
?>


The final part of the script is the template part that actually tells you what folders/files to update and any commands to run after updating them.  ideally, this is the file you would name something like "update_named" and put in root so you can do ~/update_named in the CLI and have it run.    below is an example of the command to push down named but you can set up a file like this for each remote system you want to update (named,mailscanner,sendmail,etc...).  note the first line of #!/usr/bin/php -q is required so that the server knows to run this like a bash script.  you'll also need to chmod the file 755 or something so that you can actually execute it:

#!/usr/bin/php -q
<?
//Name:         update_named
//Author:      
//Purpose:      This file is for updating named.conf files on slave
//              servers.  To add more directories to push or more hosts
//              hosts to push to, just add another value to the array and
//              the count so that it would say something like $To_Host[5] = "myhostname"

//For Pushes
$From_Directory[0] = '/etc/named.conf';
$To_Directory[0] = '/etc/';
$To_Host[0] = 'dnssrv1';
$To_Host[1] = 'dnssrv2';
$To_Host[2] = 'dnssrv3';
$To_Host[3] = 'dnssrv4';


//Includes and constants
include('updater.php');
include_once('colors.php');

Colorize($clightgreen);
echo "\n                        DNS Slave Update Script v1.1\n";
echo "          Written By , Senior Network Administrator\n";
DeColorize(); Colorize($cdarkgray);
echo "\nStarting Script....Ok\nBuilding Dependencies...Ok\nLoading Config File...Ok\n";
DeColorize(); Colorize($cwhite);
echo "We are now about to begin the update process.  Please wait as
\nthis may take several minutes to complete...." ;
Colorize($cred);
echo "DO NOT" ;
Colorize($cwhite);
echo " stop the script \nin the middle of processing as it will be
restarting services\n\n";
Decolorize();
//Call Update Functions
Colorize($cdarkgray);
Update($To_Host,$From_Directory,$To_Directory);
Decolorize();
//Call Execute Functions If needed
Colorize($cdarkgray);

foreach ($To_Host as $z => $arrVal3){
        echo "Sending Remote Command to "; Colorize($clightblue); echo $arrVal3; Colorize($cdarkgray); echo "...\n";
        Executor("ssh root@" . $arrVal3 . " service named restart");

}
DeColorize();Colorize($clightblue);
echo "          =========================================\n";
echo "          ==== The remote updates are now      ====\n";
echo "          ==== Complete.  All remote hosts     ====\n";
echo "          ==== have been updated.              ====\n";
echo "          =========================================\n";
DeColorize();
?>


Since the template was the last part i did and didn't really include any running code in it, i spent alot more time building out the look and feel of the script, which is why it's got so much echo statements in it.  i made it seem like it was more hardcore then it was purely for athestics.

The biggest bug i'm aware of in this is that the variables in the colors.php include file arn't global (i'm assuming thats what the problem is) so when you try to do a colorize command from the updater.php file it wont pick up the $clightblue variable (For example) and you have to do the actual \E color code.  i'll probably fix that someday in my own script or your free to do it in this one. the code isn't pretty but it works so i figure if anyone wants to use it and not have to spend the hours i spent on doing something like this, there ya go.  if nothing else, at least i'll be able to go back here and look the script up again if i ever loose it.

Oh, also, it will prompt you for a password to all of the remote servers you connect to in the script unless you set up a public/private key between the servers in question.  If you dont, it will prompt you at every update or command for a password and the script starts to look really ugly.  if you do a search on the experts-exchange site you'll find quite a few posts on how to do this (The one i used was from jlevie and worked like a charm) and once i set it up on the servers, the script works without me having to do anything other then call it when i wanted an update (i guess i could crontab it out but i'm preferring the manual control right now).

thanks again for your help everyone.  if i could give more then 500 points to you guys i would.  being new to the linux world would be insanely more difficult if i didn't have this community to rely on to answer my very stupid questions.
decoleurCommented:
I like your solution and I am hope that others will benifit from your contribution.

Cheers!

-t
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Linux Networking

From novice to tech pro — start learning today.