#!/bin/bash
#
# sccl_check_config vergleicht die Konfigurationsdateien aller Knoten
#
# Aufruf:
#
# sccl_check_config [-v] [-q] [-C] [-i <node>]
#
########################################################################################
#
. $(dirname $0)/globals.settings
#
unset VERB QUIET NOCLUSTER ignorenode
while getopts i:qvC? op; do
  case "$op" in
   i) ignorenode=" $OPTARG";;
   q) QUIET=1;;
   v) VERB=1;;
   C) NOCLUSTER=1;;
   *) echo "usage: $MYPRG [-v] [-q] [-C] [-i <node>]"
      exit 1;;
  esac
done
shift $(( $OPTIND - 1))
#
TMPDIR=/tmp/sccl_check_config.$$
#
RET=0
#
{ sed -n 's/,/ /g;s/^\([[:alnum:]][^[:blank:]]*[[:blank:]].*\)/P \1/p' $PACKAGES
  echo
  sed -n 's/^\([[:alnum:]][^[:blank:]]*[[:blank:]].*\)/R \1/p' $RESOURCES
  echo
} | awk -v nodes="$NODES$ignorenode" -v quiet=$QUIET '
BEGIN { m = split(nodes, nds)
        l = 0
        for( i = 1; i <= m; i++ )
          nd[nds[i]] = 1
        nd["+"] = 2
        nd["-"] = 2
        checkres["MULTI"] = 2
        checkres["EXECUTE"] = 2
        checkres["SWITCH"] = 2
        checkres["!CPKG"] = 1
        checkres["CPKG"] = 1
        checkres["CPKGO"] = 1
        checkres["CPKGW"] = 1
        checkres["CSRV"] = 1
        checkres["FS"] = 1
        checkres["FSG"] = 1
        checkres["IP"] = 1
        checkres["LOCK"] = 1
        checkres["MINPKGS"] = 1
        checkres["NFS"] = 1
        checkres["NFSG"] = 1
        checkres["!PKG"] = 1
        checkres["PKG"] = 1
        checkres["PRG"] = 1
        checkres["PRGP"] = 1
        checkres["!PROC"] = 1
        checkres["PROC"] = 1
        checkres["RS"] = 1
        checkres["RST"] = 1
        checkres["SETSTATE"] = 1
        checkres["STST"] = 1
        checkres["TEARDOWN"] = 1
        checkres["TST"] = 1 }
$1 == "P" { p[$2]++
            for( i = 3; i <= NF; i++ )
            { if( nd[$i] != 1 && (i > 3 || nd[$i] != 2) )
              { if( ! quiet )
                  print "Warning: Unknown node \"" $i "\" for package \"" $2 "\" in packages.conf"
              }
            }
          }
