#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------
package xCAT_plugin::AAsn;
use strict;
use xCAT::Table;

use xCAT::Utils;
use xCAT::TableUtils;
use xCAT::NetworkUtils;

use xCAT::MsgUtils;
use xCAT_plugin::dhcp;
use xCAT_plugin::conserver;
use File::Path;
use Getopt::Long;

#-------------------------------------------------------

=head1  AAsn

 This is the Service Node Plugin, although it does perform a few functions on
 the Management Node.   
 It reads the servicenode table for the service node it is running on,
 and run the appropriate
 setup routine for each service that is designated to be setup in the 
 servicenode table for this service node. Some functions are only done for 
 Linux.
 A few functions are done not based on the servicenode table. For example:

  on a Linux Service Node
      if site.installloc set
          mounts /install
      if site.installloc not set
          creates /install if needed
          sets up nfs
          exports /install 

#-------------------------------------------------------

=head3  handled_commands

If bypassmode then exit
If xcat daemon reload then exit

Check to see if on a Service Node
If Linux
   Call  setupInstallloc
If this is a service Node
  Read Service Node Table
   For each service returned to be setup
	  Call the appropriate setup_service routine
else if on the Management Node
  Do any Management Node setup of services needed

=cut

#-------------------------------------------------------

sub handled_commands { return; }

sub init_plugin
{
    my $doreq = shift;

    # If called in XCATBYPASS mode, don't do any setup
    if ($ENV{'XCATBYPASS'})
    {
        return 0;
    }

    # If a xcat daemon reload, don't do any setup
    if ($ENV{'XCATRELOAD'})
    {
        return 0;
    }

    my $rc = 0;

    if ((xCAT::Utils->isServiceNode()) && ( -s "/etc/xcat/cfgloc"))
    {
        my @nodeinfo   = xCAT::NetworkUtils->determinehostname;
        my $nodename   = pop @nodeinfo;                    # get hostname
        my @nodeipaddr = @nodeinfo;                        # get ip addresses
        my $service;

        if (xCAT::Utils->isLinux())
        {

            # service needed on Linux Service Node
            $service = "setupInstallloc";
            $rc      = &setupInstallloc($nodename);
            if ($rc == 0)
            {
                xCAT::Utils->update_xCATSN($service);
            }
            $service = "ssh";

            $rc = &setup_SSH();    # setup SSH
            if ($rc == 0)
            {
                xCAT::Utils->update_xCATSN($service);
            }

        }

        # read the service node table
        # for a list of all functions to setup for this service node
        #
        my @servicelist = xCAT::ServiceNodeUtils->isServiceReq($nodename, \@nodeipaddr);
        my $service;
        if ($::RUNCMD_RC == 0)
        {
            if (xCAT::Utils->isLinux())
            {    #run only the following only on Linux


                $service = "ftpserver";
                if (grep(/$service/, @servicelist))
                {

                    # make sure ftpserver not tftpserver
                    my $match = 0;
                    foreach my $service (@servicelist)
                    {
                        if ($service eq "ftpserver")
                        {
                            $match = 1;
                        }
                    }
                    if ($match == 1)
                    {    # it was ftpserver
                        $rc = &setup_FTP();    # setup vsftpd
                        if ($rc == 0)
                        {
                            xCAT::Utils->update_xCATSN($service);
                        }
                    }

                }

                $service = "ldapserver";
                if (grep(/$service/, @servicelist))
                {

                    $rc = &setup_LDAP();    # setup LDAP
                    if ($rc == 0)
                    {
                        xCAT::Utils->update_xCATSN($service);
                    }

                }

                $service = "tftpserver";
                if (grep(/$service/, @servicelist))
                {

                    $rc = &setup_TFTP($nodename, $doreq);    # setup TFTP
                    if ($rc == 0)
                    {
                        xCAT::Utils->update_xCATSN($service);
                    }

                }

            }    # end Linux only
            #
            # setup these services for AIX or Linux
            #
            $service = "conserver";
            if (grep(/$service/, @servicelist))
            {
                if (xCAT::Utils->isLinux())
                {    #run only the following only on Linux

                    $rc = &setup_CONS($nodename);    # setup conserver
                    if ($rc == 0)
                    {
                        xCAT::Utils->update_xCATSN($service);
                    }
                } else { #AIX
                   $rc = xCAT::Utils->setupAIXconserver();
            
                }
            }
            $service = "nameserver";
            if (grep(/$service/, @servicelist))
            {

                $rc = &setup_DNS();    # setup DNS
                if ($rc == 0)
                {
                    xCAT::Utils->update_xCATSN($service);
                }

            }
            $service = "nfsserver";
            if (grep(/$service/, @servicelist))
            {

                $rc = &setup_NFS($nodename);    # setup NFS
                if ($rc == 0)
                {
                    xCAT::Utils->update_xCATSN($service);
                }

                # The nfsserver field in servicenode table
                # will also setup http service for Linux
                if (xCAT::Utils->isLinux())
                {
                    $rc = &setup_HTTP($nodename);    # setup HTTP
                    if ($rc == 0)
                    {
                        xCAT::Utils->update_xCATSN('http');
                    }
                }

            }
	    my $service = "ipforward";
  	    if (grep(/$service/, @servicelist))
	    {
	    
	      $rc =  xCAT::NetworkUtils->setup_ip_forwarding(1);    # enable ip forwarding
	      if ($rc == 0)
	      {
	    	xCAT::Utils->update_xCATSN($service);
	      }
	    }

            #
            # setup dhcp only on Linux and last
            #
            if (xCAT::Utils->isLinux())
            {
                my $service = "dhcpserver";
                if (grep(/$service/, @servicelist))
                {

                    $rc = &setup_DHCP($nodename);    # setup DHCP
                    if ($rc == 0)
                    {
                        xCAT::Utils->update_xCATSN($service);
                    }

                }
            }

            # done now in setupntp postinstall script, but may change
            #$service = "ntpserver";
            #if (grep(/$service/, @servicelist))
            #{

            # $rc = &setup_NTPsn($nodename);    # setup NTP on SN
            # if ($rc == 0)
            # {
            #     xCAT::Utils->update_xCATSN($service);
            # }

            #}
        }
        else
        {    # error from servicenode tbl read
            xCAT::MsgUtils->message("S",
                                "AAsn.pm:Error reading the servicenode table.");
        }

    }
    else     # management node
    {

        # $rc = &setup_NTPmn();  # setup NTP on the Management Node
        if (xCAT::Utils->isLinux())
        {
            my @tmp = xCAT::TableUtils->get_site_attribute("vsftp");   
		    if ($tmp[0] && ($tmp[0] !~ /0|NO|No|no|N|n/ )) {         
                print "\n";    # make OK prints look better.  Only need to do this for the 1st service.
                $rc = &setup_FTP();    # setup FTP
            }
            #enable the tftp-hpa for MN
            $rc = enable_TFTPhpa();
        }
    }
    return $rc;
}