$1 == "R" { r[$2]++
            setstateflag = 0
            for( i = 4; i <= NF; i++ )
            { n = split($i, a, ":")
              if( !checkres[a[1]] )
              { l = 1
                if( ! quiet )
                  print "Error: Unknown restype \"" a[1] "\" in package \"" $2 "\""
              }
              else if( checkres[a[1]] == 2 && i > 4 )
              { l = 1
                if( ! quiet )
                  print "Error: Restype \"" a[1] "\" in package \"" $2 "\" on wrong position"
              }
              else if( a[1] == "CPKG" )
              { m = split(a[2], b, ",")
                for( j = 1; j <= m; j++ )
                { if( !cpkg[b[j]] )
                    cpkg[b[j]] = $2
                }
              }
              else if( a[1] == "!CPKG" )
              { m = split(a[2], b, ",")
                for( j = 1; j <= m; j++ )
                { if( !ncpkg[b[j]] )
                    ncpkg[b[j]] = $2
                }
              }
              else if( a[1] == "CPKGO" )
              { m = split(a[2], b, ",")
                for( j = 1; j <= m; j++ )
                { if( !cpkgo[b[j]] )
                    cpkgo[b[j]] = $2
                }
              }
              else if( a[1] == "CPKGW" )
              { if( !cpkgw[a[2]] )
                  cpkgw[a[2]] = $2
              }
              else if( a[1] == "CSRV" )
              { m = split(a[2], b, ",")
                for( j = 1; j <= m; j++ )
                { if( !csrv[b[j]] )
                    csrv[b[j]] = $2
                }
              }
              else if( a[1] == "PKG" )
              { m = split(a[2], b, ",")
                for( j = 1; j <= m; j++ )
                { if( !pkg[b[j]] )
                    pkg[b[j]] = $2
                }
              }
              else if( a[1] == "!PKG" )
              { m = split(a[2], b, ",")
                for( j = 1; j <= m; j++ )
                { if( !npkg[b[j]] )
                    npkg[b[j]] = $2
                }
              }
              else if( a[1] == "RST" )
              { m = split(a[2], b, ",")
                for( j = 1; j <= m; j++ )
                { if( !rst[b[j]] )
                    rst[b[j]] = $2
                }
                if( ! setstateflag )
                { if( ! quiet )
                    print "Warning: RST without SETSTATE in package \"" $2 "\""
                  setstateflag = 1
                }
              }
              else if( a[1] == "MINPKGS" )
              { if( !minpkgs[a[2]] )
                  minpkgs[a[2]] = $2
              }
              else if( a[1] == "RS" )
              { if( !rs[a[2]] )
                  rs[a[2]] = $2
              }
              else if( a[1] == "SETSTATE" )
                setstateflag = 1
            }
          }
END { for( i in p )
      { if( p[i] > 1 )
        { l = 1
          if( ! quiet )
            print "Error: Duplicate package \"" i "\" in packages.conf"
        }
        if( !r[i] )
        { l = 1
          if( ! quiet )
            print "Error: Missing line for package \"" i "\" in resources.conf"
        }
        if( rs[i] )
        { l = 1
          if( ! quiet )
            print "Error: Package \"" i "\" used as subresource in " rs[i]
        }
      }
      for( i in r )
      { if( r[i] > 1 )
        { l = 1
          if( ! quiet )
            print "Error: Duplicate resource \"" i "\" in resources.conf"
        }
        if( !p[i] && !rs[i] )
        { l = 1
          if( ! quiet )
            print "Error: Resource \"" i "\" in resources.conf but not in packages.conf and no RS:" i " found"
        }
      }
      for( i in cpkg )
      { if( ! r[i] )
        { l = 1
          if( ! quiet )
            print "Error: Package \"" i "\" in CPKG from resource \"" cpkg[i] "\" not found"
        }
      }
      for( i in ncpkg )
      { if( ! r[i] )
        { l = 1
          if( ! quiet )
            print "Error: Package \"" i "\" in !CPKG from resource \"" ncpkg[i] "\" not found"
        }
      }
      for( i in cpkgo )
      { if( ! r[i] )
        { l = 1
          if( ! quiet )
            print "Error: Package \"" i "\" in CPKGO from resource \"" cpkgo[i] "\" not found"
        }
      }
      for( i in cpkgw )
      { if( ! r[i] )
        { l = 1
          if( ! quiet )
            print "Error: Package \"" i "\" in CPKGW from resource \"" cpkgw[i] "\" not found"
        }
      }
      for( i in pkg )
      { if( ! r[i] )
        { l = 1
          if( ! quiet )
            print "Error: Package \"" i "\" in PKG from resource \"" pkg[i] "\" not found"
        }
      }
      for( i in npkg )
      { if( ! r[i] )
        { l = 1
          if( ! quiet )
            print "Error: Package \"" i "\" in !PKG from resource \"" npkg[i] "\" not found"
        }
      }
      for( i in rst )
      { if( ! p[i] )
        { l = 1
          if( ! quiet )
            print "Error: Package \"" i "\" in RST from resource \"" rst[i] "\" not found"
        }
      }
      for( i in rs )
      { if( rs[i] && ! r[i] )
        { l = 1
          if( ! quiet )
            print "Error: Resource \"" i "\" in RS from resource \"" rs[i] "\" not found"
        }
      }
      for( i in minpkgs )
      { m = 1
        for( j in r )
        { if( j ~ i )
            m = 0
        }
        if( m )
        { l = 1
          if( ! quiet )
            print "Error: No package is matching regexp \"" i "\" in MINPKGS from package \"" minpkgs[i] "\""
        }
      }
      if( l )
      { if( ! quiet )
            print ""
        exit(l)
      }
    }' || RET=1