#-------------------------------------------------------

=head3  process_request

  Process the command

=cut

#-------------------------------------------------------
sub process_request
{
    return;
}

#-----------------------------------------------------------------------------

=head3 setupInstallloc

    if site.installloc attribute set
          If the installdir directory is exported, unexport it
	      mount the installdir directory from the installloc location
    if site.installoc not set and we are on a Stateful install 
          If installdir mounted, unmount it 
          If installdir directory not created,  create it
          setup NFS
          export the installdir directory
          

=cut

#-----------------------------------------------------------------------------
sub setupInstallloc
{
    my ($nodename) = @_;
    my $rc         = 0;
    my $installdir = xCAT::TableUtils->getInstallDir();
    my $installloc;
    my $newinstallloc;

    # read DB for nodeinfo
    my $master;
    my $os;
    my $arch;
    my $nomount = 0;

    my $retdata = xCAT::ServiceNodeUtils->readSNInfo($nodename);
    if (ref $retdata and $retdata->{'arch'})
    {    # no error
        $master = $retdata->{'master'};    # management node
        $os     = $retdata->{'os'};
        $arch   = $retdata->{'arch'};

        # read install directory and install location from database,
        # if they exists
        my @installlocation = xCAT::TableUtils->get_site_attribute("installloc");
        my $hostname;
        my $path;
        if ($installlocation[0])
        {
            if (grep /:/, $installlocation[0])
            {
                my ($hostname, $newinstallloc) = split ":", $installlocation[0];
                if ($hostname)
                {    # hostname set in /installloc attribute
                    $master     = $hostname;         # set name for mount
                    $installloc = $newinstallloc;    #set path for mount point
                }
            }
            else
            {
                $installloc = $installlocation[0];
            }
        }
        else
        {    # if no installloc attribute then we do not mount
            $nomount = 1;
        }

        if ($nomount == 0)    # we do have installloc attribute
        {

            # mount the install directory from the installloc location
            # make the directory to mount on
            if (!(-e $installdir))
            {
                mkpath($installdir);
            }

            # check if exported, and unexport it
            my $cmd = "/bin/cat /etc/exports | grep '$installdir'";
            my $outref = xCAT::Utils->runcmd("$cmd", -1);
            if ($::RUNCMD_RC == 0)    # it is exported
            {

                # remove from /etc/exports
                my $sedcmd = "sed \\";
                $sedcmd .= "$installdir/d  /etc/exports > /etc/exports.tmp";
                system $sedcmd;
                if ($? > 0)
                {                     # error
                    xCAT::MsgUtils->message("S", "Error $cmd");
                }
                else
                {
                    $cmd = "cp /etc/exports.tmp /etc/exports";
                    system $cmd;
                    if ($? > 0)
                    {                 # error
                        xCAT::MsgUtils->message("S", "Error $cmd");
                    }
                }

                # restart nfs
                &setup_NFS($nodename);

                $cmd = " exportfs -a";
                system $cmd;
                if ($? > 0)
                {                     # error
                    $rc = 1;
                    xCAT::MsgUtils->message("S", "Error $cmd");
                }

            }

            # check to see if install  already mounted

            my $mounted = xCAT::Utils->isMounted($installdir);
            if ($mounted == 0)
            {                         # not mounted

                # need to  mount the directory
                my $cmd;
                my @nfsv4 = xCAT::TableUtils->get_site_attribute("useNFSv4onAIX");
                if ($nfsv4[0] && ($nfsv4[0] =~ /1|Yes|yes|YES|Y|y/))
                {
                    $cmd = "mount -o vers=4,rw,nolock $master:$installloc $installdir";
                }
                else
                {
                   $cmd = "mount -o rw,nolock $master:$installloc $installdir";
                }
                system $cmd;
                if ($? > 0)
                {                     # error
                    $rc = 1;
                    xCAT::MsgUtils->message("S", "Error $cmd");
                }
            }
        }

        else
        {

            # installloc not set so we will export /install on the SN, if Stateful
            if (xCAT::Utils->isStateful())
            {

                # no installloc attribute, create and export installdir
                # check to see if installdir is mounted
                my $mounted = xCAT::Utils->isMounted($installdir);
                if ($mounted == 1)
                {

                    # need to  unmount the directory
                    my $cmd = "umount $installdir";
                    system $cmd;
                    if ($? > 0)
                    {    # error
                        $rc = 1;
                        xCAT::MsgUtils->message("S", "Error $cmd");
                    }

                }

                # if it does not exist,need to make the installdir directory
                if (!(-e $installdir))
                {
                    mkpath($installdir);
                }

                # export the installdir
                #
                #  add /install to /etc/exports - if needed
                #

                my $cmd = "/bin/cat /etc/exports | grep '$installdir'";
                my $outref = xCAT::Utils->runcmd("$cmd", -1);
                my $changed_exports;
                if ($::RUNCMD_RC != 0)
                {

                    # ok - then add this entry
                    my $cmd =
                      "/bin/echo '$installdir *(rw,no_root_squash,sync,no_subtree_check)' >> /etc/exports";
                    my $outref = xCAT::Utils->runcmd("$cmd", 0);
                    if ($::RUNCMD_RC != 0)
                    {
                        xCAT::MsgUtils->message('S',
                                     "Could not update the /etc/exports file.");
                    }
                    else
                    {
                        $changed_exports++;
                    }
                }

                if ($changed_exports)
                {

                    # restart nfs
                    &setup_NFS($nodename);

                    my $cmd = "/usr/sbin/exportfs -a";
                    my $outref = xCAT::Utils->runcmd("$cmd", 0);
                    if ($::RUNCMD_RC != 0)
                    {
                        xCAT::MsgUtils->message('S', "Error with $cmd.");
                    }

                }
            }
        }
    }
    else
    {    # error reading Db
        $rc = 1;
    }
    if ($rc == 0)
    {

        # update fstab
        my $cmd = "grep $master:$installloc $installdir  /etc/fstab  ";
        xCAT::Utils->runcmd($cmd, -1);
        if ($::RUNCMD_RC != 0)
        {
            if ($nomount == 0)    # then add the entry
            {
                `echo "$master:$installloc $installdir nfs timeo=14,intr 1 2" >>/etc/fstab`;

            }
        }
        else
        {                         # fstab entry there

            if ($nomount == 1)
            {

                # then remove the entry
                my $sedcmd = "sed \\";
                $sedcmd .= "$installdir/d  /etc/fstab > /etc/fstab.tmp";
                system $sedcmd;
                if ($? > 0)
                {                 # error
                    xCAT::MsgUtils->message("S", "Error $cmd");
                }
                else
                {
                    $cmd = "cp /etc/fstab.tmp /etc/fstab";
                    system $cmd;
                    if ($? > 0)
                    {             # error
                        xCAT::MsgUtils->message("S", "Error $cmd");
                    }
                }

            }
        }
    }
    return $rc;
}


#-----------------------------------------------------------------------------

=head3 setup_CONS

    Sets up Conserver

=cut

#-----------------------------------------------------------------------------
sub setup_CONS
{
    my ($nodename) = @_;
    my $rc = 0;

    # read DB for nodeinfo
    my $master;
    my $os;
    my $arch;
    my $cmd;
    my $retdata = xCAT::ServiceNodeUtils->readSNInfo($nodename);
    if ($retdata->{'arch'})
    {    # no error
        $master = $retdata->{'master'};
        $os     = $retdata->{'os'};
        $arch   = $retdata->{'arch'};

        # make the consever 8 configuration file
        my $cmdref;
        $cmdref->{command}->[0] = "makeconservercf";
        $cmdref->{arg}->[0]     = "-l";
        $cmdref->{cwd}->[0]     = "/opt/xcat/sbin";
        $cmdref->{svboot}->[0]  = "yes";
        no strict "refs";
        my $modname = "conserver";
        ${"xCAT_plugin::" . $modname . "::"}{process_request}
          ->($cmdref, \&xCAT::Client::handle_response);

        # start conserver. conserver needs 2 CA files to start
        my $ca_file1 = "/etc/xcat/ca/ca-cert.pem";
        my $ca_file2 = "/etc/xcat/cert/server-cred.pem";
        if (!-e $ca_file1)
        {
            print
              "conserver cannot be started because the file $ca_file1 cannot be found\n";
        }
        elsif (!-e $ca_file2)
        {
            print
              "conserver cannot be started because the file $ca_file2 cannot be found\n";
        }
        else
        {
            my $rc = xCAT::Utils->startService("conserver");
            if ($rc != 0)
            {
                return 1;
            }
        }
    }
    else
    {    # error reading Db
        $rc = 1;
    }
    return $rc;
}