#
if [[ -n "$NOCLUSTER" ]]; then
  exit $RET
fi
#
if grep -q '^[a-zA-Z].*[[:blank:]].*[A-Z]' $PACKAGES; then
  if [[ -z "$QUIET" ]]; then
    echo "Warning - Uppercase in hostname:"
    grep '^[a-zA-Z].*[[:blank:]].*[A-Z]' $PACKAGES
    echo
  fi
  RET=1
fi
#
if [[ "$NODES" != "$THISHOSTNAME" ]]; then
  mkdir $TMPDIR
  for i in $NODES; do
    if [[ "$i" != "$THISHOSTNAME" && "$i" != "$THISFQDN" ]]; then
      rt=$(sccl_node -t $i)
      if [[ -n "$rt" ]]; then
        mt=$(date '+%s')
        if [[ $rt -lt $(( $mt - 300 )) || $rt -gt $(( $mt + 300 )) ]]; then
          echo "Error: The time of node $i differs from local time. Local: $(date '+%T'), $i: $(date -d@$rt '+%T')"
          RET=1
        elif [[ $rt -lt $(( $mt - 30 )) || $rt -gt $(( $mt + 30 )) ]]; then
          echo "Warning: The time of node $i differs from local time. Local: $(date '+%T'), $i: $(date -d@$rt '+%T')"
        fi
      fi
    fi
  done
  for i in $NODES; do
    ./sccl_node -c $i | grep -v '^usage: sccl node'
  done
  for d in CONFIG PACKAGES RESOURCES; do
    ./sccl_read_config $d >"$TMPDIR/$d.$THISHOSTNAME"
    grep -Ev '^ *#|^ *$' "$TMPDIR/$d.$THISHOSTNAME" >"$TMPDIR/$d.nc.$THISHOSTNAME"
    for i in $NODES; do
      if [[ "$i" != "$THISHOSTNAME" && "$i" != "$THISFQDN" ]]; then
        if ./sccl_read_config $d $i >"$TMPDIR/$d.$i"; then
          if [[ -s "$TMPDIR/$d.$i" ]]; then
            grep -Ev '^ *#|^ *$' "$TMPDIR/$d.$i" >"$TMPDIR/$d.nc.$i"
            [[ -n "$VERB" ]] && echo "$d Vergleich mit $i"
            if diff "$TMPDIR/$d.nc.$THISHOSTNAME" "$TMPDIR/$d.nc.$i" >"$TMPDIR/diff.$d"; then
              if diff -q "$TMPDIR/$d.$THISHOSTNAME" "$TMPDIR/$d.$i" >/dev/null; then
                [[ -n "$VERB" ]] && echo "Die Dateien sind identisch"
              else
                [[ -n "$VERB" ]] && echo "Die Dateien sind bis auf die Kommentare identisch"
              fi
            else
              RET=1
              if [[ -z "$QUIET" ]]; then
                [[ -z "$VERB" ]] && echo "$d Vergleich mit $i"
                echo
                cat "$TMPDIR/diff.$d"
                echo
              fi
            fi
            [[ -n "$VERB" ]] && echo
          else
            [[ -z "$QUIET" ]] && echo "$d auf $i nicht vorhanden oder leer"
            if [[ -s "$TMPDIR/$d.nc.$THISHOSTNAME" ]]; then
              RET=1
            fi
          fi
        else
          RET=1
          [[ -z "$QUIET" ]] && echo "$d konnte nicht mit $i verglichen werden."
          [[ -z "$QUIET" ]] && echo
          [[ -z "$QUIET" ]] && echo
        fi
      fi
    done
  done
  rm -rf $TMPDIR
fi
[[ -z "$VERB$QUIET" && $RET = 0 ]] && echo "OK"
exit $RET