#-----------------------------------------------------------------------------

=head3 setup_DHCP 

    Sets up DHCP services  

=cut

#-----------------------------------------------------------------------------
sub setup_DHCP
{
    my ($nodename) = @_;
    my $rc = 0;
    my $cmd;
    my $snonly = 0;
    # read the disjointdhcps attribute to determine if we will setup
    # dhcp for all nodes or just for the nodes service by this service node
    #my $sitetab = xCAT::Table->new('site');
    #if ($sitetab)
    #{
    #    my $href;
    #    ($href) = $sitetab->getAttribs({key => 'disjointdhcps'}, 'value');
    #    if ($href and $href->{value}) {
    #        $snonly=$href->{value};
    #    }
    #}
    my @hs = xCAT::TableUtils->get_site_attribute("disjointdhcps");
    my $tmp = $hs[0];
    if(defined($tmp)) {
        $snonly = $tmp;
    }

    # run makedhcp
    my $XCATROOT = "/opt/xcat";    # default

    if ($ENV{'XCATROOT'})
    {
        $XCATROOT = $ENV{'XCATROOT'};
    }
    my $cmdref;
    $cmdref->{command}->[0] = "makedhcp";
    $cmdref->{arg}->[0]     = "-n";
    $cmdref->{cwd}->[0]     = "/opt/xcat/sbin";
    no strict "refs";
    my $modname = "dhcp";
    ${"xCAT_plugin::" . $modname . "::"}{process_request}
      ->($cmdref, \&xCAT::Client::handle_response);

    my $distro = xCAT::Utils->osver();
    my $serv = "dhcpd";
    if ( $distro =~ /ubuntu.*/ ){
        $serv = "dhcp3-server";	
    }

    my $rc = xCAT::Utils->startService($serv);
    if ($rc != 0)
    {
        return 1;
    }
    
    # setup DHCP 
    # 
    my $modname = "dhcp";
    if ($snonly != 1)  {  # setup  dhcp for all nodes
      $cmdref;
      $cmdref->{command}->[0] = "makedhcp";
      $cmdref->{arg}->[0]     = "-a";
      $cmdref->{cwd}->[0]     = "/opt/xcat/sbin";

   } else {  # setup dhcp just for the nodes owned by the SN
     # determine my name
     # get servicenodes and their nodes
     # find the list of nodes serviced
     my @hostinfo=xCAT::NetworkUtils->determinehostname();
     my $sn_hash =xCAT::ServiceNodeUtils->getSNandNodes();
     my @nodes;
     my %iphash=();
     my $snkey;
     $cmdref;
     foreach  $snkey (keys %$sn_hash) {  # find the service node
        if (grep(/$snkey/, @hostinfo)) {
            push @nodes, @{$sn_hash->{$snkey}};
            $cmdref->{node} = $sn_hash->{$snkey};
            $cmdref->{'_xcatdest'}            = $snkey;
        }
     }
     if (@nodes) {
       my $nodelist;
       foreach my $n (@nodes) { 
        $nodelist .= $n;
        $nodelist .= ",";
       }
       chop $nodelist;
       $cmdref->{arg}->[0] = ();
       $cmdref->{command}->[0] = "makedhcp";
       $cmdref->{noderange}->[0]     = "$nodelist";
       $cmdref->{cwd}->[0]     = "/opt/xcat/sbin";
    }
   }
   ${"xCAT_plugin::" . $modname . "::"}{process_request}
        ->($cmdref, \&xCAT::Client::handle_response);
    return $rc;
}

#-----------------------------------------------------------------------------

=head3 setup_FTP

    Sets up FTP services (vsftp)

=cut

#-----------------------------------------------------------------------------
sub setup_FTP
{
    my $rc = 0;
    my $cmd;
    my $XCATROOT = "/opt/xcat";    # default

    if ($ENV{'XCATROOT'})
    {
        $XCATROOT = $ENV{'XCATROOT'};
    }

    # change ftp user id home directory to installdir
    # link installdir
    # restart the daemon
    my $installdir = xCAT::TableUtils->getInstallDir();
    if (!(-e $installdir))         # make it
    {
        mkpath($installdir);
    }
    $cmd = "usermod -d $installdir ftp 2>&1";
    my $outref = xCAT::Utils->runcmd($cmd, 0);
    if ($::RUNCMD_RC)
    {

        xCAT::MsgUtils->message("S", "Error from command:$cmd");
    }

    # start ftp

    my $rc = xCAT::Utils->startService("vsftpd");
    if ($rc != 0)
    {
        return 1;
    }

    return $rc;
}

#-----------------------------------------------------------------------------

=head3 setup_DNS

    Sets up Domain Name service
	http://www.adminschoice.com/docs/domain_name_service.htm#Introduction

=cut

#-----------------------------------------------------------------------------
sub setup_DNS
{

    my $XCATROOT = "/opt/xcat";    # default

    if ($ENV{'XCATROOT'})
    {
        $XCATROOT = $ENV{'XCATROOT'};
    }

    # setup the named.conf file
    system("$XCATROOT/sbin/makenamed.conf");

    # turn DNS on

    my $distro = xCAT::Utils->osver();
    my $serv = "named";
    if ( $distro =~ /ubuntu.*/ ){
        $serv = "bind9";
    }

    my $rc = xCAT::Utils->startService($serv);
    if ($rc != 0)
    {
        return 1;
    }

    # start named on boot
    if (xCAT::Utils->isAIX())
    {
        #/etc/inittab
        my $cmd = "/usr/sbin/lsitab named > /dev/null 2>&1";
        my $rc = system("$cmd") >>8;
        if ($rc != 0)
        {
            #add new entry
            my $mkcmd = qq~/usr/sbin/mkitab "named:2:once:/usr/sbin/named > /dev/console 2>&1"~;
            system("$mkcmd");
            xCAT::MsgUtils->message("SI", " named has been enabled on boot.");
        }
    }
    else
    {
        #chkconfig
        my $cmd = "/sbin/chkconfig $serv on";
        my $outref = xCAT::Utils->runcmd("$cmd", 0);
        if ($::RUNCMD_RC != 0)
        {
            xCAT::MsgUtils->message("SE", " Error: Could not enable $serv.");
        }
        else
        {
            xCAT::MsgUtils->message("SI", " $serv has been enabled on boot.");
        }
    }
    
    return 0;
}

#-----------------------------------------------------------------------------

=head3 setup_LDAP 

    Sets up LDAP  

=cut

#-----------------------------------------------------------------------------
sub setup_LDAP
{

    my $rc = xCAT::Utils->startService("ldap");
    if ($rc != 0)
    {
        return 1;
    }

    return 0;
}

#-----------------------------------------------------------------------------

=head3 setup_NFS 

    Sets up NFS services on Service Node for AIX and Linux   

=cut

#-----------------------------------------------------------------------------
sub setup_NFS
{
    my ($nodename) = @_;
    my $rc = 0;

    # make sure nfs is restarted
    my $rc = 0;
    if (xCAT::Utils->isLinux())
    {
        my $os = xCAT::Utils->osver();
        if ($os =~ /sles.*/)
        {
            $rc = xCAT::Utils->startService("nfs");
            $rc = xCAT::Utils->startService("nfsserver");
        }
        else
        {
            $rc = xCAT::Utils->startService("nfs");
        }
    }
    else
    {    #AIX
        $rc = xCAT::Utils->startService("nfsd");
    }
    if ($rc != 0)
    {
        return 1;
    }

    return $rc;
}

#-----------------------------------------------------------------------------

=head3 setup_NTPsn 

    Sets up NTP services on service node

=cut

#-----------------------------------------------------------------------------
sub setup_NTPsn
{
    my ($nodename) = @_;
    my $rc = 0;
    my $cmd;
    my $master;
    my $os;
    my $arch;
    my $ntpcfg = "/etc/ntp.conf";

    # read DB for nodeinfo
    my $retdata = xCAT::ServiceNodeUtils->readSNInfo($nodename);
    $master = $retdata->{'master'};
    $os     = $retdata->{'os'};
    $arch   = $retdata->{'arch'};
    if (!($arch))
    {    # error
        xCAT::MsgUtils->message("S", " Error reading service node info.");
        return 1;
    }

    # backup the existing config file
    $rc = &backup_NTPconf();
    if ($rc == 0)
    {

        # create config file
        open(CFGFILE, ">$ntpcfg")
          or xCAT::MsgUtils->message('SE',
                                     "Cannot open $ntpcfg for NTP update. \n");
        print CFGFILE "server ";
        print CFGFILE $master;
        print CFGFILE "\n";
        print CFGFILE "driftfile /var/lib/ntp/drift\n";
        print CFGFILE "restrict 127.0.0.1\n";
        close CFGFILE;

        $rc = &start_NTP();    # restart ntp
    }
    return $rc;
}

#-----------------------------------------------------------------------------

=head3 setup_NTPmn 

    Sets up NTP services on Management Node 
    Get ntpservers from site table.  If they do not exist, warn cannot setup NTP
=cut

#-----------------------------------------------------------------------------
sub setup_NTPmn
{
    my $rc     = 0;
    my $ntpcfg = "/etc/ntp.conf";

    # get timeservers from site table
    my @ntpservers = xCAT::TableUtils->get_site_attribute("ntpservers");
    if ($ntpservers[0])
    {

        # backup the existing config file
        $rc = &backup_NTPconf();
        if ($rc == 0)
        {

            # add server names
            open(CFGFILE, ">$ntpcfg")
              or xCAT::MsgUtils->message('SE',
                                      "Cannot open $ntpcfg for NTP update. \n");
            my @servers = split ',', $ntpservers[0];
            foreach my $addr (@servers)
            {
                print CFGFILE "server ";
                print CFGFILE $addr;
                print CFGFILE "\n";
            }
            print CFGFILE "driftfile /var/lib/ntp/drift\n";
            print CFGFILE "restrict 127.0.0.1\n";
            close CFGFILE;

            $rc = &start_NTP();    # restart ntp
        }
    }
    else
    {                              # no servers defined
        xCAT::MsgUtils->message(
            "S",
            "No NTP servers defined in the ntpservers attribute in the site table.\n"
            );
        return 1;
    }
    return $rc;
}

#-----------------------------------------------------------------------------

=head3 start_NTP 

    Starts daemon 

=cut

#-----------------------------------------------------------------------------
sub start_NTP
{

    my $rc = xCAT::Utils->startService("ntpd");
    if ($rc != 0)
    {
        return 1;
    }

    return 0;
}

#-----------------------------------------------------------------------------

=head3 backup_NTPconf 

   backup configuration 

=cut

#-----------------------------------------------------------------------------
sub backup_NTPconf
{
    my $ntpcfg           = "/etc/ntp.conf";
    my $ntpcfgbackup     = "/etc/ntp.conf.orig";
    my $ntpxcatcfgbackup = "/etc/ntp.conf.xcatbackup";
    if (!-e $ntpcfgbackup)
    {    # if original backup does not already exist
        my $cmd = "mv $ntpcfg $ntpcfgbackup";
        system $cmd;
        if ($? > 0)
        {
            xCAT::MsgUtils->message("S", "Error from command:$cmd");
            return 1;
        }
    }
    else
    {    # backup xcat cfg
        my $cmd = "mv $ntpcfg $ntpxcatcfgbackup";
        system $cmd;
        if ($? > 0)
        {
            xCAT::MsgUtils->message("S", "Error from command:$cmd");
            return 1;
        }
    }
    return 0;
}

#-----------------------------------------------------------------------------

=head3 setup_SSH 

    Sets up SSH default configuration for root  
	Turns strict host checking off


=cut

#-----------------------------------------------------------------------------
sub setup_SSH
{

    my $configfile;
    my $cmd;
    my $configinfo;
    my $sshdir;
    my $cmd;

    # build the $HOMEROOT/.ssh/config
    if (xCAT::Utils->isLinux())
    {
        $configfile = "/root/.ssh/config";
        $sshdir     = "/root/.ssh";
    }
    else
    {    #AIX
        $configfile = "/.ssh/config";
        $sshdir     = "/.ssh";
    }
    if (!(-e $sshdir))
    {    # directory does not exits
        mkdir($sshdir, 0700);
    }
    $configinfo = "StrictHostKeyChecking no";

    if (-e $configfile)
    {
        $cmd = "grep StrictHostKeyChecking $configfile";
        xCAT::Utils->runcmd($cmd, -1);
        if ($::RUNCMD_RC != 0)
        {    # not there
            $cmd = "echo  $configinfo >> $configfile";
            my @output = xCAT::Utils->runcmd($cmd, 0);
            if ($::RUNCMD_RC != 0)
            {    # error
                xCAT::MsgUtils->message("S", "Error on $cmd, @output");
                return 1;
            }

        }
    }
    else         # file does not exist
    {
        $cmd = "echo  $configinfo >> $configfile";
        my @output = xCAT::Utils->runcmd($cmd, 0);
        if ($::RUNCMD_RC != 0)
        {        # error
            xCAT::MsgUtils->message("S", "Error on $cmd, @output");
            return 1;
        }
        else
        {
            chmod 0600, $configfile;

        }
    }

    return 0;
}

#-----------------------------------------------------------------------------

=head3 setup_TFTP 

    Sets up TFTP services (using atftp) 

=cut

#-----------------------------------------------------------------------------
sub setup_TFTP
{
    my ($nodename, $doreq) = @_;

    my $rc = 0;
    my $cmd;
    my $master;
    my $os;
    my $arch;
    my $XCATROOT = "/opt/xcat";    # default

    if ($ENV{'XCATROOT'})
    {
        $XCATROOT = $ENV{'XCATROOT'};
    }

    # read DB for nodeinfo
    my $retdata = xCAT::ServiceNodeUtils->readSNInfo($nodename);
    $master = $retdata->{'master'};
    $os     = $retdata->{'os'};
    $arch   = $retdata->{'arch'};
    if (!($arch))
    {    # error
        xCAT::MsgUtils->message("S", " Error reading service node arch.");
        return 1;
    }

    # check to see if tftp is installed
    $cmd = "/usr/sbin/in.tftpd -V";
    my @output = xCAT::Utils->runcmd($cmd, -1);
    if ($::RUNCMD_RC != 0)
    {    # not installed
        xCAT::MsgUtils->message("S", "atftp is not installed, ok for Power5");
    }
    my $tftpdir;
    my $mountdirectory = "1";        # default to mount tftpdir
    my $tftphost       = $master;    # default to master
         # read sharedtftp attribute from site table, if exist
    #my $stab = xCAT::Table->new('site');
    #my $sharedtftp = $stab->getAttribs({key => 'sharedtftp'}, 'value');
    my @ss = xCAT::TableUtils->get_site_attribute("sharedtftp");
    my $sharedtftp = $ss[0];
    if ( defined($sharedtftp) )
    {

        $tftphost       = $sharedtftp;    # either hostname or yes/no
        $mountdirectory = $tftphost;
        $mountdirectory =~ tr/a-z/A-Z/;            # convert to upper
        if (   $mountdirectory ne "1"
            && $mountdirectory ne "YES"
            && $mountdirectory ne "0"
            && $mountdirectory ne "NO")
        {                                          # then tftphost is hostname
                                                   # for the mount
            $mountdirectory = "1";                 # and we mount the directory
        }
        else
        {
            $tftphost = $master;                   # will mount master,if req
        }

    }
    #$stab->close;

    # read tftpdir directory from database
    $tftpdir = xCAT::TableUtils->getTftpDir();
    if (!(-e $tftpdir))
    {
        mkdir($tftpdir);
    }

    # if request to mount
    if ($mountdirectory eq "1" || $mountdirectory eq "YES")
    {

        # check to see if tftp directory already mounted
        my $mounted = xCAT::Utils->isMounted($tftpdir);
        if ($mounted == 0)    # not already mounted
        {

            # need to  mount the directory
            my $cmd;
            my @nfsv4 = xCAT::TableUtils->get_site_attribute("useNFSv4onAIX");
            if ($nfsv4[0] && ($nfsv4[0] =~ /1|Yes|yes|YES|Y|y/))
            {
                $cmd = " mount -o vers=4,rw,nolock $tftphost:$tftpdir $tftpdir";
            }
            else
            {
                $cmd = " mount -o rw,nolock $tftphost:$tftpdir $tftpdir";
            }
            system $cmd;
            if ($? > 0)
            {                 # error
                $rc = 1;
                xCAT::MsgUtils->message("S", "Error $cmd");
            }
        }
    }
    else
    {                         #if not mounting, have to regenerate....
                              #first, run mknb to get nbfs and such going?
        my $cmdref;
        use xCAT_plugin::mknb;
        for my $architecture ("ppc64", "x86", "x86_64")
        {
            unless (-d "$::XCATROOT/share/xcat/netboot/$architecture")
            {
                next;
            }
            $cmdref->{command}->[0] = "mknb";
            $cmdref->{arg}->[0]     = $architecture;
            $doreq->($cmdref, \&xCAT::Client::handle_response);
        }

        #now, run nodeset enact on
        my $mactab = xCAT::Table->new('mac');
        my $hmtab  = xCAT::Table->new('noderes');
        if ($mactab and $hmtab)
        {
            my @mentries = ($mactab->getAllNodeAttribs([qw(node mac)]));

            #nodeset fails if no mac entry, filter on discovered nodes first
            my %netmethods;
            my @tnodes;
            foreach (@mentries)
            {
                unless (defined $_->{mac}) { next; }
                push @tnodes, $_->{node};
            }
            my %hmhash =
              %{$hmtab->getNodesAttribs(\@tnodes, [qw(node netboot)])};
            foreach (@tnodes)
            {
                if ($hmhash{$_}->[0]->{netboot})
                {
                    push @{$netmethods{$hmhash{$_}->[0]->{netboot}}}, $_;
                }
            }
            $cmdref->{command}->[0]  = "nodeset";
            $cmdref->{inittime}->[0] = "1";
            $cmdref->{arg}->[0]      = "enact";
            $cmdref->{cwd}->[0]      = "/opt/xcat/sbin";
            my $plugins_dir = $::XCATROOT . '/lib/perl/xCAT_plugin';
            foreach my $modname (keys %netmethods)
            {
                $cmdref->{node} = $netmethods{$modname};
                $doreq->($cmdref, \&xCAT::Client::handle_response);
            }

        }
    }

    # enable the tftp-hpa
    $rc = enable_TFTPhpa();

    if ($rc == 0)
    {

        if ($mountdirectory eq "1" || $mountdirectory eq "YES")
        {

            # update fstab so that it will restart on reboot
            $cmd =
              "fgrep \"$tftphost:$tftpdir $tftpdir nfs timeo=14,intr 1 2\" /etc/fstab";
            xCAT::Utils->runcmd($cmd, -1);
            if ($::RUNCMD_RC != 0)    # not already there
            {

                `echo "$tftphost:$tftpdir $tftpdir nfs timeo=14,intr 1 2" >>/etc/fstab`;
            }
        }
    }

    return $rc;

}

#-----------------------------------------------------------------------------

=head3 setup_HTTP

    Sets up HTTP services on Service Node for Linux   

=cut

#-----------------------------------------------------------------------------
sub setup_HTTP
{
    my ($nodename) = @_;
    my $rc = 0;

    if (xCAT::Utils->isLinux())
    {
        my $os = xCAT::Utils->osver();
        if ($os =~ /sles.*/)
        {
            $rc = xCAT::Utils->startService("apache2");
        }
        else
        {
            $rc = xCAT::Utils->startService("httpd");
        }
    }
    return $rc;
}

#-----------------------------------------------------------------------------
#
#=head3 enable_TFTPhpa
#
#    Configure and enable the tftp-hpa in the xinetd.
#
#=cut
#
#-----------------------------------------------------------------------------
sub enable_TFTPhpa
{
  # Check whether the tftp-hpa has been installed, the ubuntu tftpd-hpa configure file is under /etc/default
  unless (-x "/usr/sbin/in.tftpd" and ( -e "/etc/xinetd.d/tftp" or -e "/etc/default/tftpd-hpa" )) {
    xCAT::MsgUtils->message("S", "ERROR: The tftpd was not installed, enable the tftp failed.");
    return 1;
  }

  # kill the process of atftp if it's there
  my @output = xCAT::Utils->runcmd("ps -ef | grep atftpd | grep -v grep", -1);
  foreach my $ps (@output) {
    $ps =~ s/^\s+//;    # strip any leading spaces
    my ($uid, $pid, $ppid, $desc) = split /\s+/, $ps;
    system("kill -9 $pid >/dev/null 2>&1");
  }

  # read tftpdir directory from database
  my $tftpdir = xCAT::TableUtils->getTftpDir();
  if (!(-e $tftpdir)) {
    mkdir($tftpdir);
  }

  # The location of tftp mapfile
  my $mapfile = "/etc/tftpmapfile4xcat.conf";
  if (! -e "$mapfile") {
    if (! open (MAPFILE, ">$mapfile")) {
      xCAT::MsgUtils->message("S", "ERROR: Cannot open $mapfile.");
      return 1;
    }
    # replace the \ with /
    print MAPFILE 'rg (\\\) \/';
    close (MAPFILE);
  }

  my $distro = xCAT::Utils->osver();
  if ($distro !~ /ubuntu.*/i){
    if (! open (FILE, "</etc/xinetd.d/tftp")) {
      xCAT::MsgUtils->message("S", "ERROR: Cannot open /etc/xinetd.d/tftp.");
      return 1;
    }

    # The location of tftp mapfile
    my $mapfile = "/etc/tftpmapfile4xcat.conf";
    my $recfg = 0;
    my @newcfgfile;
    # Check whether need to reconfigure the /etc/xinetd.d/tftp
    while (<FILE>) {
      # check the configuration of 'server_args = -s /xx -m xx'  entry
      if (/^\s*server_args\s*=(.*)$/) {
        my $cfg_args = $1;
        # handle the -s option for the location of tftp root dir
        if ($cfg_args =~ /-s\s+([^\s]*)/) {
          my $cfgdir = $1;
          $cfgdir =~ s/\$//;
          $tftpdir =~ s/\$//;
          # make sure the tftp dir should comes from the site.tftpdir
          if ($cfgdir ne $tftpdir) {
            $recfg = 1;
          }
        }
        # handle the -m option for the mapfile
        if ($cfg_args !~ /-m\s+([^\s]*)/) {
          $recfg = 1;
        }
        if ($recfg) {
          # regenerate the entry for server_args
          my $newcfg = $_;
          $newcfg =~ s/=.*$/= -s $tftpdir -m $mapfile/;
          push @newcfgfile, $newcfg;
        } else {
          push @newcfgfile, $_;
        }
      } elsif (/^\s*disable\s*=/ && !/^\s*disable\s*=\s*yes/) {
        # disable the tftp by handling the entry 'disable = yes'
        my $newcfg = $_;
        $newcfg =~ s/=.*$/= yes/;
        push @newcfgfile, $newcfg;
        $recfg = 1;
      } else {
        push @newcfgfile, $_;
      }
    }
    close (FILE);

    # reconfigure the /etc/xinetd.d/tftp
    if ($recfg) {
      if (! open (FILE, ">/etc/xinetd.d/tftp")) {
        xCAT::MsgUtils->message("S", "ERROR: Cannot open /etc/xinetd.d/tftp");
        return 1;
      }
      print FILE @newcfgfile;
      close (FILE);
      my @output = xCAT::Utils->runcmd("service xinetd status", -1);
      if ($::RUNCMD_RC == 0) {
        if (grep(/running/, @output))
        {
          print ' ';              # indent service output to separate it from the xcatd service output
          system "service xinetd stop";
          if ($? > 0)
          {    # error
              xCAT::MsgUtils->message("S",
                                        "Error on command: service xinetd stop\n");
          }
          system "service xinetd start";
          if ($? > 0)
          {    # error
              xCAT::MsgUtils->message("S",
                                        "Error on command: service xinetd start\n");
          }
        }
      }
    }
  }

  # get the version of TCP/IP protocol
  my $protocols;
  my $v4only="-4 ";
  open($protocols,"<","/proc/net/protocols");
  if ($protocols) {
	my $line;
	while ($line = <$protocols>) {
		if ($line =~ /^TCPv6/) {
			$v4only="";
			last;
		}
	}
    } else {
	$v4only="";
    }

    # get the tftpflags which set by customer
    my $tftpflags = xCAT::TableUtils->get_site_attribute("tftpflags");
    my $startcmd = "/usr/sbin/in.tftpd $v4only -v -l -s $tftpdir -m /etc/tftpmapfile4xcat.conf";
    if ($tftpflags) {
        $startcmd = "/usr/sbin/in.tftpd $v4only $tftpflags";
    }


    if (-x "/usr/sbin/in.tftpd") {
	system("killall in.tftpd"); #xinetd can leave behind blocking tftp servers even if it won't start new ones
    if ($distro =~ /ubuntu.*/i){
        system("stop tftpd-hpa");
    }
    my @tftpprocs=`ps axf|grep -v grep|grep in.tftpd`;
	while (@tftpprocs) {
		sleep 0.1;
	}
        system("$startcmd");
    }

  return 0;
}


1;