From: Andrew DeFaria Date: Fri, 1 Mar 2019 00:07:19 +0000 (-0700) Subject: Merge branch 'master' of git+ssh://github.com/adefaria/clearscm X-Git-Url: https://defaria.com/gitweb/?a=commitdiff_plain;h=a70e80a6af6e31d56b120348bc8bc23cdd6543f5;hp=559f9045ae05e457c7eb4b6c684aa9651b98971a;p=clearscm.git Merge branch 'master' of git+ssh://github.com/adefaria/clearscm --- diff --git a/bin/bigfiles.pl b/bin/bigfiles.pl index 3c539c2..a020f19 100755 --- a/bin/bigfiles.pl +++ b/bin/bigfiles.pl @@ -43,7 +43,9 @@ sub Bigfiles { foreach (@dirs) { next if !-d "$_"; - my $cmd = "find \"$_\" -xdev -type f -size +$size -exec ls -lLG {} \\;"; + + my $lsOpts = $ARCHITECTURE eq 'solaris' ? '-loL' : '-lLG'; + my $cmd = "find \"$_\" -xdev -type f -size +$size -exec ls $lsOpts {} \\;"; my @lines = `$cmd`; foreach (@lines) { @@ -52,7 +54,7 @@ sub Bigfiles { my %info; #if (/\S+\s+\d+\s+(\S+)\s+(\d+).*\"\.\/(.*)\"/) { - if (/\S+\s+\d+\s+(\S+)\s+\S+ \S+\s+(\d+)\s+\S+\s+\d+\s+\S+\s+(\S+)/){ + if (/\S+\s+\d+\s+(\S+)\s+(\d+)\s+\S+\s+\S+\s+\d+\s+(.*)/) { $info {user} = $1; $info {filesize} = $2; $info {filename} = $3; @@ -70,7 +72,9 @@ my $top = $lines - 2; my $bytes_in_meg = 1048576; my $block_size = 512; my $size_in_meg = 1; -my %opts; +my %opts = ( + size => 1 +); my $result = GetOptions ( \%opts, @@ -81,23 +85,26 @@ my $result = GetOptions ( 'size=i', ); -my @dirs = @ARGV || '.'; -my $size = $opts {size} ? $opts {size} * $bytes_in_meg / $block_size : 4096; +my @dirs = @ARGV > 0 ? @ARGV : '.'; +my $size = $opts{size} ? $opts{size} * $bytes_in_meg / $block_size : 4096; +my @files; # Now do the find -verbose "Directory:\t$_" +verbose "Directory:\t@dirs"; -foreach (@dirs) { - verbose "Size:\t\t$size_in_meg Meg ($size blocks)"; +for (@dirs) { + verbose "Size:\t\t$opts{size} Meg ($size blocks)"; verbose "Top:\t\t$top"; my $head = $top ? "cat" : "head -$top"; - my @files = Bigfiles $size, @dirs; -} # for each + @files = Bigfiles $size, @dirs; +} # for -foreach (@files) { +for (sort {$b->{filesize} <=> $a->{filesize}} @files) { my %info = %{$_}; + last if $top-- == 0; + print "${info {filesize}}\t${info {user}}\t${info {filename}}\n"; -} # foreach +} # for diff --git a/bin/findsymlinks.sh b/bin/findsymlinks.sh new file mode 100755 index 0000000..56f8043 --- /dev/null +++ b/bin/findsymlinks.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +path=$1 + +if [ -z "$path" ]; then + echo "Usage $0 " + exit 1 +fi + +IFS='/' read -ra components <<< "$path" + +testpath='' + +for component in "${components[@]}"; do + [ -z "$component" ] && continue + + testpath="${testpath}/$component" + + if [ -h "$testpath" ]; then + points_to=$(ls -l $testpath | awk '{print $NF}') + + echo "$testpath: symbolic link to $(ls -l $testpath | awk '{print $NF}')" + testpath=$(readlink -n $testpath) + fi +done + diff --git a/bin/rexec.pl b/bin/rexec.pl index 1c61a3f..b659338 100755 --- a/bin/rexec.pl +++ b/bin/rexec.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl use strict; use warnings; @@ -18,7 +18,7 @@ Andrew DeFaria =item Revision -$Revision: 1.0 $ +$Revision: 2.0 $ =item Created: @@ -35,7 +35,8 @@ $Date: 2008/02/29 15:09:15 $ Usage: rexec.pl [-usa|ge] [-h|elp] [-v|erbose] [-d|ebug] [-use|rname ] [-p|assword ] [-log] - -m|achines ,,... + [-m|achines ,,...] + [-f|ile ] @@ -47,6 +48,7 @@ $Date: 2008/02/29 15:09:15 $ -use|rname: User name to login as (Default: $USER - Env: REXEC_USER) -p|assword: Password to use (Default: None - Env: REXEC_PASSWD) -m|achines: Machine(s) to run the command on + -f|ile: File containing machine info -l|og: Log output (.log) : Commands to execute (Enclose multiple commands in quotes) @@ -119,15 +121,17 @@ my %opts = ( debug => sub { set_debug }, username => $ENV{REXEC_USER} || $ENV{USER}, password => $ENV{REXEC_PASSWD}, - filename => $ENV{REXEC_MACHINES_FILE} || '/opt/clearscm/data/machines', + database => 1, ); sub Interrupted { use Term::ReadKey; - display BLUE . "\nInterrupted execution on $currentHost->{host}" . RESET; + my $host = $currentHost->{host} || 'Unknown Host'; - display_nolf "Executing on " . YELLOW . $currentHost->{host} . RESET . " - " + display BLUE . "\nInterrupted execution on $host" . RESET; + + display_nolf "Executing on " . CYAN . $host . RESET . " - " . CYAN . BOLD . "C" . RESET . CYAN . "ontinue" . RESET . " or " . MAGENTA . BOLD . "A" . RESET . MAGENTA . "bort run" . RESET . " (" . CYAN . BOLD . "C" . RESET . "/" @@ -147,7 +151,7 @@ sub Interrupted { if ($answer eq "s") { *STDOUT->flush; - display "Skipping $currentHost->{host}"; + display "Skipping $host"; } elsif ($answer eq "a") { display RED . "Aborting run". RESET; exit; @@ -161,9 +165,6 @@ sub Interrupted { sub connectHost ($) { my ($host) = @_; - # Start a log... - $log = Logger->new (name => $host) if $opts{log}; - eval { $currentHost = Rexec->new ( host => $host, @@ -184,27 +185,60 @@ sub connectHost ($) { return; } # connectHost +sub initLog($) { + my ($machine) = @_; + + if ($opts{log}) { + my $logdir = $opts{logdir} ? "$opts{logdir}/$machine" : $machine; + + mkdir $logdir or error "Unable to make directory $logdir", 1; + + $log = Logger->new( + name => 'output', + path => $logdir, + ); + } # if +} # initLog + +sub Log($;$) { + my ($msg, $nocrlf) = @_; + + if ($log) { + $log->msg($msg, $nocrlf); + } else { + verbose $msg, $nocrlf; + } # +} # Log + +sub logError ($;$) { + my ($msg, $exit) = @_; + + if ($log) { + $log->err($msg, $exit); + } else { + error $msg, $exit; + } # if +} # logError + sub execute ($$;$) { my ($host, $cmd, $prompt) = @_; my @lines; - verbose_nolf "Connecting to machine $host..."; + Log "Connecting to machine $host...", 1; - display_nolf BOLD . YELLOW . "$host:" . RESET if $opts{verbose}; + display_nolf BOLD . CYAN . "$host:" . RESET if $opts{verbose}; connectHost $host unless $currentHost and $currentHost->{host} eq $host; return (1, ()) unless $currentHost; - verbose " connected"; + Log ' connected'; - display WHITE . UNDERLINE . "$cmd" . RESET if $opts{verbose}; + Log "$host:" . UNDERLINE . $cmd . RESET; @lines = $currentHost->execute ($cmd); - verbose "Disconnected from $host"; - my $status = $currentHost->status; return ($status, @lines); @@ -224,8 +258,9 @@ GetOptions ( 'log', 'logdir', 'filename=s', - 'database', + 'database!', 'machines=s@', + 'condition=s', ) or pod2usage; $opts{debug} = get_debug if ref $opts{debug} eq 'CODE'; @@ -233,38 +268,47 @@ $opts{verbose} = get_verbose if ref $opts{verbose} eq 'CODE'; my $cmd = join ' ', @ARGV; +$opts{machines} = [$ENV{REXEC_HOST}] if $ENV{REXEC_HOST}; + unless ($opts{machines}) { - $opts{machines} = [$ENV{REXEC_HOST}] if $ENV{REXEC_HOST}; -} # unless + # Connect to Machines module + my $machines; -# Connect to Machines module -my $machines; + unless ($opts{database}) { + require Machines; Machines->import; -unless ($opts{database}) { - require Machines; Machines->import; + $machines = Machines->new(filename => $opts{filename}); + } else { + require Machines::MySQL; Machines::MySQL->import; - $machines = Machines->new(filename => $opts{filename}); -} else { - require Machines::MySQL; Machines::MySQL->import; + $machines = Machines::MySQL->new; - $machines = Machines::MySQL->new; -} # if + my %machines = $machines->select($opts{condition}); -my %machines = $machines->select; + $opts{machines} = [keys %machines]; + } # if +} # if my ($status, @lines); -for my $machine (sort keys %machines) { +for my $machine (sort @{$opts{machines}}) { + initLog $machine; + if ($cmd) { ($status, @lines) = execute $machine, $cmd; - display BOLD . YELLOW . "$machine:" . RESET . WHITE . $cmd; + display BOLD . CYAN . "$machine:" . UNDERLINE . WHITE . $cmd . RESET; + + logError "Execution of $cmd on $machine failed", $status if $status; - error "Execution of $cmd on $machine yielded error $status" if $status; + if ($log) { + $log->log($_) for @lines; + } # if display $_ for @lines; undef $currentHost; + undef $log; } else { verbose_nolf "Connecting to machine $machine..."; @@ -273,13 +317,15 @@ for my $machine (sort keys %machines) { if ($currentHost) { my $cmdline = CmdLine->new (); - $cmdline->set_prompt (BOLD . YELLOW . "$machine:" . RESET . WHITE); + $cmdline->set_prompt (BOLD . CYAN . "$machine:" . RESET . WHITE); while () { - #$cmd = ; + Log "$machine:"; + $cmd = $cmdline->get(); unless ($cmd) { + $log->msg('') if $log; display ''; last; } # unless @@ -289,12 +335,17 @@ for my $machine (sort keys %machines) { chomp $cmd; + Log $cmd; + ($status, @lines) = execute $machine, $cmd; - error "Execution of $cmd on $machine yielded error $status" if $status; + logError "Execution of $cmd on $machine failed", $status if $status; + Log $_ for @lines; display $_ for @lines; } # while } # if + + undef $log; } # if } # for diff --git a/clearadm/alertlog.cgi b/clearadm/alertlog.cgi index e2c1e45..8269699 100755 --- a/clearadm/alertlog.cgi +++ b/clearadm/alertlog.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -151,4 +151,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/alerts.cgi b/clearadm/alerts.cgi index 8bfa1fa..2fb1ede 100755 --- a/clearadm/alerts.cgi +++ b/clearadm/alerts.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -143,4 +143,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/clearadmscrub.pl b/clearadm/clearadmscrub.pl index 8417622..f8b558e 100755 --- a/clearadm/clearadmscrub.pl +++ b/clearadm/clearadmscrub.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -49,6 +49,7 @@ use warnings; use FindBin; use Getopt::Long; +use Sys::Hostname; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; @@ -80,7 +81,7 @@ verbose "$FindBin::Script V$VERSION"; my ($err, $msg); -foreach my $system ($clearadm->FindSystem ($host)) { +for my $system ($clearadm->FindSystem ($host)) { ($err, $msg) = $clearadm->TrimLoadavg ($$system{name}); if ($msg eq 'Records deleted' or $msg eq '') { @@ -89,7 +90,7 @@ foreach my $system ($clearadm->FindSystem ($host)) { error "#$err: $msg"; } # if - foreach my $filesystem ($clearadm->FindFilesystem ($$system{name}, $fs)) { + for my $filesystem ($clearadm->FindFilesystem ($$system{name}, $fs)) { ($err, $msg) = $clearadm->TrimFS ($$system{name}, $$filesystem{filesystem}); if ($msg eq 'Records deleted' or $msg eq '') { @@ -97,8 +98,8 @@ foreach my $system ($clearadm->FindSystem ($host)) { } else { error "#$err: $msg"; } # if - } # foreach -} # foreach + } # for +} # for # TODO: These should be configurable my $sixMonthsAgo = SubtractDays (Today2SQLDatetime, 180); @@ -106,6 +107,7 @@ my $sixMonthsAgo = SubtractDays (Today2SQLDatetime, 180); my %runlog = ( task => 'Scrub', started => Today2SQLDatetime, + system => hostname(), ); # Scrub old alertlogs @@ -178,4 +180,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/clearagent.pl b/clearadm/clearagent.pl index 5fae618..fae4519 100755 --- a/clearadm/clearagent.pl +++ b/clearadm/clearagent.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl =pod @@ -57,6 +57,7 @@ use warnings; use Getopt::Long; use FindBin; +use Sys::Hostname; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; @@ -95,7 +96,9 @@ $clearexec = Clearexec->new; $clearexec->setMultithreaded ($multithreaded); -my $logfile = "$Clearexec::CLEAROPTS{CLEAREXEC_LOGDIR}/$FindBin::Script.log"; +my $logfile = "$Clearexec::CLEAROPTS{CLEAREXEC_LOGDIR}/$FindBin::Script"; + $logfile =~ s/\.pl$//; + $logfile .= '.' . hostname() . '.log'; EnterDaemonMode $logfile, $logfile, $pidfile if $daemon; diff --git a/clearadm/clearexec.pl b/clearadm/clearexec.pl index 53963a7..cd593e5 100755 --- a/clearadm/clearexec.pl +++ b/clearadm/clearexec.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl =pod diff --git a/clearadm/cleartasks.pl b/clearadm/cleartasks.pl index 66c964b..25a297b 100755 --- a/clearadm/cleartasks.pl +++ b/clearadm/cleartasks.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl =pod @@ -47,6 +47,9 @@ $Date: 2013/06/02 18:47:26 $ Examine the Clearadm schedule and perform the tasks required. +Note that sending the Cleartasks.pl process a sigusr1 will cause it to toggle +verbose mode. + =cut use strict; @@ -54,6 +57,7 @@ use warnings; use FindBin; use Getopt::Long; +use Sys::Hostname; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; @@ -67,7 +71,10 @@ use Utils; my $VERSION = '$Revision: 1.25 $'; ($VERSION) = ($VERSION =~ /\$Revision: (.*) /); -my $logfile = "$Clearadm::CLEAROPTS{CLEARADM_LOGDIR}/$FindBin::Script.log"; +my $logfile = "$Clearadm::CLEAROPTS{CLEARADM_LOGDIR}/$FindBin::Script"; + $logfile =~ s/\.pl$//; + $logfile .= '.' . hostname() . '.log'; + my $pidfile = "$Clearadm::CLEAROPTS{CLEARADM_RUNDIR}/$FindBin::Script.pid"; my $daemon = 1; @@ -76,6 +83,18 @@ $ENV{PATH} .= ":$Clearadm::CLEAROPTS{CLEARADM_BASE}"; my ($clearadm, $clearexec); +sub ToggleVerbose() { + if (get_verbose) { + display 'Turning verbose off'; + set_verbose 0; + } else { + display 'Turning verbose on'; + set_verbose 1; + } # if +} # ToggleVerbose + +$SIG{USR1} = \&ToggleVerbose; + sub HandleSystemNotCheckingIn (%) { my (%system) = @_; @@ -131,7 +150,7 @@ END } # HandleSystemNotCheckingIn sub SystemsCheckin () { - foreach ($clearadm->FindSystem) { + for ($clearadm->FindSystem) { my %system = %$_; next if $system{active} eq 'false'; @@ -163,7 +182,7 @@ sub SystemsCheckin () { $clearadm->ClearNotifications ($system{name}) if $system{notification} and $system{notification} eq 'Heartbeat'; - } # foreach + } # for return; } # SystemsCheckin @@ -225,7 +244,7 @@ sub ProcessLoadavgErrors ($$$$@) { my $when = Today2SQLDatetime; - foreach (@output) { + for (@output) { # We need to log this output. Write it to STDOUT display $_; @@ -285,7 +304,7 @@ END undef, $lastid, ); - } # foreach + } # for return; } # ProcessLoadAvgErrors @@ -300,7 +319,7 @@ sub ProcessFilesystemErrors ($$$$@) { my %system; - foreach (@output) { + for (@output) { # We need to log this output. Write it to STDOUT display $_; @@ -317,9 +336,9 @@ sub ProcessFilesystemErrors ($$$$@) { $system{$1} = \%fsinfo; } # if } # if - } # foreach + } # for - foreach my $systemName (keys %system) { + for my $systemName (keys %system) { my @fsinfo; if (ref $system{$systemName} eq 'HASH') { @@ -340,7 +359,7 @@ were over their threshold.

    END - foreach (@fsinfo) { + for (@fsinfo) { my %fsinfo = %{$_}; my $filesystemLink = $Clearadm::CLEAROPTS{CLEARADM_WEBBASE}; $filesystemLink .= "/plot.cgi?type=filesystem&system=$systemName"; @@ -349,7 +368,7 @@ END $message .= "
  • Filesystem "; $message .= "$fsinfo{filesystem} is $fsinfo{usedPct}% full. Threshold is "; $message .= "$fsinfo{threshold}%
  • "; - } # foreach + } # for $message .= "
"; @@ -362,7 +381,7 @@ END undef, $lastid, ); - } # foreach + } # for return; } # ProcessFilesystemErrors @@ -518,26 +537,28 @@ while () { my ($sleep, @workItems) = $clearadm->GetWork; - foreach (@workItems) { + for (@workItems) { my %scheduledTask = %{$_}; $scheduledTask{system} ||= 'All systems'; if ($scheduledTask{system} =~ /all systems/i) { - foreach my $system ($clearadm->FindSystem) { + for my $system ($clearadm->FindSystem) { + next if $$system{active} eq 'false'; + $scheduledTask{system} = $$system{name}; $sleep = ExecuteTask $sleep, %scheduledTask; - } # foreach + } # for } else { $sleep = ExecuteTask $sleep, %scheduledTask; } # if - } # foreach + } # for if ($sleep > 0) { verbose "Sleeping for $sleep seconds"; sleep $sleep; } # if -} # foreach +} # for =pod diff --git a/clearadm/deletealertlog.cgi b/clearadm/deletealertlog.cgi index e16d4a3..af79c21 100755 --- a/clearadm/deletealertlog.cgi +++ b/clearadm/deletealertlog.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -156,4 +156,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/discovery.pl b/clearadm/discovery.pl index af0b789..49b4b3f 100755 --- a/clearadm/discovery.pl +++ b/clearadm/discovery.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl =pod @@ -41,7 +41,7 @@ $Date: 2011/01/07 20:48:22 $ -broadcastA|ddr : Broadcast IP (Default: Current subnet) -broadcastT|ime : Number of sends to wait for responses to broadcast - (Default: 30 seconds) + (Default: 10 seconds) =head1 DESCRIPTION @@ -62,6 +62,7 @@ use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; use Clearadm; use Display; +use OSDep; use Utils; my $VERSION = '$Revision: 1.1 $'; @@ -81,14 +82,18 @@ sub discover ($) { verbose "Performing discovery (for $broadcastTime seconds)..."; while (<$broadcast>) { - if (/from (.*):/) { - my $ip = $1; - my $hostname = gethostbyaddr (inet_aton ($ip), AF_INET); - - unless ($hosts{$ip}) { - verbose "Received response from ($ip): $hostname"; - $hosts{$ip} = $hostname; - } # unless + display "Received line: $_"; + if (/from (\S+) \((.+)\)/) { + my $hostname = $1; + my $ip = $2; + + # Remove domain + $hostname =~ s/(\w+)\..*/$1/; + + unless ($hosts{$ip}) { + verbose "Received response from ($ip): $hostname"; + $hosts{$ip} = $hostname; + } # unless } # if last @@ -117,8 +122,16 @@ Usage 'Extraneous options: ' . join ' ', @ARGV # Announce ourselves verbose "$FindBin::Script V$VERSION"; -my $broadcastCmd = "ping -b $broadcastAddress 2>&1"; +my $broadcastCmd = 'ping '; +if ($ARCHITECTURE eq 'solaris') { + $broadcastCmd .= '-s '; +} else { + $broadcastCmd .= '-b '; +} # if + +$broadcastCmd .= "$broadcastAddress 2>&1"; + my $pid = open my $broadcast, '-|', $broadcastCmd or error "Unable to do $broadcastCmd", 1; @@ -196,4 +209,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/etc/conf.d/clearadm.conf b/clearadm/etc/conf.d/clearadm.conf index 38ef606..b1031cf 100644 --- a/clearadm/etc/conf.d/clearadm.conf +++ b/clearadm/etc/conf.d/clearadm.conf @@ -12,6 +12,8 @@ # ############################################################################### Alias /clearadm /opt/clearscm/clearadm + +DirectoryIndex index.cgi index.html Options Indexes FollowSymLinks ExecCGI @@ -19,7 +21,6 @@ Alias /clearadm /opt/clearscm/clearadm Order allow,deny Allow from all Require all granted - DirectoryIndex index.cgi index.html AddHandler cgi-script .cgi diff --git a/clearadm/etc/init.d/clearagent b/clearadm/etc/init.d/clearagent deleted file mode 100755 index 99b5e55..0000000 --- a/clearadm/etc/init.d/clearagent +++ /dev/null @@ -1,156 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: clearagent -# Required-Start: $network -# Required-Stop: none -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Starts the clearagent daemon -# Description: Clearagent is part of the Clearadm package by ClearSCM, -# Inc. It is a daemon that runs in the background and -# responds to requests to run commands on the local system -# and return the results. -### END INIT INFO - -# Author: Andrew DeFaria -# -# Do NOT "set -e" - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin -DESC="Clearagent Daemon" -NAME=clearagent.pl -DAEMON=/opt/clearscm/clearadm/$NAME -PIDFILE=/opt/clearscm/clearadm/var/run/$NAME.pid -DAEMON_ARGS="" -SCRIPTNAME=/etc/init.d/$NAME -RUNASUSER="clearagent" - -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - -# Read configuration variable file if it is present -[ -r /etc/default/$NAME ] && . /etc/default/$NAME - -# Load the VERBOSE setting and other rcs variables -. /lib/init/vars.sh - -# Define LSB log_* functions. -# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. -. /lib/lsb/init-functions - -# -# Function that starts the daemon/service -# -do_start() -{ - # Return - # 0 if daemon has been started - # 1 if daemon was already running - # 2 if daemon could not be started - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ - || return 1 - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON \ - --chuid $RUNASUSER \ - -- $DAEMON_ARGS \ - || return 2 -} - -# -# Function that stops the daemon/service -# -do_stop() -{ - # Return - # 0 if daemon has been stopped - # 1 if daemon was already stopped - # 2 if daemon could not be stopped - # other if a failure occurred - start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME - RETVAL="$?" - [ "$RETVAL" = 2 ] && return 2 - # Wait for children to finish too if this is a daemon that forks - # and if the daemon is only ever run from this initscript. - # If the above conditions are not satisfied then add some other code - # that waits for the process to drop all resources that could be - # needed by services started subsequently. A last resort is to - # sleep for some time. - start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON - [ "$?" = 2 ] && return 2 - # Many daemons don't delete their pidfiles when they exit. - rm -f $PIDFILE - return "$RETVAL" -} - -# -# Function that sends a SIGHUP to the daemon/service -# -do_reload() { - # - # If the daemon can reload its configuration without - # restarting (for example, when it is sent a SIGHUP), - # then implement that here. - # - start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME - return 0 -} - -case "$1" in - start) - [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" - do_start - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - stop) - [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" - do_stop - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - status) - status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? - ;; - #reload|force-reload) - # - # If do_reload() is not implemented then leave this commented out - # and leave 'force-reload' as an alias for 'restart'. - # - #log_daemon_msg "Reloading $DESC" "$NAME" - #do_reload - #log_end_msg $? - #;; - restart|force-reload) - # - # If the "reload" option is implemented then remove the - # 'force-reload' alias - # - log_daemon_msg "Restarting $DESC" "$NAME" - do_stop - case "$?" in - 0|1) - do_start - case "$?" in - 0) log_end_msg 0 ;; - 1) log_end_msg 1 ;; # Old process is still running - *) log_end_msg 1 ;; # Failed to start - esac - ;; - *) - # Failed to stop - log_end_msg 1 - ;; - esac - ;; - *) - #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 - echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 - exit 3 - ;; -esac - -: diff --git a/clearadm/etc/init.d/clearagent b/clearadm/etc/init.d/clearagent new file mode 120000 index 0000000..0f3fa68 --- /dev/null +++ b/clearadm/etc/init.d/clearagent @@ -0,0 +1 @@ +clearagent.solaris \ No newline at end of file diff --git a/clearadm/etc/init.d/clearagent.linux b/clearadm/etc/init.d/clearagent.linux new file mode 100755 index 0000000..99b5e55 --- /dev/null +++ b/clearadm/etc/init.d/clearagent.linux @@ -0,0 +1,156 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: clearagent +# Required-Start: $network +# Required-Stop: none +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Starts the clearagent daemon +# Description: Clearagent is part of the Clearadm package by ClearSCM, +# Inc. It is a daemon that runs in the background and +# responds to requests to run commands on the local system +# and return the results. +### END INIT INFO + +# Author: Andrew DeFaria +# +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="Clearagent Daemon" +NAME=clearagent.pl +DAEMON=/opt/clearscm/clearadm/$NAME +PIDFILE=/opt/clearscm/clearadm/var/run/$NAME.pid +DAEMON_ARGS="" +SCRIPTNAME=/etc/init.d/$NAME +RUNASUSER="clearagent" + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcs variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON \ + --chuid $RUNASUSER \ + -- $DAEMON_ARGS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/clearadm/etc/init.d/clearagent.solaris b/clearadm/etc/init.d/clearagent.solaris new file mode 100755 index 0000000..b7c6883 --- /dev/null +++ b/clearadm/etc/init.d/clearagent.solaris @@ -0,0 +1,5 @@ +#/bin/bash +# +# Solaris doesn't support init.d scripts and I'm not writting a bona fide +# SMF service for this +exec /opt/clearscm/clearadm/clearagent.pl diff --git a/clearadm/etc/init.d/cleartasks b/clearadm/etc/init.d/cleartasks deleted file mode 100755 index ddbb1c2..0000000 --- a/clearadm/etc/init.d/cleartasks +++ /dev/null @@ -1,156 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: cleartasks -# Required-Start: $network $mysql -# Required-Stop: none -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Starts the cleartasks daemon -# Description: Cleartasks are part of the Clearadm package by ClearSCM, -# Inc. It is a daemon that runs in the background and -# performs the various predefined and user defined tasks -# from the Clearadm database -### END INIT INFO - -# Author: Andrew DeFaria -# -# Do NOT "set -e" - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin -DESC="Cleartasks Daemon" -NAME=cleartasks.pl -DAEMON=/opt/clearscm/clearadm/$NAME -PIDFILE=/opt/clearscm/clearadm/var/run/$NAME.pid -DAEMON_ARGS="" -SCRIPTNAME=/etc/init.d/$NAME -RUNASUSER="clearagent" - -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - -# Read configuration variable file if it is present -[ -r /etc/default/$NAME ] && . /etc/default/$NAME - -# Load the VERBOSE setting and other rcs variables -. /lib/init/vars.sh - -# Define LSB log_* functions. -# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. -. /lib/lsb/init-functions - -# -# Function that starts the daemon/service -# -do_start() -{ - # Return - # 0 if daemon has been started - # 1 if daemon was already running - # 2 if daemon could not be started - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ - || return 1 - start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON \ - --chuid $RUNASUSER \ - -- $DAEMON_ARGS \ - || return 2 -} - -# -# Function that stops the daemon/service -# -do_stop() -{ - # Return - # 0 if daemon has been stopped - # 1 if daemon was already stopped - # 2 if daemon could not be stopped - # other if a failure occurred - start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME - RETVAL="$?" - [ "$RETVAL" = 2 ] && return 2 - # Wait for children to finish too if this is a daemon that forks - # and if the daemon is only ever run from this initscript. - # If the above conditions are not satisfied then add some other code - # that waits for the process to drop all resources that could be - # needed by services started subsequently. A last resort is to - # sleep for some time. - start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON - [ "$?" = 2 ] && return 2 - # Many daemons don't delete their pidfiles when they exit. - rm -f $PIDFILE - return "$RETVAL" -} - -# -# Function that sends a SIGHUP to the daemon/service -# -do_reload() { - # - # If the daemon can reload its configuration without - # restarting (for example, when it is sent a SIGHUP), - # then implement that here. - # - start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME - return 0 -} - -case "$1" in - start) - [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" - do_start - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - stop) - [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" - do_stop - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - status) - status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? - ;; - #reload|force-reload) - # - # If do_reload() is not implemented then leave this commented out - # and leave 'force-reload' as an alias for 'restart'. - # - #log_daemon_msg "Reloading $DESC" "$NAME" - #do_reload - #log_end_msg $? - #;; - restart|force-reload) - # - # If the "reload" option is implemented then remove the - # 'force-reload' alias - # - log_daemon_msg "Restarting $DESC" "$NAME" - do_stop - case "$?" in - 0|1) - do_start - case "$?" in - 0) log_end_msg 0 ;; - 1) log_end_msg 1 ;; # Old process is still running - *) log_end_msg 1 ;; # Failed to start - esac - ;; - *) - # Failed to stop - log_end_msg 1 - ;; - esac - ;; - *) - #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 - echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 - exit 3 - ;; -esac - -: diff --git a/clearadm/etc/init.d/cleartasks b/clearadm/etc/init.d/cleartasks new file mode 120000 index 0000000..904fa9f --- /dev/null +++ b/clearadm/etc/init.d/cleartasks @@ -0,0 +1 @@ +cleartasks.solaris \ No newline at end of file diff --git a/clearadm/etc/init.d/cleartasks.linux b/clearadm/etc/init.d/cleartasks.linux new file mode 100755 index 0000000..ddbb1c2 --- /dev/null +++ b/clearadm/etc/init.d/cleartasks.linux @@ -0,0 +1,156 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: cleartasks +# Required-Start: $network $mysql +# Required-Stop: none +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Starts the cleartasks daemon +# Description: Cleartasks are part of the Clearadm package by ClearSCM, +# Inc. It is a daemon that runs in the background and +# performs the various predefined and user defined tasks +# from the Clearadm database +### END INIT INFO + +# Author: Andrew DeFaria +# +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="Cleartasks Daemon" +NAME=cleartasks.pl +DAEMON=/opt/clearscm/clearadm/$NAME +PIDFILE=/opt/clearscm/clearadm/var/run/$NAME.pid +DAEMON_ARGS="" +SCRIPTNAME=/etc/init.d/$NAME +RUNASUSER="clearagent" + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcs variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON \ + --chuid $RUNASUSER \ + -- $DAEMON_ARGS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/clearadm/etc/init.d/cleartasks.solaris b/clearadm/etc/init.d/cleartasks.solaris new file mode 100755 index 0000000..c9cd40d --- /dev/null +++ b/clearadm/etc/init.d/cleartasks.solaris @@ -0,0 +1,5 @@ +#/bin/bash +# +# Solaris doesn't support init.d scripts and I'm not writting a bona fide +# SMF service for this +exec /opt/clearscm/clearadm/cleartasks.pl diff --git a/clearadm/filesystems.cgi b/clearadm/filesystems.cgi index a278f3a..b2fa03b 100755 --- a/clearadm/filesystems.cgi +++ b/clearadm/filesystems.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -151,4 +151,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/getFilesystems.cgi b/clearadm/getFilesystems.cgi index 88d8084..4a84c87 100755 --- a/clearadm/getFilesystems.cgi +++ b/clearadm/getFilesystems.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -117,4 +117,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/getTimestamp.cgi b/clearadm/getTimestamp.cgi index 2c4212e..b4878d3 100755 --- a/clearadm/getTimestamp.cgi +++ b/clearadm/getTimestamp.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -165,4 +165,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/index.cgi b/clearadm/index.cgi index a5259ea..76d3724 100755 --- a/clearadm/index.cgi +++ b/clearadm/index.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -44,13 +44,14 @@ use Getopt::Long; use CGI qw (:standard *table start_Tr end_Tr); use CGI::Carp 'fatalsToBrowser'; +use Convert::Base64; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; use ClearadmWeb; use Clearadm; -#use Clearcase; -#use Clearcase::Views; +use Clearcase; +use Clearcase::Views; use Display; use Utils; @@ -94,7 +95,7 @@ my @systems = $clearadm->FindSystem; $perRow = @systems if @systems < $perRow; -foreach (@systems) { +for (@systems) { my %system = %{$_}; if ($i++ % $perRow == 0) { @@ -106,8 +107,7 @@ foreach (@systems) { my $data; - $data = '' - if $system{active} eq 'false'; + $data = '' if $system{active} eq 'false'; $data .= a { href => "systemdetails.cgi?system=$system{name}" @@ -115,7 +115,7 @@ foreach (@systems) { if ($system{notification}) { $data .= ' ' . a { - href => "alertlog.cgi?system=$system{name}"}, img { + href => "alertlog.cgi?system=$system{name}"}, img { src => 'alert.png', border => 0, alt => 'Alert!', @@ -123,20 +123,25 @@ foreach (@systems) { }; } # if + my $image = $system{loadavgsmall} + ? "data:image/png;base64,$system{loadavgsmall}" + : "plotloadavg.cgi?system=$system{name}&tiny=1"; + $data .= '
' . a {href => "plot.cgi?type=loadavg&system=$system{name}&scaling=Hour&points=24" }, img { - src => "plotloadavg.cgi?system=$system{name}&tiny=1", + src => $image, border => 0, }; - $data .= '
' - if $system{active} eq 'false'; + $data .= '
' if $system{active} eq 'false'; + $load{uptime} ||= 'Unknown'; + display td {class => 'dataCentered'}, "$data ", font {class => 'dim' }, "
Up: $load{uptime}"; -} # foreach +} # for while ($i % $perRow != 0) { $i++; @@ -203,4 +208,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/lib/Clearadm.pm b/clearadm/lib/Clearadm.pm index 719b772..afda2ae 100644 --- a/clearadm/lib/Clearadm.pm +++ b/clearadm/lib/Clearadm.pm @@ -88,6 +88,7 @@ use Carp; use DBI; use File::Basename; use Net::Domain qw(hostdomain); +use Sys::Hostname; use FindBin; @@ -98,9 +99,9 @@ use Display; use GetConfig; use Mail; -my $conf = dirname (__FILE__) . '/../etc/clearadm.conf'; +my $conf = dirname(__FILE__) . '/../etc/clearadm.conf'; -our %CLEAROPTS = GetConfig ($conf); +our %CLEAROPTS = GetConfig($conf); # Globals our $VERSION = '$Revision: 1.54 $'; @@ -127,7 +128,7 @@ my $defaultFilesystemHist = '6 months'; my $defaultLoadavgHist = '6 months'; # Internal methods -sub _dberror ($$) { +sub _dberror($$) { my ($self, $msg, $statement) = @_; my $dberr = $self->{db}->err; @@ -139,7 +140,7 @@ sub _dberror ($$) { my $message = ''; if ($dberr) { - my $function = (caller (1)) [3]; + my $function = (caller(1)) [3]; $message = "$function: $msg\nError #$dberr: $dberrmsg\n" . "SQL Statement: $statement"; @@ -148,46 +149,46 @@ sub _dberror ($$) { return $dberr, $message; } # _dberror -sub _formatValues (@) { +sub _formatValues(@) { my ($self, @values) = @_; my @returnValues; # Quote data values - push @returnValues, $_ eq '' ? 'null' : $self->{db}->quote ($_) + push @returnValues, $_ eq '' ? 'null' : $self->{db}->quote($_) for (@values); return @returnValues; } # _formatValues -sub _formatNameValues (%) { +sub _formatNameValues(%) { my ($self, %rec) = @_; my @nameValueStrs; - push @nameValueStrs, "$_=" . $self->{db}->quote ($rec{$_}) + push @nameValueStrs, "$_=" . $self->{db}->quote($rec{$_}) for (keys %rec); return @nameValueStrs; } # _formatNameValues -sub _addRecord ($%) { +sub _addRecord($%) { my ($self, $table, %rec) = @_; my $statement = "insert into $table ("; $statement .= join ',', keys %rec; $statement .= ') values ('; - $statement .= join ',', $self->_formatValues (values %rec); + $statement .= join ',', $self->_formatValues(values %rec); $statement .= ')'; my ($err, $msg); - $self->{db}->do ($statement); + $self->{db}->do($statement); - return $self->_dberror ("Unable to add record to $table", $statement); + return $self->_dberror("Unable to add record to $table", $statement); } # _addRecord -sub _deleteRecord ($;$) { +sub _deleteRecord($;$) { my ($self, $table, $condition) = @_; my $count; @@ -196,11 +197,11 @@ sub _deleteRecord ($;$) { $statement .= "where $condition" if $condition; - my $sth = $self->{db}->prepare ($statement) - or return $self->_dberror ('Unable to prepare statement', $statement); + my $sth = $self->{db}->prepare($statement) + or return $self->_dberror('Unable to prepare statement', $statement); $sth->execute - or return $self->_dberror ('Unable to execute statement', $statement); + or return $self->_dberror('Unable to execute statement', $statement); my @row = $sth->fetchrow_array; @@ -219,29 +220,29 @@ sub _deleteRecord ($;$) { $statement .= "where $condition" if $condition; - $self->{db}->do ($statement); + $self->{db}->do($statement); if ($self->{db}->err) { - return $self->_dberror ("Unable to delete record from $table", $statement); + return $self->_dberror("Unable to delete record from $table", $statement); } else { return $count, 'Records deleted'; } # if } # _deleteRecord -sub _updateRecord ($$%) { +sub _updateRecord($$%) { my ($self, $table, $condition, %rec) = @_; my $statement = "update $table set "; - $statement .= join ',', $self->_formatNameValues (%rec); + $statement .= join ',', $self->_formatNameValues(%rec); $statement .= " where $condition" if $condition; - $self->{db}->do ($statement); + $self->{db}->do($statement); - return $self->_dberror ("Unable to update record in $table", $statement); + return $self->_dberror("Unable to update record in $table", $statement); } # _updateRecord -sub _checkRequiredFields ($$) { +sub _checkRequiredFields($$) { my ($fields, $rec) = @_; for my $fieldname (@$fields) { @@ -261,17 +262,21 @@ sub _checkRequiredFields ($$) { return; } # _checkRequiredFields -sub _getRecords ($$) { - my ($self, $table, $condition) = @_; +sub _getRecords($$;$) { + my ($self, $table, $condition, $additional) = @_; my ($err, $msg); - my $statement = "select * from $table where $condition"; + $additional ||= ''; + + my $statement = "select * from $table"; + $statement .= " where $condition" if $condition; + $statement .= $additional; - my $sth = $self->{db}->prepare ($statement); + my $sth = $self->{db}->prepare($statement); unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); croak $msg; } # if @@ -293,7 +298,7 @@ sub _getRecords ($$) { $err = 0; last; } else { - ($err, $msg) = $self->_dberror ('Unable to execute statement', + ($err, $msg) = $self->_dberror('Unable to execute statement', $statement); } # if @@ -303,16 +308,16 @@ sub _getRecords ($$) { my $timestamp = YMDHMS; - $self->Error ("$timestamp: Unable to talk to DB server.\n\n$msg\n\n" + $self->Error("$timestamp: Unable to talk to DB server.\n\n$msg\n\n" . "Will try again in $sleepTime seconds", -1); # Try to reconnect - $self->_connect ($self->{dbserver}); + $self->_connect($self->{dbserver}); sleep $sleepTime; } # while - $self->Error ("After $maxAttempts attempts I could not connect to the database", $err) + $self->Error("After $maxAttempts attempts I could not connect to the database", $err) if ($err == 2006 and $attempts > $maxAttempts); my @records; @@ -322,12 +327,12 @@ sub _getRecords ($$) { } # while return @records; -} # _getRecord +} # _getRecords -sub _aliasSystem ($) { +sub _aliasSystem($) { my ($self, $system) = @_; - my %system = $self->GetSystem ($system); + my %system = $self->GetSystem($system); if ($system{name}) { return $system{name}; @@ -336,17 +341,17 @@ sub _aliasSystem ($) { } # if } # _aliasSystem -sub _getLastID () { +sub _getLastID() { my ($self) = @_; my $statement = 'select last_insert_id()'; - my $sth = $self->{db}->prepare ($statement); + my $sth = $self->{db}->prepare($statement); my ($err, $msg); unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); croak $msg; } # if @@ -354,7 +359,7 @@ sub _getLastID () { my $status = $sth->execute; unless ($status) { - ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); + ($err, $msg) = $self->_dberror('Unable to execute statement', $statement); croak $msg; } # if @@ -366,7 +371,7 @@ sub _getLastID () { return $row[0]; } # _getLastID -sub _connect (;$) { +sub _connect(;$) { my ($self, $dbserver) = @_; $dbserver ||= $CLEAROPTS{CLEARADM_SERVER}; @@ -374,12 +379,12 @@ sub _connect (;$) { my $dbname = 'clearadm'; my $dbdriver = 'mysql'; - $self->{db} = DBI->connect ( + $self->{db} = DBI->connect( "DBI:$dbdriver:$dbname:$dbserver", $CLEAROPTS{CLEARADM_USERNAME}, $CLEAROPTS{CLEARADM_PASSWORD}, {PrintError => 0}, - ) or croak ( + ) or croak( "Couldn't connect to $dbname database " . "as $CLEAROPTS{CLEARADM_USERNAME}\@$CLEAROPTS{CLEARADM_SERVER}" ); @@ -389,17 +394,17 @@ sub _connect (;$) { return; } # _connect -sub new (;$) { +sub new(;$) { my ($class, $dbserver) = @_; my $self = bless {}, $class; - $self->_connect ($dbserver); + $self->_connect($dbserver); return $self; } # new -sub SetNotify () { +sub SetNotify() { my ($self) = @_; $self->{NOTIFY} = $CLEAROPTS{CLEARADM_NOTIFY}; @@ -407,7 +412,7 @@ sub SetNotify () { return; } # SetNotify -sub Error ($;$) { +sub Error($;$) { my ($self, $msg, $errno) = @_; # If $errno is specified we need to stop. However we need to notify somebody @@ -416,7 +421,7 @@ sub Error ($;$) { if ($errno) { if ($self->{NOTIFY}) { - mail ( + mail( to => $self->{NOTIFY}, subject => 'Internal error occurred in Clearadm', data => "

An unexpected, internal error occurred in Clearadm:

$msg

", @@ -430,7 +435,7 @@ sub Error ($;$) { return; } # Error -sub AddSystem (%) { +sub AddSystem(%) { my ($self, %system) = @_; my @requiredFields = ( @@ -444,28 +449,28 @@ sub AddSystem (%) { $system{loadavgHist} ||= $defaultLoadavgHist; - return $self->_addRecord ('system', %system); + return $self->_addRecord('system', %system); } # AddSystem -sub DeleteSystem ($) { +sub DeleteSystem($) { my ($self, $name) = @_; - return $self->_deleteRecord ('system', "name='$name'"); + return $self->_deleteRecord('system', "name='$name'"); } # DeleteSystem sub UpdateSystem ($%) { my ($self, $name, %update) = @_; - return $self->_updateRecord ('system', "name='$name'", %update); + return $self->_updateRecord('system', "name='$name'", %update); } # UpdateSystem -sub GetSystem ($) { +sub GetSystem($) { my ($self, $system) = @_; return unless $system; - my @records = $self->_getRecords ( + my @records = $self->_getRecords( 'system', "name='$system' or alias like '%$system%'" ); @@ -477,25 +482,25 @@ sub GetSystem ($) { } # if } # GetSystem -sub FindSystem (;$) { +sub FindSystem(;$) { my ($self, $system) = @_; $system ||= ''; my $condition = "name like '%$system%' or alias like '%$system%'"; - return $self->_getRecords ('system', $condition); + return $self->_getRecords('system', $condition); } # FindSystem -sub SearchSystem (;$) { +sub SearchSystem(;$) { my ($self, $condition) = @_; $condition = "name like '%'" unless $condition; - return $self->_getRecords ('system', $condition); + return $self->_getRecords('system', $condition); } # SearchSystem -sub AddPackage (%) { +sub AddPackage(%) { my ($self, %package) = @_; my @requiredFields = ( @@ -509,32 +514,32 @@ sub AddPackage (%) { return -1, "AddPackage: $result" if $result; - return $self->_addRecord ('package', %package); + return $self->_addRecord('package', %package); } # AddPackage -sub DeletePackage ($$) { +sub DeletePackage($$) { my ($self, $system, $name) = @_; - return $self->_deleteRecord ( + return $self->_deleteRecord( 'package', "(system='$system' or alias='$system') and name='$name'"); } # DeletePackage -sub UpdatePackage ($$%) { +sub UpdatePackage($$%) { my ($self, $system, $name, %update) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; - return $self->_updateRecord ('package', "system='$system'", %update); + return $self->_updateRecord('package', "system='$system'", %update); } # UpdatePackage sub GetPackage($$) { my ($self, $system, $name) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; @@ -542,7 +547,7 @@ sub GetPackage($$) { return unless $name; - my @records = $self->_getRecords ( + my @records = $self->_getRecords( 'package', "system='$system' and name='$name'" ); @@ -554,22 +559,22 @@ sub GetPackage($$) { } # if } # GetPackage -sub FindPackage ($;$) { +sub FindPackage($;$) { my ($self, $system, $name) = @_; $name ||= ''; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; my $condition = "system='$system' and name like '%$name%'"; - return $self->_getRecords ('package', $condition); + return $self->_getRecords('package', $condition); } # FindPackage -sub AddFilesystem (%) { +sub AddFilesystem(%) { my ($self, %filesystem) = @_; my @requiredFields = ( @@ -586,42 +591,42 @@ sub AddFilesystem (%) { # Default filesystem threshold $filesystem{threshold} ||= $defaultFilesystemThreshold; - return $self->_addRecord ('filesystem', %filesystem); + return $self->_addRecord('filesystem', %filesystem); } # AddFilesystem -sub DeleteFilesystem ($$) { +sub DeleteFilesystem($$) { my ($self, $system, $filesystem) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; - return $self->_deleteRecord ( + return $self->_deleteRecord( 'filesystem', "system='$system' and filesystem='$filesystem'" ); } # DeleteFilesystem -sub UpdateFilesystem ($$%) { +sub UpdateFilesystem($$%) { my ($self, $system, $filesystem, %update) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; - return $self->_updateRecord ( + return $self->_updateRecord( 'filesystem', "system='$system' and filesystem='$filesystem'", %update ); } # UpdateFilesystem -sub GetFilesystem ($$) { +sub GetFilesystem($$) { my ($self, $system, $filesystem) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; @@ -629,7 +634,7 @@ sub GetFilesystem ($$) { return unless $filesystem; - my @records = $self->_getRecords ( + my @records = $self->_getRecords( 'filesystem', "system='$system' and filesystem='$filesystem'" ); @@ -641,70 +646,92 @@ sub GetFilesystem ($$) { } # if } # GetFilesystem -sub FindFilesystem ($;$) { +sub FindFilesystem($;$) { my ($self, $system, $filesystem) = @_; $filesystem ||= ''; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; my $condition = "system='$system' and filesystem like '%$filesystem%'"; - return $self->_getRecords ('filesystem', $condition); + return $self->_getRecords('filesystem', $condition); } # FindFilesystem -sub AddVob (%) { +sub AddVob(%) { my ($self, %vob) = @_; my @requiredFields = ( - 'system', 'tag', + 'region', ); my $result = _checkRequiredFields \@requiredFields, \%vob; - return -1, "AddVob: $result" - if $result; + return -1, "AddVob: $result" if $result; - return $self->_addRecord ('vob', %vob); + return $self->_addRecord('vob', %vob); } # AddVob -sub DeleteVob ($) { - my ($self, $tag) = @_; +sub DeleteVob($$) { + my ($self, $tag, $region) = @_; - return $self->_deleteRecord ('vob', "tag='$tag'"); + return $self->_deleteRecord('vob', "tag='$tag' and region='$region'"); } # DeleteVob -sub GetVob ($) { - my ($self, $tag) = @_; +sub GetVob($$) { + my ($self, $tag, $region) = @_; - return - unless $tag; + return unless $tag; + + # Windows vob tags begin with "\", which is problematic. The solution is to + # escape the "\" + $tag =~ s/^\\/\\\\/; - my @records = $self->_getRecords ('vob', "tag='$tag'"); + my @records = $self->_getRecords('vob', "tag='$tag' and region='$region'"); if ($records[0]) { return %{$records[0]}; } else { - return; + return; } # if } # GetVob -sub FindVob ($) { - my ($self, $tag) = @_; +sub FindVob($;$) { + my ($self, $tag, $region) = @_; - return $self->_getRecords ('vob', "tag like '%$tag%'"); + # Windows vob tags begin with "\", which is problematic. The solution is to + # escape the "\" + $tag =~ s/^\\/\\\\/; + + my $condition = "tag like '%$tag%'"; + + $condition .= " and region='$region'" if $region; + + return $self->_getRecords('vob', $condition); } # FindVob -sub AddView (%) { +sub UpdateVob(%) { + my ($self, %vob) = @_; + + # Windows vob tags begin with "\", which is problematic. The solution is to + # escape the "\" + my $vobtag = $vob{tag}; + + $vobtag =~ s/^\\/\\\\/; + + return $self->_updateRecord('vob', "tag='$vobtag' and region='$vob{region}'", %vob); +} # UpdateVob + +sub AddView(%) { my ($self, %view) = @_; my @requiredFields = ( - 'system', 'tag', + 'region' ); my $result = _checkRequiredFields \@requiredFields, \%view; @@ -712,31 +739,36 @@ sub AddView (%) { return -1, "AddView: $result" if $result; - return $self->_addRecord ('view', %view); + return $self->_addRecord('view', %view); } # AddView -sub DeleteView ($) { - my ($self, $tag) = @_; +sub DeleteView($$) { + my ($self, $tag, $region) = @_; - return $self->_deleteRecord ('vob', "tag='$tag'"); + return $self->_deleteRecord('vob', "tag='$tag' and region='$region'"); } # DeleteView -sub GetView ($) { - my ($self, $tag) = @_; +sub UpdateView(%) { + my ($self, %view) = @_; + + return $self->_updateRecord('view', "tag='$view{tag}' and region='$view{region}'", %view); +} # UpdateView - return - unless $tag; +sub GetView($$) { + my ($self, $tag, $region) = @_; - my @records = $self->_getRecords ('view', "tag='$tag'"); + return unless $tag; + + my @records = $self->_getRecords('view', "tag='$tag' and region='$region'"); if ($records[0]) { return %{$records[0]}; } else { - return; + return; } # if } # GetView -sub FindView (;$$$$) { +sub FindView(;$$$$) { my ($self, $system, $region, $tag, $ownerName) = @_; $system ||= ''; @@ -754,10 +786,10 @@ sub FindView (;$$$$) { $condition .= ' and '; $condition .= "ownerName like '%$ownerName'"; - return $self->_getRecords ('view', $condition); + return $self->_getRecords('view', $condition); } # FindView -sub AddFS (%) { +sub AddFS(%) { my ($self, %fs) = @_; my @requiredFields = ( @@ -773,20 +805,20 @@ sub AddFS (%) { # Timestamp record $fs{timestamp} = Today2SQLDatetime; - return $self->_addRecord ('fs', %fs); + return $self->_addRecord('fs', %fs); } # AddFS -sub TrimFS ($$) { +sub TrimFS($$) { my ($self, $system, $filesystem) = @_; - my %filesystem = $self->GetFilesystem ($system, $filesystem); + my %filesystem = $self->GetFilesystem($system, $filesystem); return unless %filesystem; - my %task = $self->GetTask ('scrub'); + my %task = $self->GetTask('scrub'); - $self->Error ("Unable to find scrub task!", 1) unless %task; + $self->Error("Unable to find scrub task!", 1) unless %task; my $days; my $today = Today2SQLDatetime; @@ -801,7 +833,7 @@ sub TrimFS ($$) { my $oldage = SubtractDays $today, $days; - my ($dberr, $dbmsg) = $self->_deleteRecord ( + my ($dberr, $dbmsg) = $self->_deleteRecord( 'fs', "system='$system' and filesystem='$filesystem' and timestamp<='$oldage'" ); @@ -818,25 +850,25 @@ sub TrimFS ($$) { $runlog{message} = "Scrubbed $dberr fs records for filesystem $system:$filesystem"; - my ($err, $msg) = $self->AddRunlog (%runlog); + my ($err, $msg) = $self->AddRunlog(%runlog); - $self->Error ("Unable to add runlog - (Error: $err)\n$msg") if $err; + $self->Error("Unable to add runlog - (Error: $err)\n$msg") if $err; } # if return ($dberr, $dbmsg); } # TrimFS -sub TrimLoadavg ($) { +sub TrimLoadavg($) { my ($self, $system) = @_; - my %system = $self->GetSystem ($system); + my %system = $self->GetSystem($system); return unless %system; - my %task = $self->GetTask ('loadavg'); + my %task = $self->GetTask('loadavg'); - $self->Error ("Unable to find loadavg task!", 1) unless %task; + $self->Error("Unable to find loadavg task!", 1) unless %task; my $days; my $today = Today2SQLDatetime; @@ -851,7 +883,7 @@ sub TrimLoadavg ($) { my $oldage = SubtractDays $today, $days; - my ($dberr, $dbmsg) = $self->_deleteRecord ( + my ($dberr, $dbmsg) = $self->_deleteRecord( 'loadavg', "system='$system' and timestamp<='$oldage'" ); @@ -868,18 +900,18 @@ sub TrimLoadavg ($) { $runlog{message} = "Scrubbed $dberr loadavg records for system $system"; - my ($err, $msg) = $self->AddRunlog (%runlog); + my ($err, $msg) = $self->AddRunlog(%runlog); - $self->Error ("Unable to add runload (Error: $err)\n$msg") if $err; + $self->Error("Unable to add runload (Error: $err)\n$msg") if $err; } # if return ($dberr, $dbmsg); } # TrimLoadavg -sub GetFS ($$;$$$$) { +sub GetFS($$;$$$$) { my ($self, $system, $filesystem, $start, $end, $count, $interval) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; @@ -912,7 +944,7 @@ sub GetFS ($$;$$$$) { # returns 40 rows we'll see only rows 1-10, not rows 31-40). We need limit # $offset, $count where $offset = the number of qualifying records minus # $count - my $nbrRecs = $self->Count ('fs', $condition); + my $nbrRecs = $self->Count('fs', $condition); my $offset = $nbrRecs - $count; # Offsets of < 0 are not allowed. @@ -939,10 +971,10 @@ END my ($err, $msg); - my $sth = $self->{db}->prepare ($statement); + my $sth = $self->{db}->prepare($statement); unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); croak $msg; } # if @@ -950,7 +982,7 @@ END my $status = $sth->execute; unless ($status) { - ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); + ($err, $msg) = $self->_dberror('Unable to execute statement', $statement); croak $msg; } # if @@ -964,10 +996,10 @@ END return @records; } # GetFS -sub GetLatestFS ($$) { +sub GetLatestFS($$) { my ($self, $system, $filesystem) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; @@ -975,7 +1007,7 @@ sub GetLatestFS ($$) { return unless $filesystem; - my @records = $self->_getRecords ( + my @records = $self->_getRecords( 'fs', "system='$system' and filesystem='$filesystem'" . " order by timestamp desc limit 0, 1", @@ -988,7 +1020,7 @@ sub GetLatestFS ($$) { } # if } # GetLatestFS -sub AddLoadavg () { +sub AddLoadavg() { my ($self, %loadavg) = @_; my @requiredFields = ( @@ -1003,13 +1035,13 @@ sub AddLoadavg () { # Timestamp record $loadavg{timestamp} = Today2SQLDatetime; - return $self->_addRecord ('loadavg', %loadavg); + return $self->_addRecord('loadavg', %loadavg); } # AddLoadavg -sub GetLoadavg ($;$$$$) { +sub GetLoadavg($;$$$$) { my ($self, $system, $start, $end, $count, $interval) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; @@ -1041,7 +1073,7 @@ sub GetLoadavg ($;$$$$) { # returns 40 rows we'll see only rows 1-10, not rows 31-40). We need limit # $offset, $count where $offset = the number of qualifying records minus # $count - my $nbrRecs = $self->Count ('loadavg', $condition); + my $nbrRecs = $self->Count('loadavg', $condition); my $offset = $nbrRecs - $count; # Offsets of < 0 are not allowed. @@ -1065,10 +1097,10 @@ END my ($err, $msg); - my $sth = $self->{db}->prepare ($statement); + my $sth = $self->{db}->prepare($statement); unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); croak $msg; } # if @@ -1076,7 +1108,7 @@ END my $status = $sth->execute; unless ($status) { - ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); + ($err, $msg) = $self->_dberror('Unable to execute statement', $statement); croak $msg; } # if @@ -1090,15 +1122,15 @@ END return @records; } # GetLoadvg -sub GetLatestLoadavg ($) { +sub GetLatestLoadavg($) { my ($self, $system) = @_; - $system = $self->_aliasSystem ($system); + $system = $self->_aliasSystem($system); return unless $system; - my @records = $self->_getRecords ( + my @records = $self->_getRecords( 'loadavg', "system='$system'" . " order by timestamp desc limit 0, 1", @@ -1111,7 +1143,92 @@ sub GetLatestLoadavg ($) { } # if } # GetLatestLoadavg -sub AddTask (%) { +sub GetStorage($$$;$$$$$) { + my ($self, $type, $tag, $storage, $region, $start, $end, $count, $interval) = @_; + + $interval ||= 'Day'; + $region ||= $Clearcase::CC->region; + + return unless $type =~ /vob/i or $type =~ /view/; + + my $size = $interval =~ /month/i + ? 7 + : $interval =~ /day/i + ? 10 + : $interval =~ /hour/i + ? 13 + : 16; + + undef $start if $start and $start =~ /earliest/i; + undef $end if $end and $end =~ /latest/i; + + # Windows vob tags begin with "\", which is problematic. The solution is to + # escape the "\" + $tag =~ s/^\\/\\\\/; + + my $condition; + my $table = $type eq 'vob' ? 'vobstorage' : 'viewstorage'; + + $condition = "tag='$tag' and region='$region'"; + $condition .= " and timestamp>='$start'" if $start; + $condition .= " and timestamp<='$end'" if $end; + + $condition .= " group by left(timestamp,$size)"; + + if ($count) { + # We can't simply do a "limit 0, $count" as that just gets the front end of + # the records return (i.e. if $count = say 10 and the timestamp range + # returns 40 rows we'll see only rows 1-10, not rows 31-40). We need limit + # $offset, $count where $offset = the number of qualifying records minus + # $count + my $nbrRecs = $self->Count($table, $condition); + my $offset = $nbrRecs - $count; + + # Offsets of < 0 are not allowed. + $offset = 0 if $offset < 0; + + $condition .= " limit $offset, $count"; + } # if + + my $statement = <<"END"; +select + tag, + region, + left(timestamp,$size) as timestamp, + avg($storage) as size +from + $table + where $condition +END + + my ($err, $msg); + + my $sth = $self->{db}->prepare($statement); + + unless ($sth) { + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); + + croak $msg; + } # if + + my $status = $sth->execute; + + unless ($status) { + ($err, $msg) = $self->_dberror('Unable to execute statement', $statement); + + croak $msg; + } # if + + my @records; + + while (my $row = $sth->fetchrow_hashref) { + push @records, $row; + } # while + + return @records; +} # GetStorage + +sub AddTask(%) { my ($self, %task) = @_; my @requiredFields = ( @@ -1124,32 +1241,32 @@ sub AddTask (%) { return -1, "AddTask: $result" if $result; - return $self->_addRecord ('task', %task); + return $self->_addRecord('task', %task); } # AddTask -sub DeleteTask ($) { +sub DeleteTask($) { my ($self, $name) = @_; - return $self->_deleteRecord ('task', "name='$name'"); + return $self->_deleteRecord('task', "name='$name'"); } # DeleteTask -sub FindTask ($) { +sub FindTask($) { my ($self, $name) = @_; $name ||= ''; my $condition = "name like '%$name%'"; - return $self->_getRecords ('task', $condition); + return $self->_getRecords('task', $condition); } # FindTask -sub GetTask ($) { +sub GetTask($) { my ($self, $name) = @_; return unless $name; - my @records = $self->_getRecords ('task', "name='$name'"); + my @records = $self->_getRecords('task', "name='$name'"); if ($records[0]) { return %{$records[0]}; @@ -1158,13 +1275,13 @@ sub GetTask ($) { } # if } # GetTask -sub UpdateTask ($%) { +sub UpdateTask($%) { my ($self, $name, %update) = @_; - return $self->_updateRecord ('task', "name='$name'", %update); + return $self->_updateRecord('task', "name='$name'", %update); } # Update -sub AddSchedule (%) { +sub AddSchedule(%) { my ($self, %schedule) = @_; my @requiredFields = ( @@ -1176,16 +1293,16 @@ sub AddSchedule (%) { return -1, "AddSchedule: $result" if $result; - return $self->_addRecord ('schedule', %schedule); + return $self->_addRecord('schedule', %schedule); } # AddSchedule -sub DeleteSchedule ($) { +sub DeleteSchedule($) { my ($self, $name) = @_; - return $self->_deleteRecord ('schedule', "name='$name'"); + return $self->_deleteRecord('schedule', "name='$name'"); } # DeleteSchedule -sub FindSchedule (;$$) { +sub FindSchedule(;$$) { my ($self, $name, $task) = @_; $name ||= ''; @@ -1195,13 +1312,13 @@ sub FindSchedule (;$$) { $condition .= ' and '; $condition .= "task like '%$task%'"; - return $self->_getRecords ('schedule', $condition); + return $self->_getRecords('schedule', $condition); } # FindSchedule -sub GetSchedule ($) { +sub GetSchedule($) { my ($self, $name) = @_; - my @records = $self->_getRecords ('schedule', "name='$name'"); + my @records = $self->_getRecords('schedule', "name='$name'"); if ($records[0]) { return %{$records[0]}; @@ -1210,13 +1327,13 @@ sub GetSchedule ($) { } # if } # GetSchedule -sub UpdateSchedule ($%) { +sub UpdateSchedule($%) { my ($self, $name, %update) = @_; - return $self->_updateRecord ('schedule', "name='$name'", %update); + return $self->_updateRecord('schedule', "name='$name'", %update); } # UpdateSchedule -sub AddRunlog (%) { +sub AddRunlog(%) { my ($self, %runlog) = @_; my @requiredFields = ( @@ -1230,64 +1347,68 @@ sub AddRunlog (%) { $runlog{ended} = Today2SQLDatetime; - my ($err, $msg) = $self->_addRecord ('runlog', %runlog); + $runlog{system} = hostname if $runlog{system} =~ /localhost/i; + + my ($err, $msg) = $self->_addRecord('runlog', %runlog); return ($err, $msg, $self->_getLastID); } # AddRunlog -sub DeleteRunlog ($) { +sub DeleteRunlog($) { my ($self, $condition) = @_; - return $self->_deleteRecord ('runlog', $condition); + return $self->_deleteRecord('runlog', $condition); } # DeleteRunlog -sub FindRunlog (;$$$$$$) { +sub FindRunlog(;$$$$$$) { my ($self, $task, $system, $status, $id, $start, $page) = @_; - $task ||= ''; - # If ID is specified then that's all that really matters as it uniquely # identifies a runlog entry; - my $condition; + my ($condition, $conditions); + my $limit = ''; unless ($id) { - $condition = "task like '%$task%'"; + if ($task !~ /all/i) { + $conditions++; + $condition = "task like '%$task%'"; + } # if - if ($system) { - $condition .= " and system like '%$system%'" - unless $system eq 'All'; - } else { - $condition .= ' and system is null'; - } # unless + if ($system !~ /all/i) { + $condition .= ' and ' if $conditions; + $condition .= "system like '%$system%'"; + $conditions++; + } # if + + if ($status) { + $condition .= ' and ' if $conditions; - if (defined $status) { if ($status =~ /!(-*\d+)/) { - $condition .= " and status<>$1"; + $condition .= "status<>$1"; } else { - $condition .= " and status=$status" + $condition .= "status=$status" } # if } # if - $condition .= " order by started desc"; - + # Need defined here as $start may be 0! if (defined $start) { $page ||= 10; - $condition .= " limit $start, $page"; + $limit = "limit $start, $page"; } # unless } else { $condition = "id=$id"; } # unless - return $self->_getRecords ('runlog', $condition); + return $self->_getRecords('runlog', $condition, " order by started desc $limit"); } # FindRunlog -sub GetRunlog ($) { +sub GetRunlog($) { my ($self, $id) = @_; return unless $id; - my @records = $self->_getRecords ('runlog', "id=$id"); + my @records = $self->_getRecords('runlog', "id=$id"); if ($records[0]) { return %{$records[0]}; @@ -1296,13 +1417,13 @@ sub GetRunlog ($) { } # if } # GetRunlog -sub UpdateRunlog ($%) { +sub UpdateRunlog($%) { my ($self, $id, %update) = @_; - return $self->_updateRecord ('runlog', "id=$id", %update); + return $self->_updateRecord('runlog', "id=$id", %update); } # UpdateRunlog -sub Count ($;$) { +sub Count($;$) { my ($self, $table, $condition) = @_; $condition = $condition ? 'where ' . $condition : ''; @@ -1311,10 +1432,10 @@ sub Count ($;$) { my $statement = "select count(*) from $table $condition"; - my $sth = $self->{db}->prepare ($statement); + my $sth = $self->{db}->prepare($statement); unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); croak $msg; } # if @@ -1322,7 +1443,7 @@ sub Count ($;$) { my $status = $sth->execute; unless ($status) { - ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); + ($err, $msg) = $self->_dberror('Unable to execute statement', $statement); croak $msg; } # if @@ -1363,7 +1484,7 @@ sub Count ($;$) { # execute the work to be done, timing it, and subtracting it from the $sleep # time returned. If the caller exhausts the $sleep time then they should call # us again. -sub GetWork () { +sub GetWork() { my ($self) = @_; my ($err, $msg); @@ -1386,10 +1507,10 @@ where order by lastrun END - my $sth = $self->{db}->prepare ($statement); + my $sth = $self->{db}->prepare($statement); unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); croak $msg; } # if @@ -1397,7 +1518,7 @@ END my $status = $sth->execute; unless ($status) { - ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); + ($err, $msg) = $self->_dberror('Unable to execute statement', $statement); croak $msg; } # if @@ -1407,7 +1528,7 @@ END while (my $row = $sth->fetchrow_hashref) { if ($$row{system} !~ /localhost/i) { - my %system = $self->GetSystem ($$row{system}); + my %system = $self->GetSystem($$row{system}); # Skip inactive systems next if $system{active} eq 'false'; @@ -1436,8 +1557,8 @@ END } # if my $today = Today2SQLDatetime; - my $lastrun = Add ($$row{lastrun}, (seconds => $seconds)); - my $waitTime = DateToEpoch ($lastrun) - DateToEpoch ($today); + my $lastrun = Add($$row{lastrun}, (seconds => $seconds)); + my $waitTime = DateToEpoch($lastrun) - DateToEpoch($today); if ($waitTime < 0) { # We're late - push this onto records and move on @@ -1462,17 +1583,17 @@ END return ($sleep, @records); } # GetWork -sub GetUniqueList ($$) { +sub GetUniqueList($$) { my ($self, $table, $field) = @_; my ($err, $msg); my $statement = "select $field from $table group by $field"; - my $sth = $self->{db}->prepare ($statement); + my $sth = $self->{db}->prepare($statement); unless ($sth) { - ($err, $msg) = $self->_dberror ('Unable to prepare statement', $statement); + ($err, $msg) = $self->_dberror('Unable to prepare statement', $statement); croak $msg; } # if @@ -1480,7 +1601,7 @@ sub GetUniqueList ($$) { my $status = $sth->execute; unless ($status) { - ($err, $msg) = $self->_dberror ('Unable to execute statement', $statement); + ($err, $msg) = $self->_dberror('Unable to execute statement', $statement); croak $msg; } # if @@ -1511,32 +1632,32 @@ sub AddAlert(%) { return -1, "AddAlert: $result" if $result; - return $self->_addRecord ('alert', %alert); + return $self->_addRecord('alert', %alert); } # AddAlert -sub DeleteAlert ($) { +sub DeleteAlert($) { my ($self, $name) = @_; - return $self->_deleteRecord ('alert', "name='$name'"); + return $self->_deleteRecord('alert', "name='$name'"); } # DeleteAlert -sub FindAlert (;$) { +sub FindAlert(;$) { my ($self, $alert) = @_; $alert ||= ''; my $condition = "name like '%$alert%'"; - return $self->_getRecords ('alert', $condition); + return $self->_getRecords('alert', $condition); } # FindAlert -sub GetAlert ($) { +sub GetAlert($) { my ($self, $name) = @_; return unless $name; - my @records = $self->_getRecords ('alert', "name='$name'"); + my @records = $self->_getRecords('alert', "name='$name'"); if ($records[0]) { return %{$records[0]}; @@ -1545,7 +1666,7 @@ sub GetAlert ($) { } # if } # GetAlert -sub SendAlert ($$$$$$$) { +sub SendAlert($$$$$$$) { my ( $self, $alert, @@ -1563,12 +1684,12 @@ sub SendAlert ($$$$$$$) { $footing .= "Clearadm
"; $footing .= "Copyright © $year, ClearSCM, Inc. - All rights reserved"; - my %alert = $self->GetAlert ($alert); + my %alert = $self->GetAlert($alert); if ($alert{type} eq 'email') { my $from = 'Clearadm@' . hostdomain; - mail ( + mail( from => $from, to => $to, subject => "Clearadm Alert: $system: $subject", @@ -1577,7 +1698,7 @@ sub SendAlert ($$$$$$$) { footing => $footing, ); } else { - $self->Error ("Don't know how to send $alert{type} alerts\n" + $self->Error("Don't know how to send $alert{type} alerts\n" . "Subject: $subject\n" . "Message: $message", 1); } # if @@ -1592,10 +1713,10 @@ sub SendAlert ($$$$$$$) { message => $subject, ); - return $self->AddAlertlog (%alertlog); + return $self->AddAlertlog(%alertlog); } # SendAlert -sub GetLastAlert ($$) { +sub GetLastAlert($$) { my ($self, $notification, $system) = @_; my $statement = <<"END"; @@ -1613,11 +1734,11 @@ limit 0, 1 END - my $sth = $self->{db}->prepare ($statement) - or return $self->_dberror ('Unable to prepare statement', $statement); + my $sth = $self->{db}->prepare($statement) + or return $self->_dberror('Unable to prepare statement', $statement); $sth->execute - or return $self->_dberror ('Unable to execute statement', $statement); + or return $self->_dberror('Unable to execute statement', $statement); my $alertlog= $sth->fetchrow_hashref; @@ -1630,7 +1751,7 @@ END } # if } # GetLastAlert -sub GetLastTaskFailure ($$) { +sub GetLastTaskFailure($$) { my ($self, $task, $system) = @_; my $statement = <<"END"; @@ -1650,11 +1771,11 @@ limit 0, 1 END - my $sth = $self->{db}->prepare ($statement) - or return $self->_dberror ('Unable to prepare statement', $statement); + my $sth = $self->{db}->prepare($statement) + or return $self->_dberror('Unable to prepare statement', $statement); $sth->execute - or return $self->_dberror ('Unable to execute statement', $statement); + or return $self->_dberror('Unable to execute statement', $statement); my $runlog= $sth->fetchrow_hashref; @@ -1682,11 +1803,11 @@ limit 0, 1 END - $sth = $self->{db}->prepare ($statement) - or return $self->_dberror ('Unable to prepare statement', $statement); + $sth = $self->{db}->prepare($statement) + or return $self->_dberror('Unable to prepare statement', $statement); $sth->execute - or return $self->_dberror ('Unable to execute statement', $statement); + or return $self->_dberror('Unable to execute statement', $statement); $runlog = $sth->fetchrow_hashref; @@ -1699,7 +1820,7 @@ END } # if } # GetLastTaskFailure -sub Notify ($$$$$$) { +sub Notify($$$$$$) { my ( $self, $notification, @@ -1718,44 +1839,44 @@ sub Notify ($$$$$$) { # Update filesystem, if $filesystem was specified if ($filesystem) { - ($err, $msg) = $self->UpdateFilesystem ( + ($err, $msg) = $self->UpdateFilesystem( $system, $filesystem, ( notification => $notification, ), ); - $self->Error ("Unable to set notification for filesystem $system:$filesystem " + $self->Error("Unable to set notification for filesystem $system:$filesystem " . "(Status: $err)\n$msg", $err) if $err; } # if # Update system - ($err, $msg) = $self->UpdateSystem ( + ($err, $msg) = $self->UpdateSystem( $system, ( notification => $notification, ), ); - my %notification = $self->GetNotification ($notification); + my %notification = $self->GetNotification($notification); - my %lastnotified = $self->GetLastAlert ($notification, $system); + my %lastnotified = $self->GetLastAlert($notification, $system); if (%lastnotified and $lastnotified{timestamp}) { my $today = Today2SQLDatetime; my $lastnotified = $lastnotified{timestamp}; if ($notification{nomorethan} =~ /hour/i) { - $lastnotified = Add ($lastnotified, (hours => 1)); + $lastnotified = Add($lastnotified, (hours => 1)); } elsif ($notification{nomorethan} =~ /day/i) { - $lastnotified = Add ($lastnotified, (days => 1)); + $lastnotified = Add($lastnotified, (days => 1)); } elsif ($notification{nomorethan} =~ /week/i) { - $lastnotified = Add ($lastnotified, (days => 7)); + $lastnotified = Add($lastnotified, (days => 7)); } elsif ($notification{nomorethan} =~ /month/i) { - $lastnotified = Add ($lastnotified, (month => 1)); + $lastnotified = Add($lastnotified, (month => 1)); } # if # If you want to fake an alert in the debugger just change $diff accordingly - my $diff = Compare ($today, $lastnotified); + my $diff = Compare($today, $lastnotified); return if $diff <= 0; @@ -1763,14 +1884,14 @@ sub Notify ($$$$$$) { my $when = Today2SQLDatetime; my $nomorethan = lc $notification{nomorethan}; - my %alert = $self->GetAlert ($notification{alert}); + my %alert = $self->GetAlert($notification{alert}); my $to = $alert{who}; # If $to is null then this means to send the alert to the admin for the # machine. unless ($to) { if ($system) { - my %system = $self->GetSystem ($system); + my %system = $self->GetSystem($system); $to = $system{email}; } else { @@ -1787,7 +1908,7 @@ sub Notify ($$$$$$) { $message .= "

You will receive this alert no more than $nomorethan.

"; - ($err, $msg) = $self->SendAlert ( + ($err, $msg) = $self->SendAlert( $notification{alert}, $system, $notification{name}, @@ -1797,29 +1918,29 @@ sub Notify ($$$$$$) { $runlogID, ); - $self->Error ("Unable to send alert (Status: $err)\n$msg", $err) if $err; + $self->Error("Unable to send alert (Status: $err)\n$msg", $err) if $err; verbose "Sent alert to $to"; # Update runlog to indicate we notified the user for this execution - ($err, $msg) = $self->UpdateRunlog ( + ($err, $msg) = $self->UpdateRunlog( $runlogID, ( alerted => 'true', ), ); - $self->Error ("Unable to update runlog (Status: $err)\n$msg", $err) if $err; + $self->Error("Unable to update runlog (Status: $err)\n$msg", $err) if $err; return; } # Notify -sub ClearNotifications ($$;$) { +sub ClearNotifications($$;$) { my ($self, $system, $filesystem) = @_; my ($err, $msg); if ($filesystem) { - ($err, $msg) = $self->UpdateFilesystem ( + ($err, $msg) = $self->UpdateFilesystem( $system, $filesystem, (notification => undef), ); @@ -1834,12 +1955,12 @@ sub ClearNotifications ($$;$) { # 'Filesystem' then we can toggle off the notification on the system too my $filesystemsAlerted = 0; - for ($self->FindFilesystem ($system)) { + for ($self->FindFilesystem($system)) { $filesystemsAlerted++ if $$_{notification}; } # for - my %system = $self->GetSystem ($system); + my %system = $self->GetSystem($system); return unless $system; @@ -1847,22 +1968,22 @@ sub ClearNotifications ($$;$) { if ($system{notification} and $system{notification} eq 'Filesystem' and $filesystemsAlerted == 0) { - ($err, $msg) = $self->UpdateSystem ($system, (notification => undef)); + ($err, $msg) = $self->UpdateSystem($system, (notification => undef)); - $self->Error ("Unable to clear notification for system $system " + $self->Error("Unable to clear notification for system $system " . "(Status: $err)\n$msg", $err) if $err; } # if } else { - ($err, $msg) = $self->UpdateSystem ($system, (notification => undef)); + ($err, $msg) = $self->UpdateSystem($system, (notification => undef)); - $self->Error ("Unable to clear notification for system $system " + $self->Error("Unable to clear notification for system $system " . "(Status: $err)\n$msg", $err) if $err; } # if return; } # ClearNotifications -sub SystemAlive (%) { +sub SystemAlive(%) { my ($self, %system) = @_; # If we've never heard from this system then we will assume that the system @@ -1881,10 +2002,10 @@ sub SystemAlive (%) { my $tenMinutes = 10 * 60; - $lastheardfrom = Add ($lastheardfrom, (seconds => $tenMinutes)); + $lastheardfrom = Add($lastheardfrom, (seconds => $tenMinutes)); - if (DateToEpoch ($lastheardfrom) < DateToEpoch ($today)) { - $self->UpdateSystem ( + if (DateToEpoch($lastheardfrom) < DateToEpoch($today)) { + $self->UpdateSystem( $system{name}, ( notification => 'Heartbeat' ), @@ -1893,7 +2014,7 @@ sub SystemAlive (%) { return; } else { if ($system{notification}) { - $self->UpdateSystem ( + $self->UpdateSystem( $system{name}, ( notification => undef ), @@ -1903,17 +2024,17 @@ sub SystemAlive (%) { } # if } # SystemAlive -sub UpdateAlert ($%) { +sub UpdateAlert($%) { my ($self, $name, %update) = @_; - return $self->_updateRecord ( + return $self->_updateRecord( 'alert', "name='$name'", %update ); } # UpdateAlert -sub AddAlertlog (%) { +sub AddAlertlog(%) { my ($self, %alertlog) = @_; my @requiredFields = ( @@ -1929,23 +2050,23 @@ sub AddAlertlog (%) { # Timestamp record $alertlog{timestamp} = Today2SQLDatetime; - return $self->_addRecord ('alertlog', %alertlog); + return $self->_addRecord('alertlog', %alertlog); } # AddAlertlog -sub DeleteAlertlog ($) { +sub DeleteAlertlog($) { my ($self, $condition) = @_; return unless $condition; if ($condition =~ /all/i) { - return $self->_deleteRecord ('alertlog'); + return $self->_deleteRecord('alertlog'); } else { - return $self->_deleteRecord ('alertlog', $condition); + return $self->_deleteRecord('alertlog', $condition); } # if } # DeleteAlertlog -sub FindAlertlog (;$$$$$) { +sub FindAlertlog(;$$$$$) { my ($self, $alert, $system, $notification, $start, $page) = @_; $alert ||= ''; @@ -1964,16 +2085,16 @@ sub FindAlertlog (;$$$$$) { $condition .= " limit $start, $page"; } # unless - return $self->_getRecords ('alertlog', $condition); + return $self->_getRecords('alertlog', $condition); } # FindAlertLog -sub GetAlertlog ($) { +sub GetAlertlog($) { my ($self, $alert) = @_; return unless $alert; - my @records = $self->_getRecords ('alertlog', "alert='$alert'"); + my @records = $self->_getRecords('alertlog', "alert='$alert'"); if ($records[0]) { return %{$records[0]}; @@ -1982,17 +2103,17 @@ sub GetAlertlog ($) { } # if } # GetAlertlog -sub UpdateAlertlog ($%) { +sub UpdateAlertlog($%) { my ($self, $alert, %update) = @_; - return $self->_updateRecord ( + return $self->_updateRecord( 'alertlog', "alert='$alert'", %update ); } # UpdateAlertlog -sub AddNotification (%) { +sub AddNotification(%) { my ($self, %notification) = @_; my @requiredFields = ( @@ -2006,16 +2127,16 @@ sub AddNotification (%) { return -1, "AddNotification: $result" if $result; - return $self->_addRecord ('notification', %notification); + return $self->_addRecord('notification', %notification); } # AddNotification -sub DeleteNotification ($) { +sub DeleteNotification($) { my ($self, $name) = @_; - return $self->_deleteRecord ('notification', "name='$name'"); + return $self->_deleteRecord('notification', "name='$name'"); } # DeletePackage -sub FindNotification (;$$) { +sub FindNotification(;$$) { my ($self, $name, $cond, $ordering) = @_; $name ||= ''; @@ -2024,16 +2145,16 @@ sub FindNotification (;$$) { $condition .= " and $cond" if $cond; - return $self->_getRecords ('notification', $condition); + return $self->_getRecords('notification', $condition); } # FindNotification -sub GetNotification ($) { +sub GetNotification($) { my ($self, $name) = @_; return unless $name; - my @records = $self->_getRecords ('notification', "name='$name'"); + my @records = $self->_getRecords('notification', "name='$name'"); if ($records[0]) { return %{$records[0]}; @@ -2042,16 +2163,50 @@ sub GetNotification ($) { } # if } # GetNotification -sub UpdateNotification ($%) { +sub UpdateNotification($%) { my ($self, $name, %update) = @_; - return $self->_updateRecord ( + return $self->_updateRecord( 'notification', "name='$name'", %update ); } # UpdateNotification +sub AddVobStorage(%) { + my ($self, %vobstorage) = @_; + + my @requiredFields = ( + 'tag', + ); + + my $result = _checkRequiredFields \@requiredFields, \%vobstorage; + + return -1, "AddVobStorage: $result" if $result; + + # Timestamp record + $vobstorage{timestamp} = Today2SQLDatetime; + + return $self->_addRecord('vobstorage', %vobstorage); +} # AddVobStorage + +sub AddViewStorage(%) { + my ($self, %viewstorage) = @_; + + my @requiredFields = ( + 'tag', + ); + + my $result = _checkRequiredFields \@requiredFields, \%viewstorage; + + return -1, "AddViewStorage: $result" if $result; + + # Timestamp record + $viewstorage{timestamp} = Today2SQLDatetime; + + return $self->_addRecord('viewstorage', %viewstorage); +} # AddViewStorage + 1; =pod diff --git a/clearadm/lib/ClearadmWeb.pm b/clearadm/lib/ClearadmWeb.pm index 17ccb6e..c776c82 100644 --- a/clearadm/lib/ClearadmWeb.pm +++ b/clearadm/lib/ClearadmWeb.pm @@ -73,6 +73,8 @@ use FindBin; use lib "$FindBin::Bin/../../lib"; use Clearadm; +use Clearcase::Vobs; +use Clearcase::Views; use DateUtils; use Display; use Utils; @@ -109,7 +111,9 @@ our @EXPORT = qw ( makeFilesystemDropdown makeIntervalDropdown makeNotificationDropdown + makeStoragePoolDropdown makeSystemDropdown + makeTagsDropdown makeTimeDropdown makeTaskDropdown setField @@ -121,25 +125,28 @@ our @PREDEFINED_ALERTS = ( ); our @PREDEFINED_NOTIFICATIONS = ( + 'Clearcase Storage', + 'Heartbeat', 'Loadavg', 'Filesystem', 'Scrub', - 'Heartbeat', 'System checkin', 'Update systems', ); our @PREDEFINED_TASKS = ( - 'Loadavg', + 'Clearcase Storage', 'Filesystem', + 'Loadavg', 'Scrub', 'System checkin', 'Update systems', ); our @PREDEFINED_SCHEDULES = ( - 'Loadavg', + 'Clearcase Storage', 'Filesystem', + 'Loadavg', 'Scrub', 'Update systems', ); @@ -188,7 +195,7 @@ sub setFields ($%) { my ($label, %rec) = @_; $rec{$_} = setField ($rec{$_}, $label) - foreach keys %rec; + for keys %rec; return %rec; } # setFields; @@ -196,9 +203,9 @@ sub setFields ($%) { sub dumpVars (%) { my (%vars) = @_; - foreach (keys %vars) { + for (keys %vars) { dbug "$_: $vars{$_}"; - } # foreach + } # for return; } # dumpVars @@ -259,7 +266,7 @@ sub _makeAlertlogSelection ($$) { $values{All} = 'All'; $values{$$_{$name}} = $$_{$name} - foreach ($clearadm->FindAlertlog); + for ($clearadm->FindAlertlog); my $dropdown = popup_menu { name => $name, @@ -282,13 +289,13 @@ sub _makeRunlogSelection ($$) { my %values; - foreach (@values) { + for (@values) { unless ($_ eq '') { $values{$_} = $_; } else { $values{NULL} = ''; } #if - } # foreach + } # for my $dropdown = popup_menu { name => $name, @@ -328,7 +335,7 @@ sub makeAlertDropdown (;$$) { my @values; push @values, $$_{name} - foreach ($clearadm->FindAlert); + for ($clearadm->FindAlert); my $dropdown = "$label "; $dropdown .= popup_menu { @@ -373,6 +380,57 @@ sub makeNoMoreThanDropdown (;$$) { return $dropdown; } # makeNoMorThanDropdown +sub makeTagsDropdown($$) { + my ($type, $tag) = @_; + + my $dropdown = ucfirst $type . ' '; + + if ($type eq 'vob') { + my $vobs = Clearcase::Vobs->new; + + $dropdown .= popup_menu { + name => 'tag', + class => 'dropdown', + values => [sort $vobs->vobs], + default => $tag, + }; + } else { + my $views = Clearcase::Views->new; + + $dropdown .= popup_menu { + name => 'tag', + class => 'dropdown', + values => [sort $views->views], + default => $tag, + }; + } # if + + return span {id => $type}, $dropdown; +} # makeTagsDropdown + +sub makeStoragePoolDropdown($$) { + my ($type, $tag) = @_; + + my @values; + + my $dropdown = 'Storage pool '; + + if ($type eq 'vob') { + push @values, qw(admin db cleartext derivedobj source total); + } else { + push @values, qw(admin db private total); + } # if + + $dropdown .= popup_menu { + name => 'storage', + class => 'dropdown', + values => \@values, + default => $tag, + }; + + return span {id => $type}, $dropdown; +} # makeStoragePoolsDropdown + sub makeFilesystemDropdown ($;$$$) { my ($system, $label, $default, $onchange) = @_; @@ -380,13 +438,13 @@ sub makeFilesystemDropdown ($;$$$) { my %filesystems; - foreach ($clearadm->FindFilesystem ($system)) { + for ($clearadm->FindFilesystem ($system)) { my %filesystem = %{$_}; my $value = "$filesystem{filesystem} ($filesystem{mount})"; $filesystems{$filesystem{filesystem}} = $value; - } # foreach + } # for my $dropdown .= "$label "; $dropdown .= popup_menu { @@ -437,7 +495,7 @@ sub makeNotificationDropdown (;$$) { my @values; push @values, $$_{name} - foreach ($clearadm->FindNotification); + for ($clearadm->FindNotification); my $dropdown = "$label "; $dropdown .= popup_menu { @@ -476,14 +534,14 @@ sub makeSystemDropdown (;$$$%) { $label ||= ''; - foreach ($clearadm->FindSystem) { + for ($clearadm->FindSystem) { my %system = %{$_}; my $value = $system{name}; $value .= $system{alias} ? " ($system{alias})" : ''; $systems{$system{name}} = $value; - } # foreach + } # for my $systemDropdown .= "$label "; $systemDropdown .= popup_menu { @@ -506,7 +564,7 @@ sub makeTaskDropdown (;$$) { my @values; push @values, $$_{name} - foreach ($clearadm->FindTask); + for ($clearadm->FindTask); my $taskDropdown = "$label "; $taskDropdown .= popup_menu { @@ -541,10 +599,10 @@ sub makeTimeDropdown ($$$;$$$$$) { if ($table =~ /loadavg/i) { push @times, $$_{timestamp} - foreach ($clearadm->GetLoadavg ($system, undef, undef, undef, $interval)); + for ($clearadm->GetLoadavg ($system, undef, undef, undef, $interval)); } elsif ($table =~ /filesystem/i) { push @times, $$_{timestamp} - foreach ($clearadm->GetFS ($system, $filesystem, undef, undef, undef, $interval)); + for ($clearadm->GetFS ($system, $filesystem, undef, undef, undef, $interval)); } # if push @times, 'Latest'; @@ -575,17 +633,17 @@ sub heading (;$$) { display header; display start_html { - -title => $title, - -author => 'Andrew DeFaria ', - -meta => { - keywords => 'ClearSCM Clearadm', + -title => $title, + -author => 'Andrew DeFaria ', + -meta => { + keywords => 'ClearSCM Clearadm', copyright => 'Copyright (c) ClearSCM, Inc. 2010, All rights reserved', - }, - -script => [{ - -language => 'JavaScript', - -src => 'clearadm.js', - }], - -style => ['clearadm.css', 'clearmenu.css'], + }, + -script => [{ + -language => 'JavaScript', + -src => 'clearadm.js', + }], + -style => ['clearadm.css', 'clearmenu.css'], }, $title; return if $type; @@ -609,7 +667,7 @@ sub heading (;$$) { display start_li; display a {href => 'systems.cgi'}, "Systems$ieTableWrapStart"; display start_ul; - foreach (@allSystems) { + for (sort @allSystems) { my %system = %{$_}; my $sysName = ucfirst $system{name}; $sysName .= " ($system{alias})" @@ -618,7 +676,7 @@ sub heading (;$$) { display li a { href => "systemdetails.cgi?system=$system{name}" }, ucfirst " $sysName"; - } # foreach + } # for display end_ul; display $ieTableWrapEnd; display end_li; @@ -630,7 +688,7 @@ sub heading (;$$) { display start_li; display a {href => 'filesystems.cgi'}, "Filesystems$ieTableWrapStart"; display start_ul; - foreach (@allSystems) { + for (@allSystems) { my %system = %{$_}; my $sysName = ucfirst $system{name}; $sysName .= " ($system{alias})" @@ -639,49 +697,16 @@ sub heading (;$$) { display li a { href => "filesystems.cgi?system=$system{name}" }, ucfirst " $sysName"; - } # foreach - display end_ul; - display $ieTableWrapEnd; - display end_li; - display end_ul; - - # Servers - display start_ul; - display start_li; - display a {href => '#'}, "Servers$ieTableWrapStart"; - display start_ul {class => 'skinny'}; - display start_li; - display start_a {href => 'vobs.cgi'}; - display "VOB»$ieTableWrapStart"; - display start_ul; - display li a {href => "systemdetails.cgi?system=jupiter"}, ' Jupiter (defaria.com)'; + } # for display end_ul; display $ieTableWrapEnd; - display end_li; - - display start_li; - display start_a {href => 'views.cgi'}; - display "View»$ieTableWrapStart"; - display start_ul; - display li a {href => "systemdetails.cgi?system=earth"}, ' Earth'; - display li a {href => "systemdetails.cgi?system=mars"}, ' Mars'; - display end_ul; - display $ieTableWrapEnd; - display end_ul; - display $ieTableWrapEnd; display end_li; display end_ul; # Vobs display start_ul; display start_li; - display a {href => 'vobs.cgi'}, "VOBs$ieTableWrapStart"; - display start_ul; - display li a {href => '#'}, ' /vobs/clearscm'; - display li a {href => '#'}, ' /vobs/clearadm'; - display li a {href => '#'}, ' /vobs/test'; - display li a {href => '#'}, ' /vobs/test2'; - display end_ul; + display a {href => 'vobservers.cgi'}, "   VOBs$ieTableWrapStart"; display $ieTableWrapEnd; display end_li; display end_ul; @@ -689,11 +714,7 @@ sub heading (;$$) { # Views display start_ul; display start_li; - display a {href => 'views.cgi'}, "Views$ieTableWrapStart"; - display start_ul; - display li a {href => 'viewager.cgi'}, ' View Ager'; - display li a {href => '#'}, ' Releast View'; - display end_ul; + display a {href => 'viewager.cgi'}, "Views$ieTableWrapStart"; display $ieTableWrapEnd; display end_li; display end_ul; @@ -754,7 +775,7 @@ sub displayAlert (;$) { display th {class => 'labelCentered'}, 'Category'; display end_Tr; - foreach ($clearadm->FindAlert ($alert)) { + for ($clearadm->FindAlert ($alert)) { my %alert = %{$_}; $alert{who} = setField $alert{who}, 'System Administrator'; @@ -827,7 +848,7 @@ sub displayAlert (;$) { display td {class => 'data'}, (InArray $alert{name}, @PREDEFINED_ALERTS) ? 'Predefined' : 'User Defined'; display end_Tr; - } # foreach + } # for display end_table; @@ -1018,7 +1039,7 @@ sub displayAlertlog (%) { my $i = $opts{start}; - foreach ($clearadm->FindAlertlog ( + for ($clearadm->FindAlertlog ( $opts{alert}, $opts{system}, $opts{notification}, @@ -1055,7 +1076,7 @@ sub displayAlertlog (%) { }, $alertlog{runlog}; display td {class => 'data'}, $alertlog{message}; display end_Tr; - } # foreach + } # for display end_form; @@ -1083,7 +1104,7 @@ sub displayFilesystem ($) { display th {class => 'labelCentered'}, 'Usage'; display end_Tr; - foreach ($clearadm->FindSystem ($systemName)) { + for (sort { $a->{mount} cmp $b->{mount} } $clearadm->FindSystem ($systemName)) { my %system = %{$_}; %system = setFields ('N/A', %system); @@ -1092,7 +1113,7 @@ sub displayFilesystem ($) { ? a {-href => "mailto:$system{email}"}, $system{admin} : $system{admin}; - foreach ($clearadm->FindFilesystem ($system{name})) { + for ($clearadm->FindFilesystem ($system{name})) { my %filesystem = %{$_}; my %fs = $clearadm->GetLatestFS ($system{name}, $filesystem{filesystem}); @@ -1192,18 +1213,22 @@ sub displayFilesystem ($) { display td {class => $classRightTop}, "$used ($usedPct%)
", font {class => 'unknown'}, "$fs{timestamp}"; display td {class => $classRightTop}, "$filesystem{threshold}%"; + + my $image = $filesystem{fssmall} + ? "data:image/png;base64,$filesystem{fssmall}" + : "plotfs.cgi?system=$system{name}&filesystem=$filesystem{filesystem}&tiny=1"; + display td {class => $class}, a {href => "plot.cgi?type=filesystem&system=$system{name}" . "&filesystem=$filesystem{filesystem}&scaling=Day&points=7" }, img { - src => "plotfs.cgi?system=$system{name}" - . "&filesystem=$filesystem{filesystem}&tiny=1", + src => $image, border => 0, }; display end_Tr; - } # foreach - } # foreach + } # for + } # for display end_table; @@ -1224,7 +1249,7 @@ sub displayNotification (;$) { display th {class => 'labelCentered'}, 'Category'; display end_Tr; - foreach ($clearadm->FindNotification ($notification)) { + for ($clearadm->FindNotification ($notification)) { my %notification= setFields 'N/A', %{$_}; display start_Tr; @@ -1296,7 +1321,7 @@ sub displayNotification (;$) { : 'User Defined'; display end_Tr; - } # foreach + } # for display end_table; @@ -1315,25 +1340,24 @@ sub displayRunlog (%) { my $optsChanged; - unless (($opts{oldtask} and $opts{task} or - $opts{oldtask} eq $opts{task}) and - ($opts{oldsystem} and $opts{system} or - $opts{oldsystem} eq $opts{system}) and - ($opts{oldnot} and $opts{not} or - $opts{oldnot} eq $opts{not}) and - ($opts{oldstatus} and $opts{status} or - $opts{oldstatus} eq $opts{status})) { - $optsChanged = 1; - } # unless + for (qw(task system not status)) { + my $old = "old$_"; + if (($opts{$old} and $opts{$_}) and ($opts{$old} ne $opts{$_})) { + $optsChanged = 1; + last; + } # if + } # for - my $condition; + my $condition = ''; unless ($opts{id}) { - $condition = "task like '%"; - $condition .= $opts{task} ? $opts{task} : ''; - $condition .= "%'"; + if ($opts{task} !~ /all/i) { + $condition = "task like '%"; + $condition .= $opts{task} ? $opts{task} : ''; + $condition .= "%'"; + } # if - if ($opts{system}) { + if ($opts{system} !~ /all/i) { if ($opts{system} eq '') { $condition .= ' and system is null'; undef $opts{system} @@ -1342,7 +1366,7 @@ sub displayRunlog (%) { } # if } # if - if (defined $opts{status}) { + if ($opts{status} !~ /all/i) { $condition .= ' and '; unless ($opts{not}) { $condition .= "status=$opts{status}"; @@ -1490,13 +1514,13 @@ sub displayRunlog (%) { my $status; - if (defined $opts{status}) { + if ($opts{status}) { if ($opts{status} !~ /all/i) { $status = $opts{not} ne 'true' ? $opts{status} : "!$opts{status}"; } # if } # if - foreach ($clearadm->FindRunlog ( + for ($clearadm->FindRunlog ( $opts{task}, $opts{system}, $status, @@ -1522,7 +1546,7 @@ sub displayRunlog (%) { display td {class => 'data'}, a { href => "tasks.cgi?task=$runlog{task}" }, $runlog{task}; - display td {class => 'data'}, $runlog{system} eq 'Localhost' + display td {class => 'data'}, $runlog{system} eq 'localhost' ? $runlog{system} : a { href => "systemdetails.cgi?system=$runlog{system}" @@ -1536,7 +1560,7 @@ sub displayRunlog (%) { display td {class => $class, width => '50%'}, $message; display end_Tr; - } # foreach + } # for display end_table; @@ -1556,7 +1580,7 @@ sub displaySchedule () { display th {class => 'labelCentered'}, 'Category'; display end_Tr; - foreach ($clearadm->FindSchedule) { + for ($clearadm->FindSchedule) { my %schedule = setFields 'N/A', %{$_}; display start_Tr; @@ -1634,7 +1658,7 @@ sub displaySchedule () { : 'User Defined'; display end_Tr; - } # foreach + } # for display end_table; @@ -1765,7 +1789,7 @@ sub displaySystem ($) { a {href => "plot.cgi?type=loadavg&system=$system{name}&scaling=Hour&points=24" }, img { - src => "plotloadavg.cgi?system=$system{name}&tiny=1", + src => "data:image/png;base64,$system{loadavgsmall}", border => 0, }; @@ -1805,7 +1829,7 @@ sub displaySystem ($) { display th {class => 'labelCentered'}, 'Usage'; display end_Tr; - foreach ($clearadm->FindFilesystem ($system{name})) { + for ($clearadm->FindFilesystem ($system{name})) { my %filesystem = %{$_}; my %fs = $clearadm->GetLatestFS ( @@ -1830,58 +1854,59 @@ sub displaySystem ($) { my $classRight = $class . 'Right'; display start_Tr; - display start_td {class => 'data'}; + display start_td {class => 'data'}; - my $areYouSure = 'Are you sure you want to delete ' - . "$system{name}:$filesystem{filesystem}?" . '\n' - . 'Doing so will remove all records related to this\n' - . 'filesystem and its history.'; + my $areYouSure = 'Are you sure you want to delete ' + . "$system{name}:$filesystem{filesystem}?" . '\n' + . 'Doing so will remove all records related to this\n' + . 'filesystem and its history.'; - display start_form { - method => 'post', - action => 'processfilesystem.cgi', - }; + display start_form { + method => 'post', + action => 'processfilesystem.cgi', + }; - display input { - type => 'hidden', - name => 'system', - value => $system{name}, - }; - display input { - type => 'hidden', - name => 'filesystem', - value => $filesystem{filesystem}, - }; + display input { + type => 'hidden', + name => 'system', + value => $system{name}, + }; + display input { + type => 'hidden', + name => 'filesystem', + value => $filesystem{filesystem}, + }; - display input { - name => 'delete', - type => 'image', - src => 'delete.png', - alt => 'Delete', - value => 'Delete', - title => 'Delete', - onclick => "return AreYouSure ('$areYouSure');" - }; - display input { - name => 'edit', - type => 'image', - src => 'edit.png', - alt => 'Edit', - value => 'Edit', - title => 'Edit', + display input { + name => 'delete', + type => 'image', + src => 'delete.png', + alt => 'Delete', + value => 'Delete', + title => 'Delete', + onclick => "return AreYouSure ('$areYouSure');" + }; + display input { + name => 'edit', + type => 'image', + src => 'edit.png', + alt => 'Edit', + value => 'Edit', + title => 'Edit', + }; + + if ($filesystem{notification}) { + display a { + href => "alertlog.cgi?system=$filesystem{system}"}, img { + src => 'alert.png', + border => 0, + alt => 'Alert!', + title => 'This filesystem has alerts', }; + } # if - if ($filesystem{notification}) { - display a { - href => "alertlog.cgi?system=$filesystem{system}"}, img { - src => 'alert.png', - border => 0, - alt => 'Alert!', - title => 'This filesystem has alerts', - }; - } # if + display end_form; - display end_form; display td {class => $class}, $filesystem{filesystem}; display td {class => $classCentered}, $filesystem{fstype}; display td {class => $class}, $filesystem{mount}; @@ -1897,13 +1922,11 @@ sub displaySystem ($) { . "&filesystem=$filesystem{filesystem}" . "&scaling=Day&points=7" }, img { - src => "plotfs.cgi?system=$system{name}&" - . "filesystem=$filesystem{filesystem}" - . '&tiny=1', - border => 0, + src => "data:image/png;base64,$filesystem{fssmall}", + border => 0, }; display end_Tr; - } # foreach + } # for display end_table; @@ -1925,7 +1948,7 @@ sub displayTask (;$) { display th {class => 'labelCentered'}, 'Category'; display end_Tr; - foreach ($clearadm->FindTask ($task)) { + for ($clearadm->FindTask ($task)) { my %task = %{$_}; $task{system} = 'All Systems' @@ -1995,7 +2018,7 @@ sub displayTask (;$) { display td {class => 'data'}, (InArray $task{name}, @PREDEFINED_TASKS) ? 'Predefined' : 'User Defined'; display end_Tr; - } # foreach + } # for display end_table; @@ -2619,10 +2642,9 @@ sub editTask (;$) { }; my $systemDropdown = makeSystemDropdown ( undef, - $task{system} ? $task{system} : 'All Systems', + $task{system} ? $task{system} : 'localhost', undef, ( - 'All systems' => undef, - 'Localhost' => 'Localhost', + 'localhost' => 'localhost', ), ); diff --git a/clearadm/lib/User.pm b/clearadm/lib/User.pm index 2203c29..d787d92 100644 --- a/clearadm/lib/User.pm +++ b/clearadm/lib/User.pm @@ -51,7 +51,7 @@ use strict; use warnings; use Carp; -use Net::LDAP; +#use Net::LDAP; use GetConfig; diff --git a/clearadm/lib/clearadm.sql b/clearadm/lib/clearadm.sql index f365201..8d47e36 100644 --- a/clearadm/lib/clearadm.sql +++ b/clearadm/lib/clearadm.sql @@ -56,6 +56,8 @@ create table system ( '1 year' ) not null default '6 months', loadavgThreshold float (4,2) default 5.00, + loadavgsmall blob, + loadavg blob, primary key (name) ) engine=innodb; -- system @@ -130,6 +132,8 @@ create table filesystem ( '11 months', '1 year' ) not null default '6 months', + fssmall blob, + fslarge blob, key filesystemIndex (filesystem), foreign key systemLink (system) references system (name) @@ -157,6 +161,42 @@ create table fs ( on update cascade ) engine=innodb; -- fs +-- vobstorage: Contains a snapshot of a vob's storage pools at a given date +-- and time +create table vobstorage ( + tag varchar(255) not null, + region varchar(255) not null, + timestamp datetime not null, + admin decimal(10,1), + db decimal(10,1), + cleartext decimal(10,1), + derivedobj decimal(10,1), + source decimal(10,1), + total decimal(10,1), + + key vobtagIndex (tag), + primary key (tag, region, timestamp) + foreign key vobLink (tag, region) + references vob (tag, region) + on delete cascade + on update cascade +) engine=innodb; -- vobstorage + +-- viewstorage: Contains a snapshot of a view's storage pools at a given date +-- and time +create table viewstorage ( + tag varchar(255) not null, + region varchar(255) not null, + timestamp datetime not null, + private decimal(10,1), + db decimal(10,1), + admin decimal(10,1), + total decimal(10,1), + + key viewtagIndex (tag), + primary key (tag, region, timestamp) +) engine=innodb; -- viewstorage + -- loadavg: Contains a snapshot reading of a system's load average create table loadavg ( system varchar(255) not null, @@ -171,43 +211,55 @@ create table loadavg ( on update cascade ) engine=innodb; -- loadavg --- vobs: Describe a system's vobs +-- vob: Describe a system's vobs create table vob ( - system varchar (255) not null, - tag varchar (255) not null, + tag varchar (255) not null, + region varchar (255) not null, + adminsmall blob, + dbsmall blob, + cleartextsmall blob, + derivedobjsmall blob, + sourcesmall blob, + totalsmall blob, + adminlarge blob, + dblarge blob, + cleartextlarge blob, + derivedobjlarge blob, + sourcelarge blob, + totallarge blob, - key systemIndex (system), - foreign key systemLink (system) references system (name) - on delete cascade - on update cascade, - primary key (tag) + key vobTagIndex (tag), + primary key (tag, region) ) engine=innodb; -- vob -- view: Describe views create table view ( - system varchar (255) not null, - region varchar (255) not null, - tag varchar (255) not null, - owner tinytext, - ownerName tinytext, - email tinytext, - type enum ( - 'dynamic', - 'snapshot', - 'web' - ) not null default 'dynamic', - gpath tinytext, - modified datetime, - timestamp datetime, - age tinytext, - ageSuffix tinytext, + tag varchar (255) not null, + region varchar (255) not null, + owner tinytext, + ownerName tinytext, + email tinytext, + type enum ( + 'dynamic', + 'snapshot', + 'web' + ) not null default 'dynamic', + gpath tinytext, + modified datetime, + timestamp datetime, + age tinytext, + ageSuffix tinytext, + privatesmall blob, + dbsmall blob, + adminsmall blob, + totalsmall blob, + privatelarge blob, + dblarge blob, + adminlarge blob, + totallarge blob, - key systemIndex (system), - foreign key systemLink (system) references system (name) - on delete cascade - on update cascade, - key regionIndex (region), - primary key (region, tag) + key viewTagIndex (tag), + primary key (tag, region) ) engine=innodb; -- view create table task ( diff --git a/clearadm/lib/load.sql b/clearadm/lib/load.sql index 4c005f4..a6efa48 100644 --- a/clearadm/lib/load.sql +++ b/clearadm/lib/load.sql @@ -69,6 +69,18 @@ insert into notification ( 'Once a day' ); +insert into notification ( + name, + alert, + cond, + nomorethan +) values ( + 'Clearcase Storage', + 'Email admin', + 'Clearcase Failure', + 'Once a day' +); + insert into notification ( name, alert, @@ -101,7 +113,7 @@ insert into task ( command ) values ( 'Loadavg', - 'Localhost', + 'localhost', 'Obtain a loadavg snapshot on all systems', 'updatela.pl' ); @@ -113,7 +125,7 @@ insert into task ( command ) values ( 'Filesystem', - 'Localhost', + 'localhost', 'Obtain a filesystem snapshot on all systems/filesystems', 'updatefs.pl' ); @@ -125,7 +137,7 @@ insert into task ( command ) values ( 'Scrub', - 'Localhost', + 'localhost', 'Scrub Clearadm database', 'clearadmscrub.pl' ); @@ -137,7 +149,7 @@ insert into task ( command ) values ( 'System checkin', - 'Localhost', + 'localhost', 'Checkin from all systems', 'default' ); @@ -149,11 +161,23 @@ insert into task ( command ) values ( 'Update systems', - 'Localhost', + 'localhost', 'Update all systems', 'updatesystem.pl -host all' ); +insert into task ( + name, + system, + description, + command +) values ( + 'Clearcase Storage', + 'localhost', + 'Update Clearcase VOB/View storage', + 'updateccfs.pl' +); + -- Predefined schedule insert into schedule ( name, @@ -190,3 +214,17 @@ insert into schedule ( 'Scrub', '1 day' ); + +insert into schedule ( + name, + task, + notification, + frequency +) values ( + 'Clearcase Storage', + 'Clearcase Storage', + 'Clearcase Storage', + '1 day' +); + + diff --git a/clearadm/notifications.cgi b/clearadm/notifications.cgi index 040a88f..d444582 100755 --- a/clearadm/notifications.cgi +++ b/clearadm/notifications.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -143,4 +143,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/plot.cgi b/clearadm/plot.cgi index 422f156..310ff7f 100755 --- a/clearadm/plot.cgi +++ b/clearadm/plot.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -58,39 +58,74 @@ my $clearadm; sub displayGraph () { my $parms; - foreach (keys %opts) { - $parms .= '&' - if $parms; + for (keys %opts) { + $parms .= '&' if $parms; $parms .= "$_=$opts{$_}" - } # foreach + } # for display '
'; if ($opts{type} eq 'loadavg') { - unless ($opts{tiny}) { - display img {src => "plotloadavg.cgi?$parms", class => 'chart'}; - } else { - display img {src => "plotloadavg.cgi?$parms", border => 0}; - } # unless + my %system = $clearadm->GetSystem($opts{system}); + + # We can use the cached version only if the opts are set to default + if ($opts{scaling} eq 'Hour' and $opts{points} == 24) { + my $data = $opts{tiny} ? $system{loadavgsmall} : $system{loadavg}; + + display img {src => "data:image/png;base64,$data"}; + } else { + unless ($opts{tiny}) { + display img {src => "plotloadavg.cgi?$parms", class => 'chart'}; + } else { + display img {src => "plotloadavg.cgi?$parms", border => 0}; + } # unless + } # if } elsif ($opts{type} eq 'filesystem') { - unless ($opts{tiny}) { - display img {src => "plotfs.cgi?$parms", class => 'chart'}; - } else { - display img {src => "plotfs.cgi?$parms", border => 0}; - } # unless + my %filesystem = $clearadm->GetFilesystem($opts{system}, $opts{filesystem}); + + # We can use the cached version only if the opts are set to default + if ($opts{scaling} eq 'Day' and $opts{points} == 7) { + my $data = $opts{tiny} ? $filesystem{fssmall} : $filesystem{fslarge}; + + display img {src => "data:image/png;base64,$data"}; + } else { + unless ($opts{tiny}) { + display img {src => "plotfs.cgi?$parms", class => 'chart'}; + } else { + display img {src => "plotfs.cgi?$parms", border => 0}; + } # unless + } # if + } elsif ($opts{type} eq 'vob' or $opts{type} eq 'view') { + my (%vob, %view); + + %vob = $clearadm->GetVob($opts{tag}, $opts{region}) if $opts{type} eq 'vob'; + %view = $clearadm->GetView($opts{tag}, $opts{region}) if $opts{type} eq 'view'; + # We can use the cached version only if the opts are set to default + if ($opts{scaling} eq 'Day' and $opts{points} == 7) { + my $storageType = $opts{tiny} ? "$opts{storage}small" : "$opts{storage}large"; + my $data = $opts{type} eq 'vob' ? $vob{$storageType} : $view{$storageType}; + + display img {src => "data:image/png;base64,$data"}; + } else { + unless ($opts{tiny}) { + display img {src => "plotstorage.cgi?$parms", class => 'chart'}; + } else { + display img {src => "plotstorage.cgi?$parms", border => 0}; + } # unless + } # if } # if display '
'; - return + return; } # displayGraph sub displayFSInfo () { if ($opts{filesystem}) { display h3 {-align => 'center'}, 'Latest Filesystem Reading'; } else { - display p; - return; + display p; + return; } # if display start_table {width => '800px', cellspacing => 1}; @@ -140,7 +175,7 @@ sub displayFSInfo () { return; } # displayInfo -sub displayControls () { +sub displayControls() { my $class = $opts{type} =~ /loadavg/i ? 'controls' : 'filesystemControls'; @@ -152,15 +187,22 @@ sub displayControls () { width => '800px', }; - my $systemLink = span {id => 'systemLink'}, a { - href => "systemdetails.cgi?system=$opts{system}", - }, 'System'; + my $tagsButtons; + my ($systemLink, $systemButtons); - my $systemButtons = makeSystemDropdown ( - $systemLink, - $opts{system}, - 'updateFilesystems(this.value);updateSystemLink(this.value)' - ); + if ($opts{type} =~ /(vob|view)/i) { + $tagsButtons = makeTagsDropdown ($opts{type}, $opts{tag}); + } else { + $systemLink = span {id => 'systemLink'}, a { + href => "systemdetails.cgi?system=$opts{system}", + }, 'System'; + + $systemButtons = makeSystemDropdown ( + $systemLink, + $opts{system}, + 'updateFilesystems(this.value);updateSystemLink(this.value)' + ); + } # if my $startButtons = makeTimeDropdown ( $opts{type}, @@ -182,9 +224,15 @@ sub displayControls () { $opts{scaling}, ); - my $update = $opts{type} eq 'loadavg' - ? "updateSystem('$opts{system}')" - : "updateFilesystem('$opts{system}','$opts{filesystem}')"; + my $update; + + if ($opts{type} eq 'loadavg') { + $update = "updateSystem('$opts{system}')"; + } elsif ($opts{type} eq 'filsystem') { + $update = "updateFilesystem('$opts{system}','$opts{filesystem}')"; + } else { + $update = ''; # TODO do I need something here? + } # if my $intervalButtons = makeIntervalDropdown ( 'Interval', @@ -195,7 +243,7 @@ sub displayControls () { display start_Tr; display td $startButtons; display td $intervalButtons; - display td $systemButtons; + display td $opts{type} =~ /(vob|view)/i ? $tagsButtons : $systemButtons; display end_Tr; display start_Tr; @@ -216,14 +264,20 @@ sub displayControls () { value => 'Draw Graph', }; } else { - my $filesystemButtons = makeFilesystemDropdown ( - $opts{system}, - 'Filesystem', - undef, - "updateFilesystem('$opts{system}',this.value)", - ); + if ($opts{type} eq 'filesystem') { + my $filesystemButtons = makeFilesystemDropdown ( + $opts{system}, + 'Filesystem', + undef, + "updateFilesystem('$opts{system}',this.value)", + ); - display td $filesystemButtons; + display td $filesystemButtons; + } else { + my $storagePoolButtons = makeStoragePoolDropdown ($opts{type}, $opts{tag}); + + display td $storagePoolButtons; + } # if display end_Tr; display start_Tr; @@ -240,10 +294,12 @@ sub displayControls () { $clearadm = Clearadm->new; -my $title = ucfirst ($opts{type}) . ': ' . ucfirst $opts{system}; +my $title = ucfirst ($opts{type}) . ': '; -$title .= ":$opts{filesystem}" - if $opts{filesystem}; +$title .= ucfirst $opts{system} if $opts{system}; +$title .= ":$opts{filesystem}" if $opts{filesystem}; +$title .= $opts{tag} if $opts{tag}; +$title .= " Storage pool: $opts{storage}" if $opts{storage}; heading $title; @@ -255,7 +311,8 @@ display start_form { }; # Some hidden fields to pass along -display input {type => 'hidden', name => 'type', value => $opts{type}}; +display input {type => 'hidden', name => 'type', value => $opts{type}}; +display input {type => 'hidden', name => 'region', value => $opts{region}}; displayGraph; displayFSInfo; @@ -317,4 +374,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/plotfs.cgi b/clearadm/plotfs.cgi index 3bc8a03..e4a5e6c 100755 --- a/clearadm/plotfs.cgi +++ b/clearadm/plotfs.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -61,6 +61,7 @@ use strict; use warnings; use FindBin; +use Convert::Base64; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; @@ -165,8 +166,12 @@ $graph->set ( my $image = $graph->plot(\@data) or croak $graph->error; -print "Content-type: image/png\n\n"; -print $image->png; +unless ($opts{generate}) { + print "Content-type: image/png\n\n"; + print $image->png; +} else { + print encode_base64 $image->png; +} # unless =pod diff --git a/clearadm/plotloadavg.cgi b/clearadm/plotloadavg.cgi index 853edd8..8d51a21 100755 --- a/clearadm/plotloadavg.cgi +++ b/clearadm/plotloadavg.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -59,6 +59,7 @@ use strict; use warnings; use FindBin; +use Convert::Base64; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; @@ -100,15 +101,15 @@ my @loads = $clearadm->GetLoadavg ( $opts{start}, $opts{end}, $opts{points}, - $opts{scaling} + $opts{scaling}, ); -graphError "No loadavg data found for system $opts{system}" +graphError "No loadavg data" unless @loads; my (@x, @y); -foreach (@loads) { +for (@loads) { my %load = %{$_}; if ($opts{tiny}) { @@ -118,7 +119,7 @@ foreach (@loads) { } # if push @y, $load{loadavg}; -} # foreach +} # for my @data = ([@x], [@y]); @@ -154,8 +155,12 @@ $graph->set ( my $image = $graph->plot(\@data) or croak $graph->error; -print "Content-type: image/png\n\n"; -print $image->png; +unless ($opts{generate}) { + print "Content-type: image/png\n\n"; + print $image->png; +} else { + print encode_base64 $image->png; +} # unless =pod @@ -207,4 +212,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/plotstorage.cgi b/clearadm/plotstorage.cgi new file mode 100755 index 0000000..f017de6 --- /dev/null +++ b/clearadm/plotstorage.cgi @@ -0,0 +1,231 @@ +#!/usr/local/bin/perl + +=pod + +=head1 NAME $RCSfile: plotstorage.cgi,v $ + +Plot Clearcse Storage usage + +=head1 VERSION + +=over + +=item Author + +Andrew DeFaria + +=item Revision + +$Revision: 1.13 $ + +=item Created: + +Mon Dec 13 09:13:27 EST 2010 + +=item Modified: + +$Date: 2011/01/14 16:37:04 $ + +=back + +=head1 SYNOPSIS + + Usage plotstorage.cgi: tag= type= storage= + [height=] [width=] [color=] + [scaling=] [points=] [tiny=<0|1>] + + Where: + : Tag of the Clearcase object (vob or view) + : Designates whether is a vob of a view + : Name of the Clearcase storage pool to plot information for + : Height of chart (Default: 480px - tiny: 40) + : Width of chart (Default: 800px - tiny: 150) + : A GD::Color color value (Default: purple) + : Currently one of Minute, Hour, Day or Month. Specifies how + Clearadm::GetFS will scale the data returned (Default: Minute + - tiny: Day) + : Number of points to plot (Default: all points - tiny: 7) + +=head1 DESCRIPTION + +Draws a chart of the storage usage for the Clearcase object (vob|view). +Parameters such as height, width, color, scaling and points can be set +individually though more often the user will just use the web controls to set +them. Defaults produce a nice chart. Tiny mode is used by +details.cgi to draw tiny charts in the table. Setting tiny sets +a number of the other chart options to produce a standard, tiny chart. + +=cut + +use strict; +use warnings; + +use FindBin; +use Convert::Base64; + +use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; + +use Clearadm; +use ClearadmWeb; +use Clearcase; +use Display; + +use CGI qw (:standard :cgi-lib); +use GD::Graph::area; + +my %opts = Vars; + +my $VERSION = '$Revision: 1.13 $'; + ($VERSION) = ($VERSION =~ /\$Revision: (.*) /); + +$opts{color} ||= $opts{type} eq 'vob' ? 'purple' : 'marine'; +$opts{height} ||= 350; +$opts{width} ||= 800; + +if ($opts{tiny}) { + $opts{height} = 40; + $opts{width} = 150; + $opts{points} = 7; + $opts{scaling} = 'Day'; +} # if + +my $clearadm = Clearadm->new; + +my $graph = GD::Graph::area->new ($opts{width}, $opts{height}); + +graphError "Tag is required" unless $opts{tag}; +graphError "Type is required" unless $opts{type}; +graphError "Storage is required" unless $opts{storage}; + +graphError "Points not numeric (points: $opts{points})" + if $opts{points} and $opts{points} !~ /^\d+$/; + +my @storage = $clearadm->GetStorage ( + $opts{type}, + $opts{tag}, + $opts{storage}, + $opts{region}, + $opts{start}, + $opts{end}, + $opts{points}, + $opts{scaling} +); + +graphError "No data found for $opts{type} $opts{tag} for storage pool $opts{storage}" + unless @storage; + +my (@x, @y); + +my $i = 0; + +for (@storage) { + $i++; + my %storage = %{$_}; + + if ($opts{tiny}) { + push @x, ''; + } else { + push @x, $storage{timestamp}; + } # if + + push @y, $opts{meg} ? $storage{size} / (1024 * 1024) : + $storage{size} / (1024 * 1024 * 12024); +} # for + +my @data = ([@x], [@y]); + +my $x_label_skip = @x > 1000 ? 200 + : @x > 100 ? 20 + : @x > 50 ? 2 + : @x > 10 ? 1 + : 0; + +my $storageLabel = ucfirst $opts{storage}; +my $x_label = $opts{tiny} ? '' : "$storageLabel Storage"; +my $y_label = $opts{tiny} ? '' : + $opts{msg} ? 'Used (Meg)' : 'Used (Gig)'; +my $title = $opts{tiny} ? '' : "Storage usage for " + . "$opts{type}:$opts{tag} $storageLabel"; +my $labelY = $opts{tiny} ? '' : '%.2f'; + +$graph->set ( + x_label => $x_label, + x_labels_vertical => 1, + x_label_skip => $x_label_skip, + x_label_position => .5, + y_label => $y_label, + y_number_format => $labelY, + title => $title, + dclrs => [$opts{color}], + bgclr => 'white', + transparent => 0, + long_ticks => 1, + t_margin => 5, + b_margin => 5, + l_margin => 5, + r_margin => 5, +) or graphError $graph->error; + +my $image = $graph->plot(\@data) + or croak $graph->error; + +unless ($opts{generate}) { + print "Content-type: image/png\n\n"; + print $image->png; +} else { + print encode_base64 $image->png; +} # unless + +=pod + +=head1 CONFIGURATION AND ENVIRONMENT + +DEBUG: If set then $debug is set to this level. + +VERBOSE: If set then $verbose is set to this level. + +TRACE: If set then $trace is set to this level. + +=head1 DEPENDENCIES + +=head2 Perl Modules + +L + +L + +L + +L + +=head2 ClearSCM Perl Modules + +=begin man + + Clearadm + ClearadmWeb + Display + +=end man + +=begin html + +
+Clearadm
+ClearadmWeb
+Display
+
+ +=end html + +=head1 BUGS AND LIMITATIONS + +There are no known bugs in this script + +Please report problems to Andrew DeFaria . + +=head1 LICENSE AND COPYRIGHT + +Copyright (c) 2010, ClearSCM, Inc. All rights reserved. + +=cut diff --git a/clearadm/processalert.cgi b/clearadm/processalert.cgi index f3fca08..86373a9 100755 --- a/clearadm/processalert.cgi +++ b/clearadm/processalert.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -209,4 +209,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/processfilesystem.cgi b/clearadm/processfilesystem.cgi index 9ade442..9b2f3b2 100755 --- a/clearadm/processfilesystem.cgi +++ b/clearadm/processfilesystem.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -205,4 +205,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/processnotification.cgi b/clearadm/processnotification.cgi index 6889eb4..fa116c8 100755 --- a/clearadm/processnotification.cgi +++ b/clearadm/processnotification.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -223,4 +223,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/processrunning.pl b/clearadm/processrunning.pl index 3eabc4a..c5a2a4f 100755 --- a/clearadm/processrunning.pl +++ b/clearadm/processrunning.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl =pod @@ -186,4 +186,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/processschedule.cgi b/clearadm/processschedule.cgi index 30f4c32..88d0a29 100755 --- a/clearadm/processschedule.cgi +++ b/clearadm/processschedule.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -222,4 +222,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/processsystem.cgi b/clearadm/processsystem.cgi index 8bdd2e2..b68a9ae 100755 --- a/clearadm/processsystem.cgi +++ b/clearadm/processsystem.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -86,7 +86,11 @@ my $title = 'Process System'; heading $title; -unless ($opts{'delete.x'} or $opts{'edit.x'} or $opts{action} eq 'Post') { +unless ($opts{'delete.x'} + or $opts{'edit.x'} + or $opts{action} eq 'Post' + or $opts{action} eq 'Add' + ) { displayError 'Action not defined!'; exit 1; } # unless @@ -199,4 +203,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/processtask.cgi b/clearadm/processtask.cgi index cca5801..369d008 100755 --- a/clearadm/processtask.cgi +++ b/clearadm/processtask.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -210,4 +210,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/readme.cgi b/clearadm/readme.cgi index de4a05d..9a259a3 100755 --- a/clearadm/readme.cgi +++ b/clearadm/readme.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -123,4 +123,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/runlog.cgi b/clearadm/runlog.cgi index d0410ed..e5e3f56 100755 --- a/clearadm/runlog.cgi +++ b/clearadm/runlog.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -84,14 +84,11 @@ my $title = 'Run Log'; heading $title; -undef $opts{task} - if $opts{task} and $opts{task} eq 'All'; - +$opts{task} ||= 'All'; $opts{system} ||= 'All'; +$opts{not} ||= 0; +$opts{status} ||= 'All'; -undef $opts{status} - if $opts{status} and $opts{status} eq 'All'; - display h1 {class => 'center'}, $title; displayRunlog (%opts); @@ -152,4 +149,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/schedule.cgi b/clearadm/schedule.cgi index ef3feef..9020c18 100755 --- a/clearadm/schedule.cgi +++ b/clearadm/schedule.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -139,4 +139,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/setup.pl b/clearadm/setup.pl index 7724992..98a0094 100755 --- a/clearadm/setup.pl +++ b/clearadm/setup.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl =pod @@ -78,7 +78,7 @@ sub SetupAgent () { my ($status, @output, $cmd); - if ($ARCH eq 'cygwin') { + if ($ARCHITECTURE eq 'cygwin') { verbose '[Cygwin] Creating up Clearagent Service'; $cmd = 'cygrunsrv -I clearagent -p C:/Cygwin/bin/perl '; @@ -86,7 +86,7 @@ sub SetupAgent () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; verbose '[Cygwin] Starting Clearagent Service'; @@ -94,34 +94,44 @@ sub SetupAgent () { $cmd .= 'net start clearagent'; ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; } else { - my $Arch = ucfirst $ARCH; + my $Arch = ucfirst $ARCHITECTURE; verbose 'Creating clearagent user'; $cmd = 'useradd -Mr clearagent'; + $cmd = 'useradd clearagent' if $ARCHITECTURE eq 'solaris'; ($status, @output) = Execute "$cmd 2>&1"; if ($status == 9) { warning "The user clearagent already exists"; + } elsif ($status == 2304) { + # Stupid Solaris... } elsif ($status != 0) { - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1; + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status; } # if verbose 'Setting permissions on log and var directories'; - - $cmd = "chmod 777 $Clearadm::CLEAROPTS{CLEARADM_BASE}/var;"; - $cmd .= "chmod 777 $Clearadm::CLEAROPTS{CLEARADM_BASE}/var/run;"; - $cmd .= "chmod 777 $Clearadm::CLEAROPTS{CLEARADM_BASE}/log"; - - ($status, @output) = Execute "$cmd 2>&1"; - - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 - if $status; + for (qw(var var/run log)) { + $cmd = "mkdir -p $Clearadm::CLEAROPTS{CLEARADM_BASE}/$_"; + + ($status, @output) = Execute "$cmd 2>&1"; + + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status + if $status; + + $cmd = "chmod 777 $Clearadm::CLEAROPTS{CLEARADM_BASE}/$_"; + + ($status, @output) = Execute "$cmd 2>&1"; + + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status + if $status; + } # for + verbose "[$Arch] Setting up clearagent daemon"; # Symlink $CLEARADM/etc/conf.d/clearadm -> /etc/init.d @@ -130,29 +140,47 @@ sub SetupAgent () { error "Cannot find conf.d directory ($confdir)", 1 unless -d $confdir; - unless (-e "$confdir/clearadm") { - $cmd = "ln -s $FindBin::Bin/etc/init.d/clearadm $confdir"; + unless (-e "$confdir/clearagent") { + $cmd = "ln -s $FindBin::Bin/etc/init.d/clearagent $confdir"; ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; } # unless # Setup runlevel links - $cmd = 'update-rc.d clearagent defaults'; + if ($ARCHITECTURE eq 'solaris') { + $cmd = "ln -s /etc/init.d/clearagent /etc/rc2.d/S90clearagent"; + + ($status, @output) = Execute "$cmd 2>&1"; + + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status + if $status; + + verbose 'Starting clearagent'; - ($status, @output) = Execute "$cmd 2>&1"; + $cmd = '/etc/init.d/clearagent'; + + ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 - if $status; - - verbose 'Starting clearagent'; + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status + if $status; + } else { + $cmd = 'update-rc.d clearagent defaults'; - $cmd = 'service clearagent start'; + ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 - if $status; + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status + if $status; + + verbose 'Starting clearagent'; + + $cmd = 'service clearagent start'; + + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status + if $status; + } # if } # if verbose "Done"; @@ -176,7 +204,7 @@ sub SetupTasks () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; } # unless @@ -185,7 +213,7 @@ sub SetupTasks () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; verbose 'Starting cleartasks'; @@ -194,7 +222,7 @@ sub SetupTasks () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; verbose 'Done'; @@ -218,11 +246,11 @@ sub SetupWeb () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; } # unless - if ($ARCH eq 'cygwin') { + if ($ARCHITECTURE eq 'cygwin') { $cmd = 'net stop apache2; net start apache2'; } else { $cmd = '/etc/init.d/apache2 restart'; @@ -230,7 +258,7 @@ sub SetupWeb () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; verbose 'Done'; @@ -249,7 +277,7 @@ sub SetupDatabase () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; verbose 'Setting up database users'; @@ -258,7 +286,7 @@ sub SetupDatabase () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; verbose 'Setting up predefined tasks'; @@ -267,7 +295,7 @@ sub SetupDatabase () { ($status, @output) = Execute "$cmd 2>&1"; - error "Unable to execute $cmd (Status: $status)\n" . join ("\n", @output), 1 + error "Unable to execute $cmd (Status: $status)\n" . join("\n", @output), $status if $status; verbose 'Done'; @@ -277,10 +305,10 @@ sub SetupDatabase () { # Main error "Cannot setup Clearadm when using Windows - hint try using Cgywin", 1 - if $ARCH eq 'windows'; + if $ARCHITECTURE eq 'windows'; Usage 'You must be root' - unless $> == 0 or $ARCH eq 'cygwin'; + unless $> == 0 or $ARCHITECTURE eq 'cygwin'; my $package = 'all'; @@ -326,4 +354,4 @@ if ($lcpackage eq 'all') { SetupWeb; } # if -=pod \ No newline at end of file +=pod diff --git a/clearadm/systemdetails.cgi b/clearadm/systemdetails.cgi index 1014e03..6cb81cf 100755 --- a/clearadm/systemdetails.cgi +++ b/clearadm/systemdetails.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -279,4 +279,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/systems.cgi b/clearadm/systems.cgi index 4346c93..1f7aba7 100755 --- a/clearadm/systems.cgi +++ b/clearadm/systems.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -286,4 +286,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/tasks.cgi b/clearadm/tasks.cgi index 518103a..8400203 100755 --- a/clearadm/tasks.cgi +++ b/clearadm/tasks.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -142,4 +142,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/test.pl b/clearadm/test.pl index 8e89bbb..3447284 100755 --- a/clearadm/test.pl +++ b/clearadm/test.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl use strict; use warnings; @@ -237,4 +237,4 @@ my ($err, $msg) = $clearadm->DeleteSystem ($system{name}); error $msg, $err if $err; - \ No newline at end of file + diff --git a/clearadm/updateccfs.pl b/clearadm/updateccfs.pl new file mode 100755 index 0000000..6a82134 --- /dev/null +++ b/clearadm/updateccfs.pl @@ -0,0 +1,405 @@ +#!/usr/local/bin/perl + +=pod + +=head1 NAME $RCSfile: updateccstorage.pl,v $ + +Update Filesystem + +=head1 VERSION + +=over + +=item Author + +Andrew DeFaria + +=item Revision + +$Revision: 1.29 $ + +=item Created: + +Mon Dec 13 09:13:27 EST 2010 + +=item Modified: + +$Date: 2011/06/16 15:12:50 $ + +=back + +=head1 SYNOPSIS + + Usage updateccstorage.pl: [-u|sage] [-ve|rbose] [-deb|ug] + [-view [|all]| -vob [|all]] + + Where: + -u|sage: Displays usage + + -ve|rbose: Be verbose + -deb|ug: Output debug messages + + -view [|all] Update view storage (Default: all) + -vob [|all] Update vob storage (Default: all) + -region [|all] Update region (Default: all) + +=head1 DESCRIPTION + +This script will record the state of Clearcase storage + +=cut + +use strict; +use warnings; + +use FindBin; +use Getopt::Long; + +use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; + +use Clearadm; +use Clearexec; +use Clearcase::Views; +use Clearcase::View; +use Clearcase::Vobs; +use Clearcase::Vob; +use DateUtils; +use Display; +use Utils; +use TimeUtils; + +my $VERSION = '$Revision: 1.29 $'; + ($VERSION) = ($VERSION =~ /\$Revision: (.*) /); + +my $clearadm = Clearadm->new; + +my %total; + +# Given a view tag, snapshot the storage sizes +sub snapshotViewStorage($$) { + my ($tag, $region) = @_; + + my %viewstorage = ( + tag => $tag, + region => $region, + ); + + my $view = Clearcase::View->new($tag, $region); + + $viewstorage{private} = $view->viewPrivateStorage; + $viewstorage{db} = $view->viewDatabase; + $viewstorage{admin} = $view->viewAdmin; + $viewstorage{total} = $view->viewSpace; + + my ($err, $msg) = $clearadm->AddViewStorage(%viewstorage); + + error $msg, $err if $err; + + $total{'Views snapshotted'}++; + + updateView($tag, $region); + + return; +} # snapshotVobStorage + +# Given a vob tag, snapshot the storage sizes +sub snapshotVobStorage($$) { + my ($tag, $region) = @_; + + my %vobstorage = ( + tag => $tag, + region => $region, + ); + + my $vob = Clearcase::Vob->new($tag, $region); + + $vobstorage{admin} = $vob->admsize; + $vobstorage{db} = $vob->dbsize; + $vobstorage{cleartext} = $vob->ctsize; + $vobstorage{derivedobj} = $vob->dosize; + $vobstorage{source} = $vob->srcsize; + $vobstorage{total} = $vob->size; + + my ($err, $msg) = $clearadm->AddVobStorage(%vobstorage); + + error $msg, $err, if $err; + + $total{'VOBs snapshotted'}++; + + updateVob($tag, $region); + + return; +} # snapshotVobStorage + +sub updateVob($$) { + my ($tag, $region) = @_; + + my ($err, $msg, $error, @output, $graph); + + my %vob = $clearadm->GetVob($tag, $region); + + for my $graphType (qw(admin cleartext db derivedobj source total)) { + #for my $graphType (qw(derivedobj)) { + # Windows vob tags begin with "\", which is problematic. The solution is to + # escape the "\" + my $vobtag = $tag; + $vobtag =~ s/^\\/\\\\/; + + my $cmd = "plotstorage.cgi generate=1 type=vob storage=$graphType region=$region scaling=Day points=7 tag=$vobtag"; + + $graph = "${graphType}small"; + + verbose "Generating $graph for VOB $tag (Region: $region)"; + + ($error, @output) = Execute("$cmd tiny=1 2>&1"); + + error "Unable to generate $graph" . join("\n", @output), $error if $error; + + $vob{$graph} = join '', @output; + $total{'VOB Graphs generated'}++; + + $graph = "${graphType}large"; + + verbose "Generating $graph for VOB $tag (Region: $region)"; + + ($error, @output) = Execute("$cmd 2>&1"); + + error "Unable to generate $graph" . join("\n", @output), $error if $error; + + $vob{$graph} = join '', @output; + $total{'VOB Graphs generated'}++; + } # for + + if ($vob{tag}) { + ($err, $msg) = $clearadm->UpdateVob(%vob); + + error "Unable to update VOB $tag (Region: $region) - $msg", $err if $err; + + $total{'VOBs updated'}++; + } else { + $vob{tag} = $tag; + $vob{region} = $region; + + ($err, $msg) = $clearadm->AddVob(%vob); + + error "Unable to add VOB $tag (Region: $region) - $msg", $err if $err; + + $total{'VOBs added'}++; + } # if + + return; +} # updateVob + +sub updateView($$) { + my ($tag, $region) = @_; + + my ($err, $msg, $error, @output, $graph); + + my %view = $clearadm->GetView($tag, $region); + + for my $graphType (qw(private db admin total)) { + my $cmd = "plotstorage.cgi generate=1 type=view storage=$graphType region=$region scaling=Day points=7 tag=$tag"; + + $graph = "${graphType}small"; + + verbose "Generating $graph for View $tag (Region: $region)"; + + ($error, @output) = Execute("$cmd tiny=1 2>&1"); + + error "Unable to generate $graph" . join("\n", @output), $error if $error; + + $total{'View Graphs generated'}++; + + $view{$graph} = join '', @output; + + $graph = "${graphType}large"; + + verbose "Generating $graph for View $tag (Region: $region)"; + + ($error, @output) = Execute("$cmd 2>&1"); + + error "Unable to generate $graph" . join("\n", @output), $error if $error; + + $total{'View Graphs generated'}++; + + $view{$graph} = join '', @output; + } # for + + if ($view{tag}) { + ($err, $msg) = $clearadm->UpdateView(%view); + + error "Unable to update View $tag (Region: $region) - $msg", $err if $err; + + $total{'Views updated'}++; + } else { + $view{tag} = $tag; + $view{region} = $region; + + ($err, $msg) = $clearadm->AddView(%view); + + error "Unable to add VOB $tag (Region: $region) - $msg", $err if $err; + + $total{'Views added'}++; + } # if + + return; +} # updateView + +my %opts; + +# Main +my $startTime = time; + +GetOptions ( + \%opts, + 'usage' => sub { Usage }, + 'verbose' => sub { set_verbose }, + 'debug' => sub { set_debug }, + 'view=s', + 'vob=s', + 'region=s', +) or Usage "Invalid parameter"; + +Usage 'Extraneous options: ' . join ' ', @ARGV if @ARGV; + +unless ($opts{view} or $opts{vob}) { + $opts{view} = 'all'; + $opts{vob} = 'all'; +} # unless + +$opts{region} ||= 'all'; + +# Announce ourselves +verbose "$FindBin::Script V$VERSION"; + +if ($opts{view} and $opts{view} =~ /all/i) { + if ($opts{region} =~ /all/i) { + for my $region ($Clearcase::CC->regions) { + my $views = Clearcase::Views->new($region); + + for my $view ($views->views) { + verbose "Snapshotting view $view in region $region"; + + snapshotViewStorage $view, $region; + } # for + } # for + } else { + my $views = Clearcase::Views->new($opts{region}); + + for my $view ($views->views) { + verbose "Snapshotting view $view in region $opts{region}"; + + snapshotViewStorage $view, $opts{region}; + } # for + } # if +} elsif ($opts{view}) { + if ($opts{region} =~ /all/i) { + for my $region ($Clearcase::CC->regions) { + verbose "Snapshotting view $opts{view} in region $region"; + + snapshotViewStorage $opts{view}, $region; + } # for + } else { + verbose "Snapshotting view $opts{view} in region $opts{region}"; + + snapshotViewStorage $opts{view}, $opts{region}; + } # if +} # if + +if ($opts{vob} and $opts{vob} =~ /all/i) { + if ($opts{region} =~ /all/i) { + for my $region ($Clearcase::CC->regions) { + my $vobs = Clearcase::Vobs->new(undef, $region); + + for my $vob ($vobs->vobs) { + verbose "Snapshotting vob $vob in region $region"; + + snapshotVobStorage $vob, $region; + } # for + } # for + } else { + my $vobs = Clearcase::Vobs->new(undef, $opts{region}); + + for my $vob ($vobs->vobs) { + verbose "Snapshotting vob $vob in region $opts{region}"; + + snapshotVobStorage $vob, $opts{region}; + } # for + } # if +} elsif ($opts{vob}) { + if ($opts{region} =~ /all/i) { + for my $region ($Clearcase::CC->regions) { + verbose "Snapshotting vob $opts{vob} in region $region"; + + snapshotVobStorage $opts{vob}, $region; + } # for + } else { + verbose "Snapshotting vob $opts{vob} in region $opts{region}"; + + snapshotVobStorage $opts{vob}, $opts{region}; + } # if +} # if + +if (get_verbose) { + Stats \%total; + display_duration $startTime; +} # if + +=pod + +=head1 CONFIGURATION AND ENVIRONMENT + +DEBUG: If set then $debug is set to this level. + +VERBOSE: If set then $verbose is set to this level. + +TRACE: If set then $trace is set to this level. + +=head1 DEPENDENCIES + +=head2 Perl Modules + +L + +L + +L + +=head2 ClearSCM Perl Modules + +=begin man + + Clearadm + Clearexec + DateUtils + Display + Utils + +=end man + +=begin html + +
+Clearadm
+Clearcase::Vobs
+Clearcase::Vob
+Clearcase::Views
+Clearcase::View
+DateUtils
+Display
+Utils
+
+ +=end html + +=head1 BUGS AND LIMITATIONS + +There are no known bugs in this script + +Please report problems to Andrew DeFaria . + +=head1 LICENSE AND COPYRIGHT + +Copyright (c) 2010, ClearSCM, Inc. All rights reserved. + +=cut diff --git a/clearadm/updatefs.pl b/clearadm/updatefs.pl index 7340dde..caa7d07 100755 --- a/clearadm/updatefs.pl +++ b/clearadm/updatefs.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -54,6 +54,7 @@ use warnings; use Net::Domain qw(hostname); use FindBin; use Getopt::Long; +use Convert::Base64; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; @@ -94,47 +95,30 @@ sub snapshotFS ($$) { # Sun is so braindead! # TODO: Verify this works under Solaris if ($system{type} eq 'Unix') { - foreach ('ufs', 'vxfs') { - my $cmd = "/usr/bin/df -k -F $filesystem{mount}"; + my $cmd = "df -v $filesystem{mount}"; - my ($status, @unixfs) = $clearexec->execute ($cmd); + my ($status, @unixfs) = $clearexec->execute ($cmd); - if ($status != 0) { - error ('Unable to determine fsinfo for ' - . "$system{name}:$filesystem{mount} ($cmd)\n" . - join "\n", @unixfs - ); - - return; - } # if + if ($status != 0) { + error ('Unable to determine fsinfo for ' + . "$system{name}:$filesystem{mount} ($cmd)\n" . + join "\n", @unixfs); + + return; + } # if - # Skip heading - shift @unixfs; + # Skip heading + shift @unixfs; - for (my $i = 0; $i < scalar @unixfs; $i++) { - my $firstField; - - # Trim leading and trailing spaces - $unixfs[$i] =~ s/^\s+//; - $unixfs[$i] =~ s/\s+$//; - - my @fields = split /\s+/, $unixfs[$i]; - - if (@fields == 1) { - $firstField = 0; - $i++; - - @fields = split /\s+/, $unixfs[$i];; - } else { - $firstField = 1; - } #if - - $fs{size} = $fields[$firstField] * 1024; - $fs{used} = $fields[$firstField + 1] * 1024; - $fs{free} = $fields[$firstField + 2] * 1024; - $fs{reserve} = $fs{size} - $fs{used} - $fs{free}; - } # for - } # foreach + for (my $i = 0; $i < scalar @unixfs; $i++) { + my @fields = split ' ', $unixfs[$i]; + + $fs{mount} = $fields[0]; + $fs{size} = $fields[2] * 1024; + $fs{used} = $fields[3] * 1024; + $fs{free} = $fields[4] * 1024; + $fs{reserve} = $fs{size} - $fs{used} - $fs{free}; + } # for } elsif ($system{type} eq 'Linux' or $system{type} eq 'Windows') { my $cmd = "/bin/df --block-size=1 -P $filesystem{mount}"; @@ -181,23 +165,23 @@ verbose "$FindBin::Script V$VERSION"; my $exit = 0; -foreach my $system ($clearadm->FindSystem ($host)) { - next if $$system{active} eq 'false'; +for my $system ($clearadm->FindSystem ($host)) { + next if $system->{active} eq 'false'; my $status = $clearexec->connectToServer ( - $$system{name}, - $$system{port} + $system->{name}, + $system->{port} ); unless ($status) { - verbose "Unable to connect to system $$system{name}:$$system{port}"; + verbose "Unable to connect to system $system->{name}:$system->{port}"; next; } # unless - foreach my $filesystem ($clearadm->FindFilesystem ($$system{name}, $fs)) { - verbose "Snapshotting $$system{name}:$$filesystem{filesystem}"; + for my $filesystem ($clearadm->FindFilesystem ($system->{name}, $fs)) { + verbose "Snapshotting $system->{name}:$filesystem->{filesystem}"; - my %fs = snapshotFS ($system, $$filesystem{filesystem}); + my %fs = snapshotFS ($system, $filesystem->{filesystem}); if (%fs) { my ($err, $msg) = $clearadm->AddFS (%fs); @@ -205,29 +189,49 @@ foreach my $system ($clearadm->FindSystem ($host)) { error $msg, $err if $err; } # if + # Generate graphs + my $cmd = "plotfs.cgi generate=1 system=$system->{name} filesystem=$filesystem->{filesystem} scaling=Day points=7"; + + verbose "Generating fssmall for $system->{name}:$filesystem->{filesystem}"; + my ($error, @output) = Execute("$cmd tiny=1 2>&1"); + + error 'Unable to generate fssmall' . join("\n", @output), $error if $error; + + $filesystem->{fssmall} = join '', @output; + + verbose "Generating fslarge for $system->{name}:$filesystem->{filesystem}"; + ($error, @output) = Execute("$cmd 2>&1"); + + error 'Unable to generate fslarge' . join("\n", @output), $error if $error; + + $filesystem->{fslarge} = join '', @output; + + my ($err, $msg) = $clearadm->UpdateFilesystem($system->{name}, $filesystem->{filesystem}, %$filesystem); + + error "Unable to update filesystem record $msg", $err if $err; + # Check if over threshold my %notification = $clearadm->GetNotification ('Filesystem'); - next - unless %notification; + next unless %notification; - my $usedPct = sprintf ( - '%.2f', - (($fs{used} + $fs{reserve}) / $fs{size}) * 100 - ); + my $usedPct = '0%'; + + $usedPct = sprintf ('%.2f', (($fs{used} + $fs{reserve}) / $fs{size}) * 100) if $fs{size} != 0; - if ($usedPct >= $$filesystem{threshold}) { + if ($usedPct >= $filesystem->{threshold}) { $exit = 2; - display YMDHMS . " System: $$filesystem{system} " - . "Filesystem: $$filesystem{filesystem} Used: $usedPct% " - . "Threshold: $$filesystem{threshold}"; + display YMDHMS + . " System: $filesystem->{system} " + . "Filesystem: $filesystem->{filesystem} Used: $usedPct% " + . "Threshold: $filesystem->{threshold}"; } else { - $clearadm->ClearNotifications ($$system{name}, $$filesystem{filesystem}); + $clearadm->ClearNotifications ($system->{name}, $filesystem->{filesystem}); } # if - } # foreach + } # for $clearexec->disconnectFromServer; -} # foreach +} # for exit $exit; diff --git a/clearadm/updatela.pl b/clearadm/updatela.pl index 5c8c078..99b935e 100755 --- a/clearadm/updatela.pl +++ b/clearadm/updatela.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl =pod @@ -160,8 +160,8 @@ verbose "$FindBin::Script V$VERSION"; my $exit = 0; -foreach my $system ($clearadm->FindSystem ($host)) { - next if $$system{active} eq 'false'; +for my $system ($clearadm->FindSystem ($host)) { + next if $system->{active} eq 'false'; my %load = snapshotLoad $system; @@ -170,24 +170,46 @@ foreach my $system ($clearadm->FindSystem ($host)) { error $msg, $err if $err; } else { - error "Unable to get loadavg for system $$system{name}", 1; + error "Unable to get loadavg for system $system->{name}", 1; } # if # Check if over threshold my %notification = $clearadm->GetNotification ('Loadavg'); - next - unless %notification; + next unless %notification; - if ($load{loadavg} >= $$system{loadavgThreshold}) { + if ($load{loadavg} >= $system->{loadavgThreshold}) { $exit = 2; - error YMDHMS . " System: $$system{name} " + error YMDHMS . " System: $system->{name} " . "Loadavg $load{loadavg} " - . "Threshold $$system{loadavgThreshold}"; + . "Threshold $system->{loadavgThreshold}"; } else { - $clearadm->ClearNotifications ($$system{name}); + $clearadm->ClearNotifications ($system->{name}); } # if -} # foreach + + # Add graphs to system record + my ($loadavgsmall, $loadavg); + + my $cmd = "plotloadavg.cgi generate=1 system=$system->{name} scaling=Hour points=24"; + + verbose "Generating loadavgsmall for $system->{name}"; + my ($error, @output) = Execute("$cmd tiny=1 2>&1"); + + error 'Unable to generate loadavgsmall' . join("\n", @output), $error if $error; + + $system->{loadavgsmall} = join '', @output; + + verbose "Generating loadavg for $system->{name}"; + ($error, @output) = Execute("$cmd 2>&1"); + + error 'Unable to generate loadavg' . join("\n", @output), $error if $error; + + $system->{loadavg} = join '', @output; + + my ($err, $msg) = $clearadm->UpdateSystem($system->{name}, %$system); + + error "Unable to udpate system record $msg", $err if $err; +} # for exit $exit; @@ -245,4 +267,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/updatesystem.pl b/clearadm/updatesystem.pl index 784303f..f5fbb06 100755 --- a/clearadm/updatesystem.pl +++ b/clearadm/updatesystem.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl =pod @@ -73,36 +73,43 @@ my $clearexec = Clearexec->new; my ($delete, $host, $port); -sub GetFilesystems (%) { +sub GetFilesystems(%) { my (%system) = @_; # TODO: Unix/Linux systems often vary as to what parameters df supports. The # -P is to intended to make this POSIX standard. Need to make sure this works # on other systems (i.e. Solaris, HP-UX, Redhat, etc.). - my $cmd = $system{type} eq 'Windows' ? 'df -TP' : 'df -l -TP'; + my $cmd = $system{type} eq 'Windows' + ? 'df -TP' + : $system{type} eq 'Unix' # I think I need to add a Solaris type + ? '/usr/xpg4/bin/df -l -P' + : 'df -l -TP'; my ($status, @output) = $clearexec->execute ($cmd); - error "Unable to execute uname -a - $!", $status . join ("\n". @output) + error "Unable to execute $cmd - $! (Status: $status)\n" . join ("\n". @output), $status if $status; # Real file systems start with "/" - @output = grep { /^\// } @output; + my @fs = grep { /^\// } @output; + + # Also add lines that start with rpool (This is for Solaris zones + push @fs, grep { /^rpool/ } @output; my @filesystems; - foreach (@output) { - if (/^(\S+)\s+(\S+).+?(\S+)$/) { + for (@fs) { + if (/^(\S+)\s+(\S+).+?(\S+)$/) { my %filesystem; $filesystem{system} = $system{name}; - $filesystem{filesystem} = $1; - $filesystem{fstype} = $2; - $filesystem{mount} = $3; + $filesystem{filesystem} = $1; + $filesystem{fstype} = $2; + $filesystem{mount} = $3; push @filesystems, \%filesystem; - } # if - } # foreach + } # if + } # for return @filesystems; } # GetFilesystems @@ -146,7 +153,13 @@ sub GatherSysInfo (;%) { if $status; # TODO: Need to handle this better - $system{type} = $output[0] =~ /cygwin/i ? 'Windows' : $output[0]; + if ($output[0] =~ /sunos/i) { + $system{type} = 'Unix'; + } elsif ($output[0] =~ /cygwin/i) { + $system{type} = 'Windows'; + } else { + $system{type} = 'Linux'; + } # if return %system; } # GatherSysInfo @@ -156,7 +169,7 @@ sub AddFilesystems (%) { my ($err, $msg); - foreach (GetFilesystems %system) { + for (GetFilesystems %system) { my %filesystem = %{$_}; my %oldfilesystem = $clearadm->GetFilesystem ( @@ -186,7 +199,7 @@ sub AddFilesystems (%) { . "$filesystem{system}:$filesystem{filesystem}" if $err; } # if - } # foreach + } # for return ($err, $msg); } # AddFilesystems @@ -284,14 +297,14 @@ if ($delete) { } # if } else { if ($host eq 'all') { - foreach ($clearadm->FindSystem) { + for ($clearadm->FindSystem) { my %system = %$_; ($err, $msg) = UpdateSystem (%system); error "Unable to update host $system{name}\n$msg", $err if $err; - } # foreach + } # for } else { my %system = $clearadm->GetSystem ($host); diff --git a/clearadm/viewager.cgi b/clearadm/viewager.cgi index c283ebe..1b978d9 100755 --- a/clearadm/viewager.cgi +++ b/clearadm/viewager.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -59,7 +59,8 @@ including old ones. Where: -u|sage: Displays usage - -region : Region to use when looking for the view + -region : Region to use when looking for views (Default + for generate action: all) -e|mail: Send email to owners of old views -ag|eThreshold: Number of days before a view is considered old (Default: 180) @@ -140,11 +141,11 @@ use User; my $VERSION = '$Revision: 1.11 $'; ($VERSION) = ($VERSION =~ /\$Revision: (.*) /); -my %opts = Vars; +my %opts; my $clearadm; -$opts{sortby} ||= 'age'; -$opts{region} ||= $Clearcase::CC->region; +$opts{sortby} ||= 'age'; +$opts{ageThreshold} = 180; # Default number of days a view must be older than my $subtitle = 'View Aging Report'; my $email; @@ -158,14 +159,13 @@ my $script = 'http://' . $port . $scriptName; -my (%total, $action); -my $ageThreshold = 180; # Default number of days a view must be older than +my %total; my $nbrThreshold; # Number of views threshold - think top 10 sub GenerateRegion ($) { my ($region) = @_; - verbose "Processing $region"; + verbose "Processing region $region"; $total{Regions}++; my $views = Clearcase::Views->new ($region); @@ -176,7 +176,7 @@ sub GenerateRegion ($) { my $i = 0; - foreach my $name (@Views) { + for my $name (@Views) { $total{Views}++; if (++$i % 100 == 0) { @@ -214,13 +214,17 @@ sub GenerateRegion ($) { my $ownerid = $view->owner; - if ($ownerid) { - $user = User->new ($ownerid); + if ($ownerid =~ /^\w+(\\|\/)(\w+)/) { + # TODO: Handle user identification better + #$user = User->new ($ownerid); - $user->{name} ||= 'Unknown'; + $ownerid = $2; + $user->{name} = $2; + $user->{email} = "$2\@gddsi.com"; } else { $ownerid = 'Unknown'; $user->{name} = 'Unknown'; + $user->{email} = 'unknown@gddsi.com'; } # if my $age = 0; @@ -235,29 +239,40 @@ sub GenerateRegion ($) { # Compute age $age = Age ($modified_date); $ageSuffix = $age != 1 ? 'days' : 'day'; - } else { - $modified_date = 'Unknown'; } # if - my ($err, $msg) = $clearadm->AddView ( - system => $view->shost, - region => $view->region, - tag => $view->tag, - owner => $ownerid, - ownerName => $user->{name}, - email => $user->{email}, - type => $type, - gpath => $gpath, - modified_date => $modified_date, - age => $age, - ageSuffix => $ageSuffix, + my %oldView = $clearadm->GetView($view->tag, $view->region); + + my ($err, $msg); + + my %viewRec = ( + system => $view->shost, + region => $view->region, + tag => $view->tag, + owner => $ownerid, + ownerName => $user->{name}, + email => $user->{email}, + type => $type, + gpath => $gpath, + age => $age, + ageSuffix => $ageSuffix, ); - error "Unable to add view $name to Clearadm\n$msg", $err - if $err; - } # foreach + # Some views have not yet been modified + $viewRec{modified} = $modified_date if $modified_date; + + if (%oldView) { + ($err, $msg) = $clearadm->UpdateView(%viewRec); - verbose "\nProcessed $region"; + error "Unable to update view $name in Clearadm\n$msg", $err if $err; + } else { + ($err, $msg) = $clearadm->AddView (%viewRec); + + error "Unable to add view $name to Clearadm\n$msg", $err if $err; + } # if + } # for + + verbose "\nProcessed region $region"; return; } # GenerateRegion @@ -266,9 +281,9 @@ sub Generate ($) { my ($region) = @_; if ($region =~ /all/i) { - foreach ($Clearcase::CC->regions) { - GenerateRegion $_; - } # foreach + for ($Clearcase::CC->regions) { + GenerateRegion $_; + } # for } else { GenerateRegion $region; } # if @@ -283,21 +298,21 @@ sub Report (@) { my @sortedViews; - if ($opts{sort} eq 'age') { + if ($opts{sortby} eq 'age') { # Sort by age numerically decending @sortedViews = sort { $$b{$opts{sortby}} <=> $$a{$opts{sortby}} } @views; } else { - @sortedViews = sort { $$a{$opts{sort}} cmp $$b{$opts{sort}} } @views; + @sortedViews = sort { $$a{$opts{sortby}} cmp $$b{$opts{sortby}} } @views; } # if $total{Reported} = 0; - foreach (@sortedViews) { + for (@sortedViews) { my %view = %{$_}; last if ($nbrThreshold and $total{Reported} + 1 > $nbrThreshold) or - ($view{age} < $ageThreshold); + ($view{age} < $opts{ageThreshold}); $total{Reported}++; @@ -321,11 +336,11 @@ format STDOUT_TOP = . format STDOUT = @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<<< @>>>> @<<<< -$view{tag},$view{owner},$view{type},$view{modified_date},$view{age},$view{ageSuffix} +$view{tag},$view{owner},$view{type},$view{modified},$view{age},$view{ageSuffix} . write; - } # foreach + } # for return; } # Report @@ -369,17 +384,12 @@ sub FormatTable ($@) { width => '100%', }; - my $registryHost = $Clearcase::CC->registry_host; - - $registryHost = font {class => 'unknown'}, 'Unknown' - unless $registryHost; - $caption .= start_Tr; $caption .= td { -align => 'left', -width => '30%', }, font ({-class => 'label'}, 'Registry: '), - $registryHost, '
', + setField($Clearcase::CC->registry_host), '
', font ({-class => 'label'}, 'Views: '), $nbrViews; $caption .= td { @@ -454,18 +464,20 @@ sub FormatTable ($@) { # Sort by age numerically decending @views = $opts{reverse} == 1 ? sort { $$a{$opts{sortby}} <=> $$b{$opts{sortby}} } @views - : sort { $$b{$opts{sortby}} <=> $$a{$opts{sortby}} } @views + : sort { $$b{$opts{sortby}} <=> $$a{$opts{sortby}} } @views; } else { @views = $opts{reverse} == 1 ? sort { $$b{$opts{sortby}} cmp $$a{$opts{sortby}} } @views - : sort { $$a{$opts{sortby}} cmp $$b{$opts{sortby}} } @views + : sort { $$a{$opts{sortby}} cmp $$b{$opts{sortby}} } @views; } # if my $i; - foreach (@views) { + for (@views) { my %view = %{$_}; + next if $view{region} ne $opts{region}; + my $owner = $view{owner}; if ($view{owner} =~ /\S+(\\|\/)(\S+)/) { @@ -474,7 +486,9 @@ sub FormatTable ($@) { $owner = $view{ownerName} ? $view{ownerName} : 'Unknown'; - my $rowClass= $view{age} > $ageThreshold ? 'oldview' : 'view'; + next if $opts{user} and $owner ne $opts{user}; + + my $rowClass= $view{age} > $opts{ageThreshold} ? 'oldview' : 'view'; $table .= start_Tr { class => $rowClass @@ -503,7 +517,7 @@ sub FormatTable ($@) { class => $view{type} }, $view{age}, ' ', $view{ageSuffix}); $table .= end_Tr; - } # foreach + } # for $table .= end_table; @@ -524,7 +538,7 @@ sub EmailUser ($@) {

Won't you take a moment to review this message and clean up any views you no longer need?

-

The following views are owned by you and have not been modified in $ageThreshold +

The following views are owned by you and have not been modified in $opts{ageThreshold} days:

END @@ -587,7 +601,7 @@ sub EmailUsers (@) { my @userViews; my $currUser = $views [0]->{ownerName}; - foreach (@views) { + for (@views) { my %view = %{$_}; next @@ -601,12 +615,12 @@ sub EmailUsers (@) { @userViews =(); } else { - if ($view{age} > $ageThreshold) { + if ($view{age} > $opts{ageThreshold}) { push @userViews, \%view if !-f "$view{gpath}/ageless"; } # if } # if - } # foreach + } # for display"Done"; @@ -627,18 +641,23 @@ GetOptions ( 'nbrThreshold=i', ) or Usage "Invalid parameter"; -local $| = 1; +# Get options from CGI +my %CGIOpts = Vars; + +$opts{$_} = $CGIOpts{$_} for keys %CGIOpts; -$opts{region} ||= ''; +local $| = 1; # Announce ourselves verbose "$FindBin::Script v$VERSION"; $clearadm = Clearadm->new; -if ($action and $action eq 'generate') { +if ($opts{action} and $opts{action} eq 'generate') { + $opts{region} ||= 'all'; + Generate $opts{region}; - Stats \%total; + Stats \%total if $opts{verbose}; } else { if ($opts{region} and ($opts{region} eq 'Clearcase not installed')) { heading; @@ -647,6 +666,8 @@ if ($action and $action eq 'generate') { exit 1; } # if + $opts{region} ||= $Clearcase::CC->region; + my @views = $clearadm->FindView ( 'all', $opts{region}, @@ -654,7 +675,7 @@ if ($action and $action eq 'generate') { $opts{user} ); - if ($action and $action eq 'report') { + if ($opts{action} and $opts{action} eq 'report') { Report @views; Stats \%total; } elsif ($email) { @@ -743,4 +764,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/viewdetails.cgi b/clearadm/viewdetails.cgi index 51e4265..ef9df9b 100755 --- a/clearadm/viewdetails.cgi +++ b/clearadm/viewdetails.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -57,6 +57,7 @@ use CGI::Carp 'fatalsToBrowser'; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; +use Clearadm; use ClearadmWeb; use Clearcase; use Clearcase::View; @@ -80,24 +81,11 @@ my $VERSION = '$Revision: 1.11 $'; sub DisplayTable ($) { my ($view) = @_; - # Data fields - my $tag = setField $view->tag; - my $server = setField $view->shost; - my $region = setField $view->region; - my $properties = setField $view->properties; - my $text_mode = setField $view->text_mode; my $permissions = setField $view->owner_mode . setField $view->group_mode . setField $view->other_mode; - my $owner = setField $view->owner; my $active = ($view->active) ? 'YES' : 'NO'; - my $created_by = setField $view->created_by; - my $created_date = setField $view->created_date; - my $cs_updated_by = setField $view->cs_updated_by; - my $cs_updated_date = setField $view->cs_updated_date; - my $gpath = setField $view->gpath; - my $access_path = setField $view->access_path; - my $uuid = setField $view->uuid; + my $gpath = $view->gpath; $gpath = font {-class => 'unknown'}, '<no-gpath>' if $gpath eq ''; @@ -107,45 +95,49 @@ sub DisplayTable ($) { -class => 'main', }; + my $clearadm = Clearadm->new; + + my %clearadmview = $clearadm->GetView($view->tag, $view->region); + display start_Tr; display th {class => 'label'}, 'Tag:'; - display td {class => 'data', colspan => 3}, $tag; + display td {class => 'data', colspan => 3}, setField $view->tag; display th {class => 'label'}, 'Server:'; display td {class => 'data'}, a { - href => "serverdetails.cgi?server=$server" - }, $server; + href => 'systemdetails.cgi?system=' . $view->shost + }, $view->shost; display th {class => 'label'}, 'Region:'; - display td {class => 'data'}, $region; + display td {class => 'data'}, $view->region; display end_Tr; display start_Tr; display th {class => 'label'}, 'Properties:'; - display td {class => 'data', colspan => 3}, $properties; + display td {class => 'data', colspan => 3}, $view->properties; display th {class => 'label'}, 'Text Mode:'; - display td {class => 'data'}, $text_mode; + display td {class => 'data'}, $view->text_mode; display th {class => 'label'}, 'Permission:'; display td {class => 'data'}, $permissions; display end_Tr; display start_Tr; display th {class => 'label'}, 'Owner:'; - display td {class => 'data', colspan => 3}, $owner; + display td {class => 'data', colspan => 3}, $view->owner; display th {class => 'label'}, 'Active:'; display td {class => 'data', colspan => 3}, $active; display end_Tr; display start_Tr; display th {class => 'label'}, 'Created by:'; - display td {class => 'data', colspan => 3}, $created_by; + display td {class => 'data', colspan => 3}, $view->created_by; display th {class => 'label'}, 'on:'; - display td {class => 'data', colspan => 3}, $created_date; + display td {class => 'data', colspan => 3}, $view->created_date; display end_Tr; display start_Tr; display th {class => 'label'}, 'CS Updated by:'; - display td {class => 'data', colspan => 3}, $cs_updated_by; + display td {class => 'data', colspan => 3}, $view->cs_updated_by; display th {class => 'label'}, 'on:'; - display td {class => 'data', colspan => 3}, $cs_updated_date; + display td {class => 'data', colspan => 3}, $view->cs_updated_date; display end_Tr; display start_Tr; @@ -155,12 +147,68 @@ sub DisplayTable ($) { display start_Tr; display th {class => 'label'}, 'Access Path:'; - display td {class => 'data', colspan => 7}, $access_path; + display td {class => 'data', colspan => 7}, $view->access_path; display end_Tr; display start_Tr; display th {class => 'label'}, 'UUID:'; - display td {class => 'data', colspan => 7}, $uuid; + display td {class => 'data', colspan => 7}, $view->uuid; + display end_Tr; + + display start_Tr; + display th {class => 'labelCentered', colspan => 10}, 'View Storage Pools'; + display end_Tr; + + my $image = $clearadmview{dbsmall} + ? "data:image/png;base64,$clearadmview{dbsmall}" + : "plotstorage.cgi?type=view&storage=db&tiny=1&tag=" . $view->tag; + + display start_Tr; + display th {class => 'label'}, 'Database:'; + display td {class => 'data', colspan => 3, align => 'center'}, a {href => + "plot.cgi?type=view&storage=db&scaling=Day&points=7®ion=" . $view->region . '&tag=' . $view->tag + }, img { + src => $image, + border => 0, + }; + + $image = $clearadmview{privatesmall} + ? "data:image/png;base64,$clearadmview{privatesmall}" + : "plotstorage.cgi?type=view&storage=private&tiny=1&tag=" . $view->tag; + + display th {class => 'label'}, 'Private:'; + display td {class => 'data', colspan => 5, align => 'center'}, a {href => + "plot.cgi?type=view&storage=private&scaling=Day&points=7®ion=" . $view->region . '&tag=' . $view->tag + }, img { + src => $image, + border => 0, + }; + display end_Tr; + + $image = $clearadmview{adminsmall} + ? "data:image/png;base64,$clearadmview{adminsmall}" + : "plotstorage.cgi?type=view&storage=admin&tiny=1&tag=" . $view->tag; + + display start_Tr; + display th {class => 'label'}, 'Admin:'; + display td {class => 'data', colspan => 3, align => 'center'}, a {href => + "plot.cgi?type=view&storage=admin&scaling=Day&points=7®ion=" . $view->region . '&tag=' . $view->tag + }, img { + src => $image, + border => 0, + }; + + $image = $clearadmview{totalsmall} + ? "data:image/png;base64,$clearadmview{totalsmall}" + : "plotstorage.cgi?type=view&storage=total&tiny=1&tag=" . $view->tag; + + display th {class => 'label'}, 'Total Space:'; + display td {class => 'data', colspan => 5, align => 'center'}, a {href => + "plot.cgi?type=view&storage=total&scaling=Day&points=7®ion=" . $view->region . '&tag=' . $view->tag + }, img { + src => $image, + border => 0, + }; display end_Tr; display end_table; @@ -258,9 +306,7 @@ unless ($opts{tag}) { exit; } # unless -my $view = Clearcase::View->new ($opts{tag}, $opts{region}); - -DisplayTable $view; +DisplayTable(Clearcase::View->new($opts{tag}, $opts{region})); footing; @@ -290,6 +336,7 @@ L =begin man + Clearadm ClearadmWeb Clearcase Clearcase::View @@ -302,6 +349,7 @@ L =begin html
+Clearadm
ClearadmWeb
Clearcase
Clearcase::View
@@ -322,4 +370,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/viewservers.cgi b/clearadm/viewservers.cgi index 1b91175..f214c04 100755 --- a/clearadm/viewservers.cgi +++ b/clearadm/viewservers.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -221,4 +221,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/clearadm/vobdetails.cgi b/clearadm/vobdetails.cgi new file mode 100755 index 0000000..420700c --- /dev/null +++ b/clearadm/vobdetails.cgi @@ -0,0 +1,444 @@ +#!/usr/local/bin/perl + +=pod + +=head1 NAME $RCSfile: vobdetails.cgi,v $ + +View Details + +=head1 VERSION + +=over + +=item Author + +Andrew DeFaria + +=item Revision + +$Revision: 1.11 $ + +=item Created: + +Mon Oct 25 11:10:47 PDT 2008 + +=item Modified: + +$Date: 2011/01/14 16:51:58 $ + +=back + +=head1 SYNOPSIS + + Usage vobdetails.cgi: [-u|sage] [-r|egion ] -vo|b + [-ve|rbose] [-d|ebug] + + Where: + -u|sage: Displays usage + -r|egion : Region to use when looking for the vob + -vo|b : Tag of vob to display details for + + -ve|rbose: Be verbose + -d|ebug: Output debug messages + +=head2 DESCRIPTION + +This script display the details for the given vob + +=cut + +use strict; +use warnings; + +use FindBin; +use Getopt::Long; +use CGI qw (:standard :cgi-lib *table start_Tr end_Tr); +use CGI::Carp 'fatalsToBrowser'; + +use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; + +use Clearadm; +use ClearadmWeb; +use Clearcase; +use Clearcase::Vob; +use Clearcase::Vobs; +use Display; +use Utils; + +my %opts = Vars; + +my $subtitle = 'VOB Details'; + +if ($Clearcase::CC->region) { + $opts{region} ||= $Clearcase::CC->region; +} else { + $opts{region} ||= 'Clearcase not installed'; +} # if + +my $VERSION = '$Revision: 1.11 $'; + ($VERSION) = ($VERSION =~ /\$Revision: (.*) /); + +sub DisplayTable ($) { + my ($vob) = @_; + + my $active = ($vob->active) ? 'YES' : 'NO'; + my $gpath = $vob->gpath; + + $gpath = font {-class => 'unknown'}, '<no-gpath>' + if $gpath eq ''; + + display start_table { + -cellspacing => 1, + -class => 'main', + }; + + my $clearadm = Clearadm->new; + + my %clearadmvob = $clearadm->GetVob($vob->tag, $vob->region); + + display start_Tr; + display th {class => 'label'}, 'Tag:'; + display td {class => 'data', colspan => 3}, setField $vob->tag; + display th {class => 'label'}, 'Server:'; + display td {class => 'data'}, a { + href => 'systemdetails.cgi?system=' . $vob->shost + }, $vob->shost; + display th {class => 'label'}, 'Region:'; + display td {class => 'data', colspan => 3}, $vob->region; + display end_Tr; + + display start_Tr; + display th {class => 'label'}, 'Type:'; + display td {class => 'data', colspan => 3}, $vob->access; + display th {class => 'label'}, 'Attributes:'; + display td {class => 'data'}, $vob->vob_registry_attributes; + display th {class => 'label'}, 'Mount Opts:'; + display td {class => 'data', colspan => 3}, $vob->mopts; + display end_Tr; + + display start_Tr; + display th {class => 'label'}, 'Owner:'; + display td {class => 'data', colspan => 3}, $vob->owner; + display th {class => 'label'}, 'Active:'; + display td {class => 'data'}, $active; + display th {class => 'label'}, 'ACLs Enabled:'; + display td {class => 'data', colspan => 3}, $vob->aclsEnabled; + display end_Tr; + + display start_Tr; + display th {class => 'label'}, 'Created by:'; + display td {class => 'data', colspan => 3}, $vob->ownername; + display th {class => 'label'}, 'on:'; + display td {class => 'data'}, $vob->created; + display th {class => 'label'}, 'Atomic Checkin:'; + display td {class => 'data', colspan => 3}, $vob->atomicCheckin; + display end_Tr; + + display start_Tr; + display th {class => 'label'}, 'Comment:'; + display td {class => 'data', colspan => 5}, $vob->comment; + display th {class => 'label'}, 'Schema Version:'; + display td {class => 'data', colspan => 3}, $vob->schemaVersion; + display end_Tr; + + display start_Tr; + display th {class => 'label'}, 'Global Path:'; + display td {class => 'data', colspan => 5}, $gpath; + display th {class => 'label'}, 'Registry Attributes:'; + display td {class => 'data', colspan => 3}, $vob->vob_registry_attributes; + display end_Tr; + + display start_Tr; + display th {class => 'label'}, 'Access Path:'; + display td {class => 'data', colspan => 5}, $vob->access_path; + display th {class => 'label'}, 'Group:'; + display td {class => 'data', colspan => 3}, $vob->group; + display end_Tr; + + display start_Tr; + display th {class => 'label'}, 'Family UUID:'; + display td {class => 'data', colspan => 5}, $vob->family_uuid; + display th {class => 'label'}, 'Remote Privilage:'; + display td {class => 'data', colspan => 3}, $vob->remotePrivilege; + display end_Tr; + + display start_Tr; + display th {class => 'label'}, 'Replica UUID:'; + display td {class => 'data', colspan => 5}, $vob->replica_uuid; + display th {class => 'label'}, 'Master Replica:'; + display td {class => 'data', colspan => 3}, $vob->masterReplica; + display end_Tr; + + my $groups = join "
", $vob->groups; + + display start_Tr; + display th {class => 'label'}, 'Groups:'; + display td {class => 'data', colspan => 10}, $groups; + display end_Tr; + + my %attributes = $vob->attributes; + my $attributes = ''; + + for (keys %attributes) { + $attributes .= "$_ = $attributes{$_}
"; + } # for + + display start_Tr; + display th {class => 'label'}, 'Attributes:'; + display td {class => 'data', colspan => 10}, $attributes; + display end_Tr; + + my %hyperlinks = $vob->hyperlinks; + my $hyperlinks = ''; + + for (keys %hyperlinks) { + $hyperlinks .= "$_ = $hyperlinks{$_}
"; + } # for + + display start_Tr; + display th {class => 'label'}, 'Hyperlinks:'; + display td {class => 'data', colspan => 10}, $hyperlinks; + display end_Tr; + + display start_Tr; + display th {class => 'labelCentered', colspan => 10}, 'VOB Storage Pools'; + display end_Tr; + + my $image = $clearadmvob{adminsmall} + ? "data:image/png;base64,$clearadmvob{adminsmall}" + : "plotstorage.cgi?type=vob&storage=admin&tiny=1&tag=" . $vob->tag; + + display start_Tr; + display th {class => 'label'}, 'Admin:'; + display td {class => 'data', colspan => 4, align => 'center'}, a {href => + 'plot.cgi?type=vob&storage=admin&scaling=Day&points=7®ion=' . $vob->region . '&tag=' . $vob->tag + }, img { + src => $image, + border => 0, + }; + + $image = $clearadmvob{sourcesmall} + ? "data:image/png;base64,$clearadmvob{sourcesmall}" + : 'plotstorage.cgi?type=vob&storage=source&tiny=1®ion=' . $vob->region . '&tag=' . $vob->tag; + + display th {class => 'label'}, 'Source Size:'; + display td {class => 'data', colspan => 4, align => 'center'}, a {href => + 'plot.cgi?type=vob&storage=source&scaling=Day&points=7®ion=' . $vob->region . '&tag=' . $vob->tag + }, img { + src => $image, + border => 0, + }; + display end_Tr; + + display start_Tr; + $image = $clearadmvob{dbsmall} + ? "data:image/png;base64,$clearadmvob{dbsmall}" + : 'plotstorage.cgi?type=vob&storage=db&tiny=1®ion=' . $vob->region . '&tag=' . $vob->tag; + + display th {class => 'label'}, 'Database:'; + display td {class => 'data', colspan => 4, align => 'center'}, a {href => + 'plot.cgi?type=vob&storage=db&scaling=Day&points=7®ion=' . $vob->region . '&tag=' . $vob->tag + }, img { + src => $image, + border => 0, + }; + + $image = $clearadmvob{derivedobjsmall} + ? "data:image/png;base64,$clearadmvob{derivedobjsmall}" + : 'plotstorage.cgi?type=vob&storage=derivedobj&tiny=1®ion=' . $vob->region . '&tag=' . $vob->tag; + + display th {class => 'label'}, 'Derived Obj:'; + display td {class => 'data', colspan => 4, align => 'center'}, a {href => + 'plot.cgi?type=vob&storage=derivedobj&scaling=Day&points=7®ion=' . $vob->region . '&tag=' . $vob->tag + }, img { + src => $image, + border => 0, + }; + display end_Tr; + + display start_Tr; + $image = $clearadmvob{cleartextsmall} + ? "data:image/png;base64,$clearadmvob{cleartextsmall}" + : 'plotstorage.cgi?type=vob&storage=cleartext&tiny=1®ion=' . $vob->retion . '&tag=' . $vob->tag; + + display th {class => 'label'}, 'Cleartext:'; + display td {class => 'data', colspan => 4, align => 'center'}, a {href => + 'plot.cgi?type=vob&storage=cleartext&scaling=Day&points=7®ion=' . $vob->region . '&tag=' . $vob->tag + }, img { + src => $image, + border => 0, + }; + + $image = $clearadmvob{totalsmall} + ? "data:image/png;base64,$clearadmvob{totalsmall}" + : 'plotstorage.cgi?type=vob&storage=total&tiny=1®ion=' . $vob->region . '&tag=' . $vob->tag; + + display th {class => 'label'}, 'Total Size:'; + display td {class => 'data', colspan => 4, align => 'center'}, a {href => + 'plot.cgi?type=vob&storage=total&scaling=Day&points=7®ion=' . $vob->region . '&tag=' . $vob->tag + }, img { + src => $image, + border => 0, + }; + display end_Tr; + + display end_table; + + return; +} # DisplayTable + +sub DisplayRegion { + display start_form (action => 'vobdetails.cgi'); + + display 'Region '; + + my ($defaultRegion, @regions) = ('', ('Clearcase not installed')); + + display popup_menu ( + -name => 'region', + -values => [@regions], + -default => $defaultRegion, + -onchange => 'submit();', + ); + + display submit ( + -value => 'Go', + ); + + display end_form; + + return +} # DisplayRegion + +sub DisplayVobs($) { + my ($region) = @_; + + my @vobs = Clearcase::Vobs->new ($region); + + unless (@vobs) { + push @vobs, 'No VOBs'; + } # unless + + display start_form (action => 'vobdetails.cgi'); + + display 'Region '; + + display popup_menu ( + -name => 'region', + -values => [$Clearcase::CC->regions], + -default => $region, + -onchange => 'submit();', + ); + + display b ' VOB: '; + + display popup_menu ( + -name => 'vob', + -values => \@vobs, + -onchange => 'submit();', + ); + + display submit ( + -value => 'Go', + ); + + display end_form; + + return; +} # DisplayVobs + +# Main +GetOptions ( + \%opts, + 'usage' => sub { Usage }, + 'verbose' => sub { set_verbose }, + 'debug' => sub { set_debug }, + 'vob=s', + 'region=s', +) or Usage "Invalid parameter"; + +# Announce ourselves +verbose "$FindBin::Script v$VERSION"; + +heading $subtitle; + +display h1 { + -class => 'center', +}, $subtitle; + +unless ($opts{tag}) { + unless ($opts{region}) { + DisplayRegion; + } else { + DisplayVobs $opts{region}; + } # unless + + exit; +} # unless + +my $vob = Clearcase::Vob->new ($opts{tag}, $opts{region}); + +DisplayTable $vob; + +footing; + +=pod + +=head1 CONFIGURATION AND ENVIRONMENT + +DEBUG: If set then $debug is set to this level. + +VERBOSE: If set then $verbose is set to this level. + +TRACE: If set then $trace is set to this level. + +=head1 DEPENDENCIES + +=head2 Perl Modules + +L + +L + +L + +L + +=head2 ClearSCM Perl Modules + +=begin man + + ClearadmWeb + Clearcase + Clearcase::View + Clearcase::Views + Display + Utils + +=end man + +=begin html + +
+Clearadm
+ClearadmWeb
+Clearcase
+Clearcase::View
+Clearcase::Views
+Display
+Utils
+
+ +=end html + +=head1 BUGS AND LIMITATIONS + +There are no known bugs in this script + +Please report problems to Andrew DeFaria . + +=head1 LICENSE AND COPYRIGHT + +Copyright (c) 2010, ClearSCM, Inc. All rights reserved. + +=cut diff --git a/clearadm/vobservers.cgi b/clearadm/vobservers.cgi index 453fd09..6748c9e 100755 --- a/clearadm/vobservers.cgi +++ b/clearadm/vobservers.cgi @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/local/bin/perl =pod @@ -51,7 +51,7 @@ use warnings; use FindBin; use Getopt::Long; -use CGI qw (:standard :cgi-lib *table start_Tr end_Tr); +use CGI qw (:standard :cgi-lib *table start_Tr end_Tr start_ol end_ol); use CGI::Carp 'fatalsToBrowser'; use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; @@ -59,6 +59,8 @@ use lib "$FindBin::Bin/lib", "$FindBin::Bin/../lib"; use ClearadmWeb; use Clearcase; use Clearcase::Server; +use Clearcase::Vobs; +use Clearcase::Vob; use Display; use Utils; @@ -71,6 +73,68 @@ my $subtitle = 'Vob Servers'; my $VERSION = '$Revision: 1.9 $'; ($VERSION) = ($VERSION =~ /\$Revision: (.*) /); +sub DisplayVobs($) { + my ($server) = @_; + + display h3 { + -class => 'center', + }, "Vobs on " . $server->name; + + display start_table; + + display start_Tr; + display th { + -class => 'labelCentered', + }, '#'; + display th { + -class => 'labelCentered', + }, 'Tag'; + display th { + -class => 'labelCentered', + }, 'Type'; + display th { + -class => 'labelCentered', + }, 'Active'; + display th { + -class => 'labelCentered', + }, 'Access Path'; + display th { + -class => 'labelCentered', + }, 'Attributes'; + display end_Tr; + + my $i = 0; + + my $vobs = Clearcase::Vobs->new($server->name); + + for (sort $vobs->vobs) { + my $vob = Clearcase::Vob->new($_); + + display start_Tr; + display td { + -class => 'dataCentered', + }, ++$i; + display td { + -class => 'data', + }, a {-href => "vobdetails.cgi?tag=" . $vob->tag}, $vob->tag; + display td { + -class => 'dataCentered', + }, $vob->access; + display td { + -class => 'dataCentered', + }, $vob->active; + display td { + -class => 'data', + }, $vob->access_path; + display td { + -class => 'data', + }, $vob->vob_registry_attributes; + display end_Tr; + } # for + + display end_table; +} # DisplayVob + sub DisplayTable (@) { my (@vobServers) = @_; @@ -94,39 +158,167 @@ sub DisplayTable (@) { display th { -class => 'labelCentered', }, 'OS Version'; + display th { + -class => 'labelCentered', + }, 'Hardware'; + display th { + -class => 'labelCentered', + }, 'Registry Host'; + display th { + -class => 'labelCentered', + }, 'Region'; + display th { + -class => 'labelCentered', + }, 'License Host'; display end_Tr; my $i = 0; - foreach (@vobServers) { - my $server = Clearcase::Server->new ($_, $opts{region}); - - # Data fields - my $name = $server->name; - my $ccVer = $server->ccVer; - my $osVer = $server->osVer; + my $server; - $ccVer ||= $unknown; - $osVer ||= $unknown; + for (@vobServers) { + $server = Clearcase::Server->new ($_, $opts{region}); display start_Tr; display td { -class => 'dataCentered', }, ++$i; display td { - -class => 'data', - }, a {-href => "serverdetails.cgi?server=$name"}, $name; + -class => 'dataCentered', + }, a {-href => "systemdetails.cgi?system=" . $server->name}, $server->name; display td { - -class => 'data', - }, $ccVer; + -class => 'dataCentered', + }, $server->ccVer; display td { - -class => 'data', - }, $osVer; + -class => 'dataCentered', + }, $server->osVer; + display td { + -class => 'dataCentered', + }, $server->hardware; + display td { + -class => 'dataCentered', + }, a {-href => "systemdetails.cgi?system=" . $server->registryHost}, $server->registryHost; + display td { + -class => 'dataCentered', + }, $server->registryRegion; + display td { + -class => 'dataCentered', + }, $server->licenseHost; display end_Tr; - } # foreach - display end_table; + display start_Tr; + display th { + -class => 'labelCentered', + }, 'MVFS'; + display th { + -class => 'labelCentered', + }, 'Scaling'; + display th { + -class => 'labelCentered', + }, 'Free Mnodes'; + display th { + -class => 'labelCentered', + }, 'Free Mnodes Cleartext'; + display th { + -class => 'labelCentered', + }, 'File names'; + display th { + -class => 'labelCentered', + }, 'Directory names'; + display th { + -class => 'labelCentered', + }, 'Blocks Per Directory'; + display th { + -class => 'labelCentered', + }, 'Names not found'; + display end_Tr; + + display start_Tr; + display td { + -class => 'dataCentered', + }, ' '; + display td { + -class => 'dataCentered', + }, $server->scalingFactor; + display td { + -class => 'dataRight', + }, $server->mvfsFreeMnodes; + display td { + -class => 'dataRight', + }, $server->mvfsFreeMnodesCleartext; + display td { + -class => 'dataRight', + }, $server->mvfsFileNames; + display td { + -class => 'dataRight', + }, $server->mvfsDirectoryNames; + display td { + -class => 'dataRight', + }, $server->mvfsBlocksPerDirectory; + display td { + -class => 'dataRight', + }, $server->mvfsNamesNotFound; + display end_Tr; + + display start_Tr; + display th { + -class => 'labelCentered', + }, 'RPC Handles'; + display th { + -class => 'labelCentered', + }, 'Cleartext Idle Lifetime'; + display th { + -class => 'labelCentered', + }, 'VOB HTS'; + display th { + -class => 'labelCentered', + }, 'Cleartext HTS'; + display th { + -class => 'labelCentered', + }, 'Thread HTS'; + display th { + -class => 'labelCentered', + }, 'DNC HTS'; + display th { + -class => 'labelCentered', + }, 'Process HTS'; + display th { + -class => 'labelCentered', + }, 'Initial Mnode Table Size'; + display end_Tr; + + display start_Tr; + display td { + -class => 'dataRight', + }, $server->mvfsRPCHandles; + display td { + -class => 'dataRight', + }, $server->cleartextIdleLifetime; + display td { + -class => 'dataRight', + }, $server->vobHashTableSize; + display td { + -class => 'dataRight', + }, $server->cleartextHashTableSize; + display td { + -class => 'dataRight', + }, $server->threadHashTableSize; + display td { + -class => 'dataRight', + }, $server->dncHashTableSize; + display td { + -class => 'dataRight', + }, $server->processHashTableSize; + display td { + -class => 'dataRight', + }, $server->mvfsInitialMnodeTableSize; + display end_Tr; + display end_table; + } # for + display p; + DisplayVobs $server; + return; } # DisplayTable @@ -158,11 +350,11 @@ error "Unable to list all vobs in the region $opts{region}" my %vobServers; -foreach (@output) { +for (@output) { if (/Server host: (.*)/) { $vobServers{$1} = undef; } # if -} # foreach +} # for DisplayTable sort (keys (%vobServers)); @@ -224,4 +416,4 @@ Please report problems to Andrew DeFaria . Copyright (c) 2010, ClearSCM, Inc. All rights reserved. -=cut \ No newline at end of file +=cut diff --git a/data/machines b/data/machines index 83d6961..db2246e 100644 --- a/data/machines +++ b/data/machines @@ -11,28 +11,22 @@ # Column 4 ClearCase Version (if applicable) # Column 5 Owner (if known) # Column 6 Usage (if known) -chargers:Sun:Solaris 5.9:7.0.1.1:ccadm:ranview1 -colts:Sun:Solaris 5.9:7.0.1.0:ccadm:ranview2 -cowboys:Sun:Solaris 5.9:7.0.1.0:ccadm:ranvob1/registry server -niners:Sun:Solaris 5.9:2003.06.10+:ccadm: -patriots:Sun:Solaris 5.9:7.0.1.0:ccadm:ranvob2 -rams:Sun:Solaris 5.9:7.0.1.0:ccadm:ranvob3/registry server -#ranadm1:Sun:Solaris 5.9::ccadm:Jumpstart, PowerBroker, NIS, SMTP, DNS, NTP -ranadm2:Sun:Solaris 5.9:2003.06.10+:ccadm:License server, Sys admin, NIS, Home Directory server -ranbkp2::::ccadm:Backup -ranbuild1:Sun:Solaris 5.8:7.0.1.0:ccadm:builds -ranbuild2:Sun:Solaris 5.9:2003.06.10+:ccadm:builds -ranbuild4:Sun:Solaris 5.9:7.0.1.1:ccadm:builds -rancpp01:Redhat Linux:2.6.18.53.Eel5xen::ccadm: -rancpp02:Redhat Linux:2.6.18.53.Eel5xen::ccadm: -rancpp03:Redhat Linux:2.6.18.53.Eel5xen::ccadm: -rancpp10:Redhat Linux:2.6.18.53.Eel5xen::ccadm: -#randbs:Sun:Solaris 5.9::ccadm:CQ DB server/Bldforge -randws094:Sun:Solaris 5.10:7.0.1.1:John Hartin:Old workstation -randws103:Sun:Solaris 5.9:7.0.1.1:: -randws106:Sun:Solaris 5.9:2003.06.10+:: -randws113:Sun:Solaris 5.9:7.0.1.1:: -randws114:Sun:Solaris 5.9:2003.06.10+:Tony Trujilo: -randws119:Sun:Solaris 5.9:7.0.1.1:Hy Truong:Workstation -ranlin03:Redhat Linux:2.4.21-50.Elsmp::ccadm: -ranray:Sun:Solaris 5.9:2003.06.10+:ccadm: +rdeadm1:Oracle:Solaris 5.11:9.0.0:Tools Team:Primary Admin Server, NIS Master, DNS slave +rdeadm2:Oracle:Solaris 5.11:9.0.0:Tools Team:Secondary Admin Server, home, NIS Slave, DNS Master, mail and prj +rdevob1:Oracle:Solaris 5.11:9.0.0:Tools Team:Clearcase Vob Server 1 +rdevob2:Oracle:Solaris 5.11:9.0.0:Tools Team:Clearcase Vob Server 2 +rdeview1:Oracle:Solaris 5.11:9.0.0:Tools Team:Clearcase View Server +rdebuild1:Oracle:Solaris 5.11:9.0.0:Tools Team:Build Server 1 +rdebuild2:Oracle:Solaris 5.11:9.0.0:Tools Team:Build Server 2 +rdebuild3:Oracle:Solaris 5.11:9.0.0:Tools Team:Build Server 3 +rdebuild4:Oracle:Solaris 5.11:9.0.0:Tools Team:Build Server 4 +rdedws000:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws033:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws035:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws036:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws094:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws103:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws106:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws113:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws114:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop +rdedws119:Oracle:Solaris 5.11:9.0.0:Tools Team:Engineering Desktop diff --git a/data/ran b/data/ran new file mode 100644 index 0000000..1e408cb --- /dev/null +++ b/data/ran @@ -0,0 +1,44 @@ +################################################################################ +# +# File: machines +# Description: Defintion of machines for allmach +# Author: Andrew@DeFaria.com +# +################################################################################ +# Column 1 Machine name +# Column 2 Model +# Column 3 OS Version +# Column 4 ClearCase Version (if applicable) +# Column 5 Owner (if known) +# Column 6 Usage (if known) +cowboys:Sun:Solaris 5.9:7.0.1.0:ccadm:ranvob1/registry server +patriots:Sun:?:Solaris 5.9:7.0.1.0:ccadm:ranvob2 +rams:Sun:Solaris 5.9:7.0.1.0:ccadm:ranvob3/registry server +chargers:Sun:Solaris 5.9:70.1.1:ccadm:ranview1 +colts:Sun:Solaris 5.9:7.0.1.0:ccadm:ranview2 +ranbuild1:Sun:Solaris 5.8:7.0.1.0:ccadm:builds +ranbuild2:Sun:Solaris 5.9:2003.06.10+:ccadm:builds +ranbuild4:Sun:Solaris 5.9:7.0.1.1:ccadm:builds +randws119:Sun:Solaris 5.9:7.0.1.1:Hy Truong:Workstation +randws094:Sun:Solaris 5.10:7.0.1.1:John Hartin:Old workstation +randws033:Sun:Solaris 5.10:Sam Schwalm:Workstation +randws103:Sun:Solaris 5.9:7.0.1.1:?:? +randws106:Sun:Solaris 5.9:2003.06.10+:?:? +randws113:Sun:Solaris 5.9:7.0.1.1:?:? +randws114:Sun:Solaris 5.9:2003.06.10+:Tony Trujilo:? +randws000:Sun:Solaris 5.10:7.0.1.1:?:? +randws021:?:?:?:?:? +randws035:?:?:?:ccadm:? +randws036:?:?:?:ccadm:? +ranadm1:Sun:Solaris 5.9:?:ccadm:Jumpstart, PowerBroker, NIS, SMTP, DNS, NTP +ranadm2:Sun:Solaris 5.9:2003.06.10+:ccadm:License server, Sys admin, NIS, Home Directory server +ranray:Sun:Solaris 5.9:2003.06.10+:ccadm:? +ranray16:?:?:?:ccadm:Thin client to ranray +niners:Sun:Solaris 5.9:2003.06.10+:ccadm:? +randbs:Sun:Solaris 5.9:?:ccadm:CQ DB server/Bldforge +ranbkp2:?:?:?:ccadm:? +ranlin03:Redhat Linux:2.4.21-50.Elsmp:?:ccadm:? +rancpp10:Redhat Linux:2.6.18.53.Eel5xen:?:ccadm:? +rancpp01:Redhat Linux:2.6.18.53.Eel5xen:?:ccadm:? +rancpp02:Redhat Linux:2.6.18.53.Eel5xen:?:ccadm:? +rancpp03:Redhat Linux:2.6.18.53.Eel5xen:?:ccadm:? diff --git a/etc/machines.sql b/etc/machines.sql index 3691e75..0e9fb6a 100644 --- a/etc/machines.sql +++ b/etc/machines.sql @@ -24,6 +24,7 @@ use machines; create table system ( name varchar (255) not null, model tinytext, + domain tinytext, alias varchar (255), active enum ( 'true', diff --git a/etc/ranmachines.sql b/etc/ranmachines.sql new file mode 100644 index 0000000..83c6bdf --- /dev/null +++ b/etc/ranmachines.sql @@ -0,0 +1,254 @@ +insert into system values ( + 'cowboys', + 'Oracle', + 'RAN', + 'gdvob1', + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '7.0.0.1', + 'Unix', + null, + 'Primary Vob Server' +); + +insert into system values ( + 'patriots', + 'Oracle', + 'RAN', + 'gdvob2', + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '7.0.0.1', + 'Unix', + null, + null +); + +insert into system values ( + 'rams', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '7.0.0.1', + 'Unix', + null, + null +); + +insert into system values ( + 'chargers', + 'Oracle', + 'RAN', + 'gdview1', + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '7.0.0.1', + 'Unix', + null, + 'View Server' +); + +insert into system values ( + 'ranbuild1', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.8', + '7.0.1.1', + 'Unix', + null, + 'Build Server 1' +); + +insert into system values ( + 'ranbuild2', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '7.0.1.1', + 'Unix', + null, + 'Build Server 2' +); + +insert into system values ( + 'ranbuild4', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '7.0.1.1', + 'Unix', + null, + 'Build Server 4' +); + +insert into system values ( + 'randws119', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '7.0.1.1', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'randws094', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.10', + '7.0.1.1', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'randws033', + 'Oracle', + 'RAN', + null, + 'false', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.10', + '7.0.1.1', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'randws103', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '7.0.1.1', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'randws114', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '2003.06.10', + 'Unix', + null, + 'RAN Workstation' +); + +insert into system values ( + 'randws000', + 'Oracle', + 'RAN', + null, + 'false', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.10', + '7.0.1.1', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'ranadm1', + 'Oracle', + 'RAN', + null, + 'false', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '2003.06.10+', + 'Unix', + null, + 'Jumpstart, PowerBroker, NIS, SMTP, DNS, NTP' +); + +insert into system values ( + 'ranadm2', + 'Oracle', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '2003.06.10+', + 'Unix', + null, + 'License server, Sys admin, NIS, Home Directory server' +); + +insert into system values ( + 'niners', + 'Oracle', + 'RAN', + 'nmsbuild1', + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.9', + '2003.06.10+', + 'Unix', + null, + 'RAN Workstation' +); + +insert into system values ( + 'ranlin03', + 'Redhat', + 'RAN', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Linux 2.4.21-50', + '2003.06.10+', + 'Linux', + null, + 'Workstation' +); diff --git a/etc/rdemachines.sql b/etc/rdemachines.sql new file mode 100644 index 0000000..817858f --- /dev/null +++ b/etc/rdemachines.sql @@ -0,0 +1,285 @@ +insert into system values ( + 'rdeadm1', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Primary Admin Server, NIS Master, DNS slave' +); + +insert into system values ( + 'rdeadm2', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Secondary Admin Server, home, NIS Slave, DNS Master' +); + +insert into system values ( + 'rdevob1', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Vob Server' +); + +insert into system values ( + 'rdevob2', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Vob Server (Ericson)' +); + +insert into system values ( + 'rdeview1', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'View Server' +); + +insert into system values ( + 'rdebuild1', + 'Oracle', + 'RDE', + 'rdebf1', + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Build Server 1' +); + +insert into system values ( + 'rdebuild2', + 'Oracle', + 'RDE', + 'rdebf2', + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Build Server 2' +); + +insert into system values ( + 'rdebuild3', + 'Oracle', + 'RDE', + 'rdebf3', + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Build Server 3' +); + +insert into system values ( + 'rdebuild4', + 'Oracle', + 'RDE', + 'ranbf4', + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Build Server 4' +); + +insert into system values ( + 'rdedws000', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws033', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws035', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws036', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws094', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws103', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws106', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws113', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws114', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + +insert into system values ( + 'rdedws119', + 'Oracle', + 'RDE', + null, + 'true', + 'Andrew DeFaria', + 'Andrew.DeFaria@gd-ms.com', + 'Solaris 5.11', + '9.0.0', + 'Unix', + null, + 'Workstation' +); + diff --git a/lib/Clearcase.pm b/lib/Clearcase.pm index 81822dd..e9b58ff 100644 --- a/lib/Clearcase.pm +++ b/lib/Clearcase.pm @@ -82,7 +82,7 @@ use Display; my ($clearpid, $clearin, $clearout, $oldHandler, $cleartool); -our $VIEW_DRIVE = $ENV{CLEARCASE_VIEW_DRIVE} || 'M'; +our $VIEW_DRIVE = 'M'; our $VOB_MOUNT = 'vob'; our $WIN_VOB_PREFIX = '\\'; our $SFX = $ENV{CLEARCASE_XN_SFX} ? $ENV{CLEARCASE_XN_SFX} : '@@'; @@ -118,9 +118,9 @@ BEGIN { # We can go to the registry pretty easy in Cygwin but I'm not sure how to do # that in plain old Windows. Most people either have Clearcase installed on # the C drive or commonly on the D drive on servers. So we'll look at both. - $CCHOME = 'C:\\Program Files (x86)\\ibm\\RationalSDLC\\Clearcase'; + $CCHOME = 'C:\\IBMRational\\RationalSDLC\\Clearcase'; - $CCHOME = 'D:\\Program Files (x86)\\ibm\\RationalSDLC\\Clearcase' + $CCHOME = 'D:\\IBMRational\\RationalSDLC\\Clearcase' unless -d $CCHOME; error 'Unable to figure out where Clearcase is installed', 1 @@ -579,7 +579,7 @@ Array of output lines from the cleartool command execution. # to use these Clearcase objects say in a web page where the server is often # run as a plain user who does not have cleartool in their path. unless ($cleartool) { - if ($ARCHITECTURE =~ /Win/i or $ARCHITECTURE eq 'cygwin') { + if ($ARCHITECTURE =~ /Win/ or $ARCHITECTURE eq 'cygwin') { $cleartool = 'cleartool'; } elsif (-x '/opt/rational/clearcase/bin/cleartool') { $cleartool = '/opt/rational/clearcase/bin/cleartool'; @@ -593,6 +593,7 @@ Array of output lines from the cleartool command execution. if (!$clearpid) { # Simple check to see if we can execute cleartool @output = `$cleartool -ver 2>&1`; + @output = (); return (-1, 'Clearcase not installed') unless $? == 0; diff --git a/lib/Clearcase/Server.pm b/lib/Clearcase/Server.pm index 0021a5c..c47e321 100644 --- a/lib/Clearcase/Server.pm +++ b/lib/Clearcase/Server.pm @@ -29,6 +29,7 @@ $Date: 2011/01/02 04:59:36 $ =head2 SYNOPSIS Provides access to information about a Clearcase Server. + =head2 DESCRIPTION This module implements an object oriented interface to a Clearcase @@ -92,6 +93,8 @@ sub new ($;$) { my $self = bless { name => $name }, $class; + $self->updateServerInfo($name); + return $self; } # new @@ -143,11 +146,11 @@ sub mvfsBlocksPerDirectory () { return $self->{mvfsBlocksPerDirectory}; } # mvfsBlocksPerDirectory -sub mvfsCleartextMnodes () { +sub mvfsFreeMnodesCleartext() { my ($self) = @_; - return $self->{mvfsCleartextMnodes}; -} # mvfsCleartextMnodes + return $self->{mvfsFreeMnodesCleartext}; +} # mvfsFreeMnodesCleartext sub mvfsDirectoryNames () { my ($self) = @_; @@ -245,6 +248,66 @@ sub processHashTableSize () { return $self->{processHashTableSize}; } # processHashTableSize +sub updateServerInfo($) { + my ($self, $host) = @_; + + my ($status, @output) = $Clearcase::CC->execute( + "hostinfo -long -properties -full $host" + ); + + for (@output) { + if (/Product: ClearCase (.*)/) { + $self->{ccVer} = $1; + } elsif (/Operating system: (.*)/) { + $self->{osVer} = $1; + } elsif (/Hardware type: (.*)/) { + $self->{hardware} = $1; + } elsif (/License host: (.*)/) { + $self->{licenseHost} = $1; + } elsif (/Registry host: (.*)/) { + $self->{registryHost} = $1; + } elsif (/Registry region: (.*)/) { + $self->{registryRegion} = $1; + } elsif (/Blocks per directory: (.*)/) { + $self->{mvfsBlocksPerDirectory} = $1; + } elsif (/Free mnodes for cleartext: (.*)/) { + $self->{mvfsFreeMnodesCleartext} = $1; + } elsif (/Directory names: (.*)/) { + $self->{mvfsDirectoryNames} = $1; + } elsif (/File names: (.*)/) { + $self->{mvfsFileNames} = $1; + } elsif (/Free mnodes: (.*)/) { + $self->{mvfsFreeMnodes} = $1; + } elsif (/Initial mnode table size: (.*)/) { + $self->{mvfsInitialMnodeTableSize} = $1; + } elsif (/Minimum free mnodes for cleartext: (.*)/) { + $self->{mvfsMinCleartextMnodes} = $1; + } elsif (/Mimimum free mnodes: (.*)/) { + $self->{mvfsMinFreeMnodes} = $1; + } elsif (/Names not found: (.*)/) { + $self->{mvfsNamesNotFound} = $1; + } elsif (/RPC handles: (.*)/) { + $self->{mvfsRPCHandles} = $1; + } elsif (/Scaling factor to initialize MVFS cache sizes: (.*)/) { + $self->{scalingFactor} = $1; + } elsif (/Cleartext idle lifetime: (.*)/) { + $self->{cleartextIdleLifetime} = $1; + } elsif (/VOB hash table size: (.*)/) { + $self->{vobHashTableSize} = $1; + } elsif (/Cleartext hash table size: (.*)/) { + $self->{cleartextHashTableSize} = $1; + } elsif (/Thread hash table size: (.*)/) { + $self->{threadHashTableSize} = $1; + } elsif (/DNC hash table size: (.*)/) { + $self->{dncHashTableSize} = $1; + } elsif (/Process hash table size: (.*)/) { + $self->{processHashTableSize} = $1; + } # if + } # for + + return; +} # updateServerInfo + 1; =pod diff --git a/lib/Clearcase/UCM/Folder.pm b/lib/Clearcase/UCM/Folder.pm index d606d62..0d0da46 100644 --- a/lib/Clearcase/UCM/Folder.pm +++ b/lib/Clearcase/UCM/Folder.pm @@ -96,7 +96,11 @@ Returns: "mkfolder $comment -in " . $class->{parent} . ' ' . $name . '@' . $pvob->tag ); - return $class->updateFolderInfo; + return if $status; + + ($status, @output) = $class->updateFolderInfo; + + return $status ? undef : $class; } # new sub name () { @@ -416,6 +420,7 @@ sub updateFolderInfo () { return $self; } # updateFolderInfo + 1; =head1 DEPENDENCIES diff --git a/lib/Clearcase/UCM/Pvob.pm b/lib/Clearcase/UCM/Pvob.pm index 0b39949..86629c1 100644 --- a/lib/Clearcase/UCM/Pvob.pm +++ b/lib/Clearcase/UCM/Pvob.pm @@ -47,9 +47,7 @@ package Clearcase::UCM::Pvob; use strict; use warnings; -# Would be better represented by use parent "Clearcase::Vob" but we're -# working with old versions of Perl here... -use base 'Clearcase::Vob'; +use parent 'Clearcase::Vob'; use Carp; @@ -93,7 +91,8 @@ Returns: croak 'Clearcase::UCM::Pvob: Must specify pvob tag' unless $tag; $class = bless { - tag => $tag, + tag => $tag, + ucmproject => 1, }, $class; # bless $class->updateVobInfo; @@ -101,46 +100,6 @@ Returns: return $class; } # new -sub create (;$$$%) { - my ($self, $host, $vbs, $comment, %opts) = @_; - -=pod - -=head2 create - -Creates a pvob - -Parameters: - -=for html
- -=over - -=item none - -=back - -=for html
- -Returns: - -=for html
- -=over - -=item none - -=back - -=for html
- -=cut - - $opts{ucmproject} = undef; - - return $self->SUPER::create ($host, $vbs, $comment, %opts); -} # create - sub tag() { my ($self) = @_; diff --git a/lib/Clearcase/View.pm b/lib/Clearcase/View.pm index 77cfc6a..79dea02 100644 --- a/lib/Clearcase/View.pm +++ b/lib/Clearcase/View.pm @@ -46,9 +46,9 @@ fields they are expanded. display_nolf MAGENTA . "Additional groups:\t"; - foreach ($view->additional_groups) { + for ($view->additional_groups) { display_nolf "$_ "; - } # foreach + } # for display ''; @@ -127,8 +127,8 @@ use warnings; use Clearcase; use Display; -sub new ($) { - my ($class, $tag) = @_; +sub new ($;$) { + my ($class, $tag, $region) = @_; =pod @@ -172,7 +172,7 @@ Returns: my $self = bless { tag => $tag }, $class; - $self->updateViewInfo; + $self->updateViewInfo ($region); return $self; } # new @@ -1168,12 +1168,7 @@ Returns: =cut return $self->{tag}; - } # tag - -# Alias name to tag -sub name() { - goto &tag; -} # name +} # tag sub text_mode () { my ($self) = @_; @@ -1368,7 +1363,7 @@ Returns: } # exists sub create (;$$$) { - my ($self, $host, $vws, $opts) = @_; + my ($self, $host, $vws, $region) = @_; =pod @@ -1414,37 +1409,34 @@ Ouput from cleartool =cut + $region ||= $Clearcase::CC->region; + if ($self->exists) { - $self->updateViewInfo; + $self->updateViewInfo ($region); return (0, ()) } # if my ($status, @output); - $opts ||= ''; - if ($host && $vws) { - ($status, @output) = $Clearcase::CC->execute( - "mkview -tag $self->{tag} $opts " . - "-host $host -hpath $vws -gpath $vws $vws" - ); + ($status, @output) = + $Clearcase::CC->execute ("mkview -tag $self->{tag} -region $region " + . "-host $host -hpath $vws -gpath $vws $vws"); } else { # Note this requires that -stgloc's work and that using -auto is not a # problem. - ($status, @output) = $Clearcase::CC->execute( - "mkview -tag $self->{tag} $opts -stgloc -auto" - ); + ($status, @output) = + $Clearcase::CC->execute ("mkview -tag $self->{tag} -stgloc -auto"); } # if - $self->updateViewInfo; + $self->updateViewInfo ($region); return ($status, @output); } # create -# TODO Is this used? sub createUCM ($$) { - my ($self, $stream, $pvob) = @_; + my ($self, $stream, $pvob, $region) = @_; =pod @@ -1490,10 +1482,14 @@ Array of output =cut - return (0, ()) if $self->exists; + $region ||= $Clearcase::CC->region; + + return (0, ()) + if $self->exists; # Update object members - $self->{pvob} = $pvob; + $self->{stream} = $stream; + $self->{pvob} = $pvob; # Need to create the view my ($status, @output) = @@ -1503,7 +1499,7 @@ Array of output return ($status, @output) if $status; - $self->updateViewInfo; + $self->updateViewInfo ($region); return ($status, @output); } # createUCM @@ -1549,13 +1545,12 @@ Ouput from cleartool =cut - return (0, ()) unless $self->exists; + return (0, ()) + unless $self->exists; my ($status, @output); if ($self->dynamic) { - $self->stop; - ($status, @output) = $Clearcase::CC->execute ( "rmview -force -tag $self->{tag}" ); @@ -1749,11 +1744,13 @@ Ouput from cleartool return ($status, @output); } # set -sub updateViewInfo () { - my ($self) = @_; +sub updateViewInfo ($$) { + my ($self, $region) = @_; + + $region ||= $Clearcase::CC->region; my ($status, @output) = $Clearcase::CC->execute ( - "lsview -long -properties -full $self->{tag}" + "lsview -region $region -long -properties -full $self->{tag}" ); # Assuming this view is an empty shell of an object that the user may possibly @@ -1767,7 +1764,7 @@ sub updateViewInfo () { $self->{ucm} = 0; $self->{additional_groups} = ''; - foreach (@output) { + for (@output) { if (/Global path: (.*)/) { $self->{gpath} = $1; } elsif (/Server host: (.*)/) { @@ -1808,19 +1805,26 @@ sub updateViewInfo () { $self->{text_mode} = $1; } elsif (/Properties: (.*)/) { $self->{properties} = $1; - } elsif (/Owner: (\S+)\s+: (\S+) /) { + } elsif (/View owner: (\S+)$/) { + # It is possible that there may be problems enumerating + # -properties and -full when listing views due to servers + # no longer being available. Still the "View owner" line + # denotes the view's owner. + $self->{owner} = $1; + $self->{owner_mode} = ''; + } elsif (/Owner: (\S+)\s+: (\S+)/) { $self->{owner} = $1; $self->{owner_mode} = $2; } elsif (/Group: (.+)\s+:\s+(\S+)\s+/) { $self->{group} = $1; - $self->{group_mode} = $2; - } elsif (/Other:\s+: (\S+) /) { + $self->{group_mode} = $2; + } elsif (/Other:\s+: (\S+)/) { $self->{other_mode} = $1; } elsif (/Additional groups: (.*)/) { my @additional_groups = split /\s+/, $1; $self->{additional_groups} = \@additional_groups; } # if - } # foreach + } # for # Change modes to numeric $self->{mode} = 0; @@ -1840,6 +1844,361 @@ sub updateViewInfo () { return; } # updateViewInfo +sub viewPrivateStorage() { + my ($self) = @_; + +=pod + +=head1 viewPrivateStorage + +Returns the view private storage size for this view. + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item view private storage + +=back + +=for html
+ +=cut + + $self->updateViewSpace unless ($self->{viewPrivateStorage}); + + return $self->{viewPrivateStorage}; +} # viewPrivateStorage + +sub viewPrivateStoragePct() { + my ($self) = @_; + +=pod + +=head1 viewPrivateStoragePct + +Returns the view private storage percent for this view. + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item view private storage + +=back + +=for html
+ +=cut + + $self->updateViewSpace unless ($self->{viewPrivateStoragePct}); + + return $self->{viewPrivateStoragePct}; +} # viewPrivateStoragePct + +sub viewDatabase() { + my ($self) = @_; + +=pod + +=head1 viewDatabase + +Returns the view database size for this view. + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item view database size + +=back + +=for html
+ +=cut + + $self->updateViewSpace unless ($self->{viewDatabase}); + + return $self->{viewDatabase}; +} # viewDatabase + +sub viewDatabasePct() { + my ($self) = @_; + +=pod + +=head1 viewDatabasePct + +Returns the view database percent for this view. + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item view database percent + +=back + +=for html
+ +=cut + + $self->updateViewSpace unless ($self->{viewDatabasePct}); + + return $self->{viewDatabasePct}; +} # viewDatabasePct + +sub viewAdmin() { + my ($self) = @_; + +=pod + +=head1 viewAdmin + +Returns the view admin size for this view. + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item view admin size + +=back + +=for html
+ +=cut + + $self->updateViewSpace unless ($self->{viewAdmin}); + + return $self->{viewAdmin}; +} # viewAdmin + +sub viewAdminPct() { + my ($self) = @_; + +=pod + +=head1 viewAdminPct + +Returns the view admin percent for this view. + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item view admin percent + +=back + +=for html
+ +=cut + + $self->updateViewSpace unless ($self->{viewAdminPct}); + + return $self->{viewAdminPct}; +} # viewAdminPct + +sub viewSpace() { + my ($self) = @_; + +=pod + +=head1 viewSpace + +Returns the view total size for this view. + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item view space + +=back + +=for html
+ +=cut + + $self->updateViewSpace unless ($self->{viewSpace}); + + return $self->{viewSpace}; +} # viewSpace + +sub viewSpacePct() { + my ($self) = @_; + +=pod + +=head1 viewSpacePct + +Returns the view database percent for this view. + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item view space percent + +=back + +=for html
+ +=cut + + $self->updateViewSpace unless ($self->{viewSpacePct}); + + return $self->{viewSpacePct}; +} # viewSpacePct + +sub updateViewSpace() { + my ($self) = @_; + + my ($status, @output) = $Clearcase::CC->execute ( + "space -region $self->{region} -view $self->{tag}" + ); + + $self->{viewPrivateStorage} = 0.0; + $self->{viewPrivateStoragePct} = '0%'; + $self->{viewAdmin} = 0.0; + $self->{viewAdminPct} = '0%'; + $self->{viewDatabase} = 0.0; + $self->{viewDatabasePct} = '0%'; + $self->{viewSpace} = 0.0; + $self->{viewSpacePct} = '0%'; + + for (@output) { + if (/\s*(\S+)\s*(\S+)\s*View private storage/) { + $self->{viewPrivateStorage} = $1; + $self->{viewPrivateStoragePct} = $2; + } elsif (/\s*(\S+)\s*(\S+)\s*View database/) { + $self->{viewDatabase} = $1; + $self->{viewDatabasePct} = $2; + } elsif (/\s*(\S+)\s*(\S+)\s*View administration/) { + $self->{viewAdmin} = $1; + $self->{viewAdminPct} = $2; + } elsif (/\s*(\S+)\s*(\S+)\s*Subtotal/) { + $self->{viewSpace} = $1; + $self->{viewSpacePct} = $2; + } # if + } # for + + return; +} # updateViewSpace + 1; =pod diff --git a/lib/Clearcase/Vob.pm b/lib/Clearcase/Vob.pm index 142c1dc..596fafb 100644 --- a/lib/Clearcase/Vob.pm +++ b/lib/Clearcase/Vob.pm @@ -56,7 +56,7 @@ expanded if and when accessed. This helps the VOB object to be more efficient. display "DB Size:\t" . $vob->dbsize; display "Adm Size:\t" . $vob->admsize; display "CT Size:\t" . $vob->ctsize; - display "DO Size:\t" . $vob->dbsize; + display "DO Size:\t" . $vob->dosize; display "Src Size:\t" . $vob->srcsize; display "Size:\t\t" . $vob->size; @@ -157,7 +157,7 @@ sub tag () { =head2 tag -Returns the VOB's tag +Returns the VOB tag Parameters: @@ -195,7 +195,7 @@ sub gpath () { =head2 gpath -Returns the VOB's global path +Returns the VOB global path Parameters: @@ -233,7 +233,7 @@ sub shost () { =head2 shost -Returns the VOB's server host +Returns the VOB server host Parameters: @@ -430,7 +430,7 @@ sub replica_uuid () { =head2 replica_uuid -Returns the VOBS replica_uuid +Returns the VOB replica_uuid Parameters: @@ -468,7 +468,7 @@ sub host () { =head2 host -Returns the VOB's host +Returns the VOB host Parameters: @@ -506,7 +506,7 @@ sub access_path () { =head2 access_path -Returns the VOB's access path +Returns the VOB access path Parameters: @@ -628,7 +628,7 @@ sub expand_space () { $self->{srcsize} = 0; $self->{size} = 0; - foreach (@output) { + for (@output) { if (/(\d*\.\d).*VOB database(.*)/) { $self->{dbsize} = $1; } elsif (/(\d*\.\d).*administration data(.*)/) { @@ -642,11 +642,717 @@ sub expand_space () { } elsif (/(\d*\.\d).*Subtotal(.*)/) { $self->{size} = $1; } # if - } # foreach + } # for + + return; +} # expand_space + +sub expand_description () { + my ($self) = @_; + + my ($status, @output) = $Clearcase::CC->execute ("describe -long vob:$self->{tag}"); + + for (my $i = 0; $i < @output; $i++) { + if ($output[$i] =~ /created (\S+) by (.+) \((\S+)\)/) { + $self->{created} = $1; + $self->{ownername} = $2; + $self->{owner} = $3; + } elsif ($output[$i] =~ /^\s+\"(.+)\"/) { + $self->{comment} = $1; + } elsif ($output[$i] =~ /master replica: (.+)/) { + $self->{masterReplica} = $1; + } elsif ($output[$i] =~ /replica name: (.+)/) { + $self->{replicaName} = $1; + } elsif ($output[$i] =~ /VOB family featch level: (\d+)/) { + $self->{featureLevel} = $1; + } elsif ($output[$i] =~ /database schema version: (\d+)/) { + $self->{schemaVersion} = $1; + } elsif ($output[$i] =~ /modification by remote privileged user: (.+)/) { + $self->{remotePrivilege} = $1; + } elsif ($output[$i] =~ /atomic checkin: (.+)/) { + $self->{atomicCheckin} = $1; + } elsif ($output[$i] =~ /VOB ownership:/) { + while ($output[$i] !~ /Additional groups:/) { + $i++; + + if ($output[$i++] =~ /owner (.+)/) { + $self->{owner} = $1; + } # if + + if ($output[$i++] =~ /group (.+)/) { + $self->{group} = $1; + } # if + } # while + + my @groups; + + while ($output[$i] !~ /ACLs enabled/) { + if ($output[$i++] =~ /group (.+)/) { + push @groups, $1; + } # if + } # while + + $self->{groups} = \@groups; + + if ($output[$i++] =~ /ACLs enabled: (.+)/) { + $self->{aclsEnabled} = $1; + } # if + + my %attributes; + + while ($i < @output and $output[$i] !~ /Hyperlinks:/) { + if ($output[$i] !~ /Attributes:/) { + my ($key, $value) = split / = /, $output[$i]; + + # Trim leading spaces + $key =~ s/^\s*(\S+)/$1/; + + # Remove unnecessary '"'s + $value =~ s/\"(.*)\"/$1/; + + $attributes{$key} = $value; + } # if + + $i++; + } # while + + $self->{attributes} = \%attributes; + + $i++; + + my %hyperlinks; + + while ($i < @output and $output[$i]) { + my ($key, $value) = split " -> ", $output[$i++]; + + # Trim leading spaces + $key =~ s/^\s*(\S+)/$1/; + + $hyperlinks{$key} = $value; + } # while + + $self->{hyperlinks} = \%hyperlinks; + } # if + } # for return; } # expand_space +sub masterReplica() { + +=pod + +=head2 masterReplica + +Returns the VOB master replica + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB master replica + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{masterReplica}; + + return $self->{masterReplica} +} # masterReplica + +sub created() { + +=pod + +=head2 created + +Returns the date the VOB was created + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item Date the VOB was created + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{created}; + + return $self->{created} +} # created + +sub ownername() { + +=pod + +=head2 ownername + +Returns the VOB ownername + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB Owner Name + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{ownername}; + + return $self->{ownername} +} # ownername + +sub owner() { + +=pod + +=head2 owner + +Returns the VOB owner + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB master replica + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{owner}; + + return $self->{owner} +} # owner + +sub comment() { + +=pod + +=head2 comment + +Returns the VOB comment + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB comment + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{comment}; + + return $self->{comment} +} # comment + +sub replicaName() { + +=pod + +=head2 replicaName + +Returns the VOB replicaName + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB replica name + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{replicaName}; + + return $self->{replicaName} +} # replicaName + +sub featureLevel() { + +=pod + +=head2 featureLevel + +Returns the VOB featureLevel + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB feature level + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{featureLevel}; + + return $self->{featureLevel} +} # featureLevel + +sub schemaVersion() { + +=pod + +=head2 schemaVersion + +Returns the VOB schemaVersion + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB schema version + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{schemaVersion}; + + return $self->{schemaVersion} +} # schemaVersion + +sub remotePrivilege() { + +=pod + +=head2 remotePrivilege + +Returns the VOB remotePrivilege + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item Remote Privilege capability + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{remotePrivilege}; + + return $self->{remotePrivilege} +} # remotePrivilege + +sub atomicCheckin() { + +=pod + +=head2 atomicCheckin + +Returns the VOB atomicCheckin + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item Whether atomic check in enabled + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{atomicCheckin}; + + return $self->{atomicCheckin} +} # atomicCheckin + +sub group() { + +=pod + +=head2 group + +Returns the VOB group + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB group + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{group}; + + return $self->{group} +} # group + +sub groups() { + +=pod + +=head2 groups + +Returns the VOB groups + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB groups + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{groups}; + + return @{$self->{groups}} +} # groups + +sub aclsEnabled() { + +=pod + +=head2 aclsEnabled + +Returns the VOB aclsEnabled + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB aclsEnabled + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{aclsEnabled}; + + return $self->{aclsEnabled} +} # aclsEnabled + +sub attributes() { + +=pod + +=head2 attributes + +Returns the VOB attributes + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB attributes + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{attributes}; + + return %{$self->{attributes}}; +} # attributes + +sub hyperlinks() { + +=pod + +=head2 hyperlinks + +Returns the VOB hyperlinks + +Parameters: + +=for html
+ +=over + +=item none + +=back + +=for html
+ +Returns: + +=for html
+ +=over + +=item VOB hyperlinks + +=back + +=for html
+ +=cut + + my ($self) = @_; + + $self->expand_description unless $self->{hyperlinks}; + + return %{$self->{hyperlinks}}; +} # hyperlinks + sub countdb () { my ($self) = @_; @@ -672,7 +1378,7 @@ sub countdb () { chomp @output; # Parse output - foreach (@output) { + for (@output) { if (/^ELEMENT\s*:\s*(\d*)/) { $self->{elements} = $1; } elsif (/^BRANCH\s*:\s*(\d*)/) { @@ -680,7 +1386,7 @@ sub countdb () { } elsif (/^VERSION\s*:\s*(\d*)/) { $self->{versions} = $1; } # if - } # foreach + } # for chdir $cwd; @@ -1248,6 +1954,8 @@ Ouput from cleartool } # for if ($host && $vbs) { + $additionalOpts .= '-ucmproject' if $self->{ucmproject}; + ($status, @output) = $Clearcase::CC->execute ( "mkvob -tag $self->{tag} $comment $additionalOpts -host $host -hpath $vbs " . "-gpath $vbs $vbs"); @@ -1316,7 +2024,7 @@ sub updateVobInfo ($$) { # use the create method on, return our blessings... return if $status != 0; - foreach (@output) { + for (@output) { if (/Global path: (.*)/) { $self->{gpath} = $1; } elsif (/Server host: (.*)/) { @@ -1340,7 +2048,7 @@ sub updateVobInfo ($$) { } elsif (/Vob registry attributes: (.*)/) { $self->{vob_registry_attributes} = $1; } # if - } # foreach + } # for return; } # getVobInfo diff --git a/lib/Clearcase/Vobs.pm b/lib/Clearcase/Vobs.pm index 0f2d85f..ad175f4 100644 --- a/lib/Clearcase/Vobs.pm +++ b/lib/Clearcase/Vobs.pm @@ -72,12 +72,12 @@ use Clearcase; use Display; use OSDep; -sub new () { - my ($class) = @_; +sub new (;$) { + my ($class, $host, $region) = @_; =pod -=head2 new (tag) +=head2 new (host) Construct a new Clearcase Vobs object. @@ -87,7 +87,10 @@ Parameters: =over -=item none +=item host + +If host is specified then limit the vob list to only those vobs on that host. If +host is not specified then all vobs are considered =back @@ -107,18 +110,13 @@ Returns: =cut - my ($status, @output) = $Clearcase::CC->execute ("lsvob -short"); + my $cmd = 'lsvob -short'; + $cmd .= " -host $host" if $host; + $cmd .= " -region $region" if $region; - return if $status; + my ($status, @output) = $Clearcase::CC->execute ($cmd); - # Strip $VOBTAG_PREFIX - foreach (@output) { - if ($ARCHITECTURE eq 'windows' or $ARCHITECTURE eq 'cygwin') { - s/\\//; - } else { - s/$Clearcase::VOBTAG_PREFIX//; - } # if - } # foreach + return if $status; return bless { vobs => \@output diff --git a/lib/CmdLine.pm b/lib/CmdLine.pm index ed92843..e6d6ead 100644 --- a/lib/CmdLine.pm +++ b/lib/CmdLine.pm @@ -507,7 +507,7 @@ Returns: my $me = get_me; - $histfile ||= ".${me}_hist"; + $histfile ||= "$ENV{HOME}/.${me}_hist"; error "Creating bogus .${me}_hist file!" if $me eq '-' or $me eq ''; diff --git a/lib/DateUtils.pm b/lib/DateUtils.pm index f106394..40a581e 100644 --- a/lib/DateUtils.pm +++ b/lib/DateUtils.pm @@ -60,7 +60,7 @@ use Time::Local; use Display; use Utils; -our @EXPORT = qw ( +our @EXPORT = qw( Add Age Compare @@ -79,6 +79,7 @@ our @EXPORT = qw ( YMDHMS timestamp ymdhms + MDYHMS2SQLDatetime ); my @months = ( @@ -101,11 +102,11 @@ my $SECS_IN_HOUR = $SECS_IN_MIN * 60; my $SECS_IN_DAY = $SECS_IN_HOUR * 24; # Forwards -sub Today2SQLDatetime (); -sub DateToEpoch ($); -sub EpochToDate ($); +sub Today2SQLDatetime(); +sub DateToEpoch($); +sub EpochToDate($); -sub ymdhms { +sub ymdhms(;$) { my ($time) = @_; $time ||= time; @@ -120,7 +121,7 @@ sub ymdhms { $wday, $yday, $isdst - ) = localtime ($time); + ) = localtime($time); # Adjust month $mon++; @@ -138,7 +139,7 @@ sub ymdhms { return $year, $mon, $mday, $hour, $min, $sec; } # ymdhms -sub julian ($$$) { +sub julian($$$) { my ($year, $month, $day) = @_; my $days = 0; @@ -153,19 +154,19 @@ sub julian ($$$) { return $days + $day; } # julian -sub _is_leap_year ($) { +sub _is_leap_year($) { my ($year) = @_; - + return 0 if $year % 4; return 1 if $year % 100; return 0 if $year % 400; - + return 1; } # _is_leap_year -sub Add ($%) { +sub Add($%) { my ($datetime, %parms) = @_; - + =pod =head2 Add ($datetime, %parms) @@ -191,7 +192,7 @@ Hash of parms. Acceptable values are of the following format: hours => $hours days => $days month => $month - + Note that month will simply increment the month number, adjusting for overflow of year if appropriate. Therefore a date of 2/28/2001 would increase by 1 month to yield 3/28/2001. And, unfortunately, an increase of 1 month to 1/30/2011 @@ -222,47 +223,47 @@ Returns: 'days', 'months', ); - - foreach (keys %parms) { - unless (InArray ($_, @validKeys)) { + + for (keys %parms) { + unless (InArray($_, @validKeys)) { croak "Invalid key in DateUtils::Add: $_"; } # unless - } # foreach - + } # for + my $epochTime = DateToEpoch $datetime; - + my $amount = 0; - + $parms{seconds} ||= 0; $parms{minutes} ||= 0; $parms{hours} ||= 0; $parms{days} ||= 0; - + $amount += $parms{days} * $SECS_IN_DAY; $amount += $parms{hours} * $SECS_IN_HOUR; $amount += $parms{minutes} * $SECS_IN_MIN; $amount += $parms{seconds}; - + $epochTime += $amount; $datetime = EpochToDate $epochTime; - + if ($parms{month}) { my $years = $parms{month} / 12; my $months = $parms{month} % 12; - + my $month = substr $datetime, 5, 2; - + $years += ($month + $months) / 12; - substr ($datetime, 5, 2) = ($month + $months) % 12; - - substr ($datetime, 0, 4) = substr ($datetime, 0, 4) + $years; + substr($datetime, 5, 2) = ($month + $months) % 12; + + substr($datetime, 0, 4) = substr ($datetime, 0, 4) + $years; } # if - + return $datetime; } # Add -sub Age ($) { +sub Age($) { my ($timestamp) = @_; =pod @@ -311,13 +312,13 @@ Returns: my $timestamp_days = julian $timestamp_year, $month, $day; if ($timestamp_year > $today_year or - ($timestamp_days > $today_days and $timestamp_year == $today_year)) { + ($timestamp_days > $today_days and $timestamp_year == $today_year)) { return; } else { my $leap_days = 0; for (my $i = $timestamp_year; $i < $today_year; $i++) { - + $leap_days++ if $i % 4 == 0; } # for @@ -326,9 +327,9 @@ Returns: } # if } # Age -sub Compare ($$) { +sub Compare($$) { my ($date1, $date2) = @_; - + =pod =head2 Compare ($date2, $date2) @@ -371,9 +372,9 @@ Returns: return DateToEpoch ($date1) <=> DateToEpoch ($date2); } # Compare -sub DateToEpoch ($) { +sub DateToEpoch($) { my ($date) = @_; - + =pod =head2 DateToEpoch ($datetime) @@ -414,13 +415,13 @@ Returns: my $hour = substr $date, 11, 2; my $minute = substr $date, 14, 2; my $seconds = substr $date, 17, 2; - + my $days; for (my $i = 1970; $i < $year; $i++) { $days += _is_leap_year ($i) ? 366 : 365; } # for - + my @monthDays = ( 0, 31, @@ -435,23 +436,23 @@ Returns: 304, 334, ); - + $days += $monthDays[$month - 1]; - + $days++ if _is_leap_year ($year) and $month > 2; - + $days += $day - 1; - + return ($days * $SECS_IN_DAY) + ($hour * $SECS_IN_HOUR) + ($minute * $SECS_IN_MIN) + $seconds; } # DateToEpoch -sub EpochToDate ($) { +sub EpochToDate($) { my ($epoch) = @_; - + =pod =head2 EpochToDate ($epoch) @@ -490,19 +491,19 @@ Returns: my ($month, $day, $hour, $minute, $seconds); my $leapYearSecs = 366 * $SECS_IN_DAY; my $yearSecs = $leapYearSecs - $SECS_IN_DAY; - + while () { my $amount = _is_leap_year ($year) ? $leapYearSecs : $yearSecs; - + last if $amount > $epoch; - + $epoch -= $amount; $year++; } # while - - my $leapYearAdjustment = _is_leap_year ($year) ? 1 : 0; - + + my $leapYearAdjustment = _is_leap_year($year) ? 1 : 0; + if ($epoch >= (334 + $leapYearAdjustment) * $SECS_IN_DAY) { $month = '12'; $epoch -= (334 + $leapYearAdjustment) * $SECS_IN_DAY; @@ -540,24 +541,24 @@ Returns: $month = '01'; } # if - $day = int (($epoch / $SECS_IN_DAY) + 1); + $day = int(($epoch / $SECS_IN_DAY) + 1); $epoch = $epoch % $SECS_IN_DAY; - $hour = int ($epoch / $SECS_IN_HOUR); + $hour = int($epoch / $SECS_IN_HOUR); $epoch = $epoch % $SECS_IN_HOUR; - $minute = int ($epoch / $SECS_IN_MIN); + $minute = int($epoch / $SECS_IN_MIN); $seconds = $epoch % $SECS_IN_MIN; - + $day = "0$day" if $day < 10; $hour = "0$hour" if $hour < 10; $minute = "0$minute" if $minute < 10; $seconds = "0$seconds" if $seconds < 10; - + return "$year-$month-$day $hour:$minute:$seconds"; } # EpochToDate -sub UTCTime ($) { +sub UTCTime($) { my ($datetime) = @_; - + =pod =head2 UTCTime ($epoch) @@ -593,10 +594,10 @@ Returns: =cut my @localtime = localtime; - my ($sec, $min, $hour, $mday, $mon, $year) = gmtime ( + my ($sec, $min, $hour, $mday, $mon, $year) = gmtime( DateToEpoch ($datetime) - (timegm (@localtime) - timelocal (@localtime)) ); - + $year += 1900; $mon++; @@ -605,13 +606,13 @@ Returns: $hour = '0' . $hour if $hour < 10; $mon = '0' . $mon if $mon < 10; $mday = '0' . $mday if $mday < 10; - + return "$year-$mon-${mday}T$hour:$min:${sec}Z"; } # UTCTime -sub UTC2Localtime ($) { +sub UTC2Localtime($) { my ($utcdatetime) = @_; - + # If the field does not look like a UTC time then just return it. return $utcdatetime unless $utcdatetime =~ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/; @@ -625,7 +626,7 @@ sub UTC2Localtime ($) { ); } # UTC2Localtime -sub FormatDate ($) { +sub FormatDate($) { my ($date) = @_; =pod @@ -669,7 +670,7 @@ Returns: . substr ($date, 0, 4); } # FormatDate -sub FormatTime ($) { +sub FormatTime($) { my ($time) = @_; =pod @@ -711,13 +712,13 @@ Returns: my $AmPm = $hours > 12 ? "Pm" : "Am"; $hours = $hours - 12 if $hours > 12; - + $hours = "0$hours" if length $hours == 1; return "$hours:$minutes $AmPm"; } # FormatTime -sub MDY (;$) { +sub MDY(;$) { my ($time) = @_; =pod @@ -759,7 +760,7 @@ Returns: return "$mon/$mday/$year"; } # MDY -sub SQLDatetime2UnixDatetime ($) { +sub SQLDatetime2UnixDatetime($) { my ($sqldatetime) = @_; =pod @@ -814,12 +815,12 @@ Returns: my $year = substr $sqldatetime, 0, 4; my $month = substr $sqldatetime, 5, 2; my $day = substr $sqldatetime, 8, 2; - my $time = FormatTime (substr $sqldatetime, 11); + my $time = FormatTime(substr $sqldatetime, 11); return $months{$month} . " $day, $year \@ $time"; } # SQLDatetime2UnixDatetime -sub SubtractDays ($$) { +sub SubtractDays($$) { my ($timestamp, $nbr_of_days) = @_; =pod @@ -913,7 +914,7 @@ Returns: return $year . "-" . $month . "-" . $days . substr $timestamp, 10; } # SubtractDays -sub Today2SQLDatetime () { +sub Today2SQLDatetime() { =pod @@ -950,7 +951,7 @@ Returns: return UnixDatetime2SQLDatetime (scalar (localtime)); } # Today2SQLDatetime -sub UnixDatetime2SQLDatetime ($) { +sub UnixDatetime2SQLDatetime($) { my ($datetime) = @_; =pod @@ -1059,7 +1060,7 @@ Returns: unless ($months{$month_name}) { $month_name = substr $datetime, 8, 3; } # unless - + my $month = $months{$month_name}; my $time = substr $datetime, 11, 8; @@ -1071,12 +1072,12 @@ Returns: warning "Year undefined for $orig_datetime\nReturning today's date"; return Today2SQLDatetime; } # unless - + unless ($month) { warning "Month undefined for $orig_datetime\nReturning today's date"; return Today2SQLDatetime; } # unless - + unless ($day) { warning "Day undefined for $orig_datetime\nReturning today's date"; return Today2SQLDatetime; @@ -1090,7 +1091,7 @@ Returns: return "$year-$month-$day $time"; } # UnixDatetime2SQLDatetime -sub YMD (;$) { +sub YMD(;$) { my ($time) = @_; =pod @@ -1132,7 +1133,7 @@ Returns: return "$year$mon$mday"; } # YMD -sub YMDHM (;$) { +sub YMDHM(;$) { my ($time) = @_; =pod @@ -1174,7 +1175,7 @@ Returns: return "$year$mon$mday\@$hour:$min"; } # YMDHM -sub YMDHMS (;$) { +sub YMDHMS(;$) { my ($time) = @_; =pod @@ -1216,7 +1217,7 @@ Returns: return "$year$mon$mday\@$hour:$min:$sec"; } # YMDHMS -sub timestamp (;$) { +sub timestamp(;$) { my ($time) = @_; =pod @@ -1256,6 +1257,72 @@ Returns: return "$year$mon${mday}_$hour$min$sec"; } # timestamp +sub MDYHMS2SQLDatetime($) { + my ($datetime) = @_; + + $datetime =~ s/^\s+|\s+$//g; + + my ($year, $mon, $day, $hour, $min, $sec, $ampm); + + # For datetime format of MM/DD/YYYY HH:MM:SS [Am|Pm] + if ($datetime =~ /^(\d{1,2})\/(\d{1,2})\/(\d{4}) (\d{1,2}):(\d{1,2}):(\d{1,2}) (\w{2})$/) { + $mon = $1; + $day = $2; + $year = $3; + $hour = $4; + $min = $5; + $sec = $6; + $ampm = $7; + # For datetime format of MM/DD/YYYY HH:MM:SS + } elsif ($datetime =~ /^(\d{1,2})\/(\d{1,2})\/(\d{4}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/){ + $mon = $1; + $day = $2; + $year = $3; + $hour = $4; + $min = $5; + $sec = $6; + # For datetime format of MM/DD/YYYY + } elsif ($datetime =~ /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/) { + $mon = $1; + $day = $2; + $year = $3; + $hour = '00'; + $min = '00'; + $sec = '00'; + } else { + return + } # if + + # Range checks + return if $mon > 12 or $mon <= 0; + return if $day > 31 or $day <= 0; + return if $hour > 23 or $hour < 0; + return if $min > 59 or $min < 0; + + if ($day >= 31 and ($mon == 2 + or $mon == 4 + or $mon == 6 + or $mon == 9 + or $mon == 11)) { + return; + } # if + + return if $day > 29 and $mon == 2; + return if $day == 29 and $mon == 2 and not _is_leap_year($year); + + # Convert to 24 hour time if necessary + $hour += 12 if $ampm and $ampm =~ /pm/i; + + # Add any leading zeros + $mon = "0$mon" if length $mon == 1; + $day = "0$day" if length $day == 1; + $hour = "0$hour" if length $hour == 1; + $min = "0$min" if length $min == 1; + $sec = "0$sec" if length $sec == 1; + + return "$year-$mon-$day $hour:$min:$sec"; +} # MDYHMS2SQLDatetime + 1; =head2 DEPENDENCIES diff --git a/lib/Machines/MySQL.pm b/lib/Machines/MySQL.pm old mode 100644 new mode 100755 index 398fd8f..00f2b7c --- a/lib/Machines/MySQL.pm +++ b/lib/Machines/MySQL.pm @@ -57,11 +57,12 @@ our $VERSION = '$Revision: 1.0 $'; ($VERSION) = ($VERSION =~ /\$Revision: (.*) /); my %MACHINEOPTS = ( - SERVER => 'localhost', - USERNAME => 'machines', - PASSWORD => 'w0rk$harder', + SERVER => $ENV{REXEC_DBHOST} || 'localhost', + USERNAME => 'rexec', + PASSWORD => 'rexec', ); +# Internal methods sub _connect (;$) { my ($self, $dbserver) = @_; @@ -105,7 +106,6 @@ sub _checkRequiredFields ($$) { return; } # _checkRequiredFields -# Internal methods sub _dberror ($$) { my ($self, $msg, $statement) = @_; @@ -239,4 +239,4 @@ sub AddSystem (%) { return $self->_addRecord ('system', %system); } # AddSystem -1; \ No newline at end of file +1; diff --git a/lib/Utils.pm b/lib/Utils.pm index f52fe4b..8aabcaa 100644 --- a/lib/Utils.pm +++ b/lib/Utils.pm @@ -357,7 +357,7 @@ Returns: while () { my $key; - while (not defined ($key = ReadKey -1)) { } + while (not defined ($key = ReadKey -1)) { } if ($key =~ /(\r|\n)/) { print "\n"; diff --git a/puppet/client.pp b/puppet/client.pp new file mode 100644 index 0000000..e56c141 --- /dev/null +++ b/puppet/client.pp @@ -0,0 +1,23 @@ +# RDE Puppet Client config + +# This subclass defines the configuration for RDE Clients +class rde::client { + # Remove any NIS groups + file_line { 'no_NIS_groups': + ensure => 'absent', + path => '/etc/passwd', + line => '# Remove +', + match => '^\+@.*', + multiple => 'true', + match_for_absence => 'true', + replace => 'false', + tag => 'nis', + } + + file_line { 'all_users': + path => '/etc/passwd', + ensure => 'present', + line => '+', + tag => 'nis', + } +} diff --git a/puppet/dns.pp b/puppet/dns.pp new file mode 100644 index 0000000..4926660 --- /dev/null +++ b/puppet/dns.pp @@ -0,0 +1,125 @@ +# RDE Puppet DNS config +# +# This subclass defines the configuration for DNS servers +class rde::dns { + if ($hostname == 'rdeadm1') or ($hostname == 'rdeadm2') { + package { 'service/network/dns/bind': ensure => present, } + + service { 'dns/server': ensure => 'running', } + + file { '/var/named': + ensure => 'directory', + owner => 'root', + group => 'sys', + mode => '0755', + notify => Service['dns/server'], + } + } + + if $hostname == 'rdeadm1' { + file { '/etc/named.conf': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/named.conf.slave', + notify => Service['dns/server'], + } + } elsif $hostname == 'rdeadm2' { + file { '/etc/named.conf': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/named.conf.master', + notify => Service['dns/server'], + } + + file { '/var/named/named.ca': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/named.ca', + notify => Service['dns/server'], + } + + file { '/var/named/gddsi.com': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/gddsi.com', + require => File["/var/named"], + notify => Service['dns/server'], + } + + file { '/var/named/gd-ms.us': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/gd-ms.us', + require => File["/var/named"], + notify => Service['dns/server'], + } + + file { '/var/named/localhost': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/localhost', + require => File["/var/named"], + notify => Service['dns/server'], + } + + file { '/var/named/localhost.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/localhost.in-addr.arpa', + require => File["/var/named"], + notify => Service['dns/server'], + } + + file { '/var/named/11.240.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/11.240.10.in-addr.arpa', + require => File["/var/namedb"], + notify => Service['dns/server'], + } + + file { '/var/named/12.100.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/12.100.10.in-addr.arpa', + require => File["/etc/namedb/master"], + notify => Service['dns/server'], + } + + file { '/var/named/12.240.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/12.240.10.in-addr.arpa', + require => File["/etc/namedb/master"], + notify => Service['dns/server'], + } + + file { '/var/named/13.100.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/13.100.10.in-addr.arpa', + require => File["/etc/namedb/master"], + notify => Service['dns/server'], + } + + file { '/var/named/14.100.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/14.100.10.in-addr.arpa', + require => File["/etc/namedb/master"], + notify => Service['dns/server'], + } + } +} diff --git a/puppet/gd/client.pp b/puppet/gd/client.pp new file mode 100644 index 0000000..e56c141 --- /dev/null +++ b/puppet/gd/client.pp @@ -0,0 +1,23 @@ +# RDE Puppet Client config + +# This subclass defines the configuration for RDE Clients +class rde::client { + # Remove any NIS groups + file_line { 'no_NIS_groups': + ensure => 'absent', + path => '/etc/passwd', + line => '# Remove +', + match => '^\+@.*', + multiple => 'true', + match_for_absence => 'true', + replace => 'false', + tag => 'nis', + } + + file_line { 'all_users': + path => '/etc/passwd', + ensure => 'present', + line => '+', + tag => 'nis', + } +} diff --git a/puppet/gd/dns.pp b/puppet/gd/dns.pp new file mode 100644 index 0000000..4926660 --- /dev/null +++ b/puppet/gd/dns.pp @@ -0,0 +1,125 @@ +# RDE Puppet DNS config +# +# This subclass defines the configuration for DNS servers +class rde::dns { + if ($hostname == 'rdeadm1') or ($hostname == 'rdeadm2') { + package { 'service/network/dns/bind': ensure => present, } + + service { 'dns/server': ensure => 'running', } + + file { '/var/named': + ensure => 'directory', + owner => 'root', + group => 'sys', + mode => '0755', + notify => Service['dns/server'], + } + } + + if $hostname == 'rdeadm1' { + file { '/etc/named.conf': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/named.conf.slave', + notify => Service['dns/server'], + } + } elsif $hostname == 'rdeadm2' { + file { '/etc/named.conf': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/named.conf.master', + notify => Service['dns/server'], + } + + file { '/var/named/named.ca': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/named.ca', + notify => Service['dns/server'], + } + + file { '/var/named/gddsi.com': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/gddsi.com', + require => File["/var/named"], + notify => Service['dns/server'], + } + + file { '/var/named/gd-ms.us': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/gd-ms.us', + require => File["/var/named"], + notify => Service['dns/server'], + } + + file { '/var/named/localhost': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/localhost', + require => File["/var/named"], + notify => Service['dns/server'], + } + + file { '/var/named/localhost.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/localhost.in-addr.arpa', + require => File["/var/named"], + notify => Service['dns/server'], + } + + file { '/var/named/11.240.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/11.240.10.in-addr.arpa', + require => File["/var/namedb"], + notify => Service['dns/server'], + } + + file { '/var/named/12.100.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/12.100.10.in-addr.arpa', + require => File["/etc/namedb/master"], + notify => Service['dns/server'], + } + + file { '/var/named/12.240.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/12.240.10.in-addr.arpa', + require => File["/etc/namedb/master"], + notify => Service['dns/server'], + } + + file { '/var/named/13.100.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/13.100.10.in-addr.arpa', + require => File["/etc/namedb/master"], + notify => Service['dns/server'], + } + + file { '/var/named/14.100.10.in-addr.arpa': + owner => 'root', + group => 'sys', + mode => '0644', + source => 'puppet:///modules/rde/14.100.10.in-addr.arpa', + require => File["/etc/namedb/master"], + notify => Service['dns/server'], + } + } +} diff --git a/puppet/gd/init.pp b/puppet/gd/init.pp new file mode 100644 index 0000000..3346210 --- /dev/null +++ b/puppet/gd/init.pp @@ -0,0 +1,248 @@ +# RDE Puppet Base config +# +# This is the base class for all machines. +class rde { + package { 'nis': + ensure => 'present', + } + + nis { 'domainname': + domainname => 'rde', + } + + file { '/etc/defaultdomain': + path => '/etc/defaultdomain', + owner => 'root', + group => 'sys', + mode => '0644', + content => 'rde', + notify => Service['nis/client'], + } + + service { 'nis/domain': + ensure => 'running', + enable => 'true', + provider => 'smf', + notify => Service['nis/client'], + } + + nsswitch { 'nsswitch': + alias => 'files nis', + automount => 'files nis', + default => 'files', + group => 'files nis', + host => 'files dns nis', + netgroup => 'files nis', + password => 'files nis', + notify => [Service['nis/client'], Service['autofs']], + } + + service { 'nis/client': + ensure => 'running', + enable => 'true', + provider => 'smf', + notify => Service['autofs'], + } + + service { 'dns/client': + ensure => 'running', + enable => 'true', + provider => 'smf', + } + + dns { 'dns/client': + #nameserver => ['10.100.13.21', '10.100.13.22'], + nameserver => ['10.100.0.10', '10.100.0.30'], + domain => 'gddsi.com', + search => ['gddsi.com'], + notify => [Service['dns/client'], Service['autofs']], + } + + package { 'ntp': + ensure => 'present', + } + + file { 'ntp.conf': + path => '/etc/inet/ntp.conf', + owner => 'root', + group => 'sys', + mode => '0444', + source => 'puppet:///modules/rde/ntp.conf', + notify => Service['ntp'] + } + + service { 'ntp': + ensure => 'running', + enable => 'true', + provider => 'smf', + } + + service { 'rpc/bind': ensure => 'running', } + + service { 'zones-proxy-client': + ensure => 'running', + enable => 'true', + provider => 'smf', + } + + # I'm not sure if this is needed on clients. It was needed for + # the NIS server and slave. + svccfg { 'binding': + fmri => 'svc:/network/rpc/bind', + property => 'config/local_only', + type => 'boolean', + value => 'false', + } + + service { 'autofs': + ensure => 'running', + enable => 'true', + provider => 'smf', + notify => Service['rpc/bind'], + } + + service { 'sendmail': + ensure => 'running', + enable => 'true', + provider => 'smf', + } + + if ($hostname = 'rdeadm1') { + file_line { 'sendmail_relay': + ensure => 'present', + path => '/etc/mail/sendmail.cf', + line => 'DSsmtp-west.gd-ms.us.', + notify => Service['sendmail'], + } + } else { + file_line { 'sendmail_relay': + ensure => 'present', + path => '/etc/mail/sendmail.cf', + line => 'DSrdeadm1.gddsi.com', + notify => Service['sendmail'], + } + } + + svccfg { 'sendmail': + fmri => 'svc:/network/smtp:sendmail', + property => 'config/local_only', + type => 'boolean', + value => 'false', + notify => Service['sendmail'], + } + + file { '/etc/passwd': + owner => 'root', + group => 'sys', + mode => '0644', + } + + file { '/etc/group': + owner => 'root', + group => 'sys', + mode => '0644', + } + + file { '/etc/shadow': + owner => 'root', + group => 'sys', + mode => '0400', + } + + host { 'rdeadm1': + ensure => 'present', + comment => 'NIS Master', + ip => '10.100.13.21', + } + + host { 'rdeadm2': + ensure => 'present', + comment => 'NIS Slave', + ip => '10.100.13.22', + } + + file { 'motd': + path => '/etc/motd', + owner => 'root', + group => 'sys', + mode => '0444', + source => 'puppet:///modules/rde/motd', + } + + file { 'issue': + path => '/etc/issue', + owner => 'root', + group => 'sys', + mode => '0444', + source => 'puppet:///modules/rde/issue', + } + + file { 'sudoers': + path => '/etc/sudoers.d/admins', + owner => 'root', + group => 'sys', + mode => '0444', + content => "+ccadms ALL=(ALL) ALL\np2282c ALL=(ALL) NOPASSWD:ALL\nhn06511 ALL=(ALL) NOPASSWD:ALL\n", + } + + # Add "+" to /etc/group + file_line { 'groups': + path => '/etc/group', + ensure => 'present', + line => '+', + } + + # Add "+" to /etc/shadow + file_line { 'shadow': + path => '/etc/shadow', + ensure => 'present', + line => '+', + } + + # Everybody mounts these + file_line { 'vob_storage', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/rdevob1 - /rdevob1 nfs - yes -', + } + file_line { 'view_storage', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/rdeview1 - /rdeview1 nfs - yes -', + } + + if ($hostname == 'rdevob1' || $hostname == 'rdevob2') { + file_line { 'transfer': + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/transfer - /transfer nfs - yes -', + } + file_line { 'rdevob2', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/rdevob2 - /rdevob2 nfs - yes -', + } + } + + if ($hostname == 'rdevob1') { + file_line { 'export', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/export - /export nfs - yes -', + } + } + + if ($hostname == 'rdevob1') { + file_line { 'rdeview2', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/rdeview2 - /rdeview2 nfs - yes -', + } + } + + $std_packages = ['vim', 'gvim', 'tcsh', 'xauth', 'xclock', 'xterm', 'top', 'rdesktop', 'firefox', 'telnet', 'git', 'expect', 'make', 'gcc', 'motif', 'libxp'] + + package { $std_packages: + ensure => 'present', + } +} diff --git a/puppet/gd/server.pp b/puppet/gd/server.pp new file mode 100644 index 0000000..66f629a --- /dev/null +++ b/puppet/gd/server.pp @@ -0,0 +1,23 @@ +# RDE Puppet Server config + +# This subclass defines the configuration for RDE Servers +class rde::server { + # Remove any naked '+''s + file_line { 'all_users': + ensure => 'absent', + path => '/etc/passwd', + line => '# Remove +', + match => '^\+$', + match_for_absence => 'true', + replace => 'false', + tag => 'nis', + } + + # Make sure only members of the ccadms netgroup can log in + file_line { 'server_users': + path => '/etc/passwd', + ensure => 'present', + line => '+@ccadms', + tag => 'nis', + } +} diff --git a/puppet/gd/wincbc.pp b/puppet/gd/wincbc.pp new file mode 100644 index 0000000..734e96a --- /dev/null +++ b/puppet/gd/wincbc.pp @@ -0,0 +1,46 @@ +# RDE Puppet Windows config + +# This subclass defines the configuration for RDE Windows machines +class rde::windows { + tag 'cbc' + + #$win_software_repo = '\\az251dp2ch2d\Software' # A software repo. Currently on the machine under test but can be on any share + + # Install Cygwin + $cyg_setup = "$win_software_repo\\Cygwin-2.9-Win64\\setup-x86_64.exe" + $cyg_repo = "-L -l $win_software_repo\\Cygwin-2.9-Win64" + $cyg_categories = "-C Base" + $cyg_root = 'C:\Cygwin' + $cyg_install_to = "-R $cyg_root" + $cyg_pkgs = "-P openssh,cygrunsrv,bzip2,unzip,zip,gcc-core,gcc-G++,git,git-gui,make,vim,vim-common,perl,perl_base,perl-Term-ReadLine-Gnu,perl-Term-ReadKey,php,python2,python3,dos2unix,rlwrap,wget,xorg-server,xorg-server-common,xorg-x11-fonts-dpi100,xauth,xclock,xload,xterm,gnome-terminal,dbus-x11" + + exec { 'Install Cygwin': + command => "$cyg_setup -q $cyg_repo $cyg_install_to $cyg_categories $cyg_pkgs", + creates => $cyg_root, + timeout => 600, # Cygwin takes some time to install + } + + exec { 'Setup sshd': + path => "$cyg_root\\bin", + command => "bash /usr/bin/ssh-host-config2 -y -u cyg_server -w 'Ranroot!'", + creates => "$cyg_root/etc/sshd_config", + logoutput => 'on_failure', + } + + windows::path { "$cyg_root\\bin": } + + windows::unzip { "$win_software_repo\\ProcessExplorer.zip": + destination => 'C:\Windows\System32', + creates => 'C:\Windows\System32\Procexp.exe', + } + + exec { 'Install Firefox': + command => "$win_software_repo\\FirefoxInstaller.exe -ms", + creates => 'C:\Program Files\Mozilla Firefox\firefox.exe', + } + + exec { 'Install Adobe Reader': + command => "$win_software_repo\\AcroRdrDC1801120040_en_US.exe /sAll", + creates => 'C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe', + } +} diff --git a/puppet/gd/winclient.pp b/puppet/gd/winclient.pp new file mode 100644 index 0000000..3073f55 --- /dev/null +++ b/puppet/gd/winclient.pp @@ -0,0 +1,7 @@ +# RDE Puppet Windows Client config + +# This subclass defines the configuration for RDE Windows client machines +class rde::windows::client { + # Not sure what additional software is needed for a Windows Server to be a Domain + # Controller (DC) nor what added software might make it more useful. +} diff --git a/puppet/gd/windc.pp b/puppet/gd/windc.pp new file mode 100644 index 0000000..18f6df6 --- /dev/null +++ b/puppet/gd/windc.pp @@ -0,0 +1,25 @@ +# RDE Puppet Windows Domain Controller config + +# This subclass defines the configuration for RDE Windows domain controller +class rde::windows::domain_controller { + tag 'dc' + + install => 'present', + installmanagementtools => true, + restart => true, + installflag => true, + configure => 'present', + configureflag => true, + domain => 'forest', + domainname => 'gddsi.com', + netbiosdomainname => 'rde', + domainlevel => '6', + forestlevel => '6', + databasepath => 'c:\windows\ntds', + logpath => 'c:\windows\ntds', + sysvolpath => 'c:\windows\sysvol', + installtype => 'domain', + dsrmpassword => '', + installdns => 'yes', + localadminpassword => '', +} \ No newline at end of file diff --git a/puppet/gd/winserver.pp b/puppet/gd/winserver.pp new file mode 100644 index 0000000..abf43c4 --- /dev/null +++ b/puppet/gd/winserver.pp @@ -0,0 +1,7 @@ +# RDE Puppet Windows Server config + +# This subclass defines the configuration for RDE Windows server machines + +class rde::windows::server { + +} \ No newline at end of file diff --git a/puppet/gd/wints.pp b/puppet/gd/wints.pp new file mode 100644 index 0000000..6963e74 --- /dev/null +++ b/puppet/gd/wints.pp @@ -0,0 +1,188 @@ +# RDE Puppet Windows Terminal config + +# This subclass defines the configuration for RDE Windows terminal server. Note that +# this server will have a lot of development tools installed on it as RDE developers +# use these machines to run Windows tools. +# +# Seems like there are a few ways to install Windows packages. One is just using exec. +# The other is just to unzip a file. Finally there's .msi files. I think we can use +# the package resource for .msi's and .exe's. Not as sure about being able to unsip +# applications that are just delivered as a zip file. I need a Windows machine to test +# things on. + +class rde::wints { + $win_software_repo = '\\az251dp2ch2d\Software' # A software repo. Currently on the machine under test but can be on any share + tag 'ts' + + # ActivePerl: Installs OK + windows::unzip { "$win_software_repo\\ActivePerl-5.24.3.2404-MSWin32-x64-404865.zip": + destination => "C:\\", + creates => 'C:\Perl', + tag => ['activeperl'], + } + + # PHP + file { 'C:\PHP': + ensure => 'directory', + tag => ['php'], + } + + # PHP: Installs OK + windows::unzip { "$win_software_repo\\PHP-5.6.31\\php-5.6.31-Win32-VC11-x86.zip": + destination => "C:\\PHP", + creates => "C:\\PHP\\bin", + require => File['C:\PHP'], + tag => ['php'], + } + + # Ghostscript: Installs OK + package { 'Ghostscript': + source => "$win_software_repo\\Ghostscript-9.0.9\\gs909w64.exe", + install_options => '/S /NCRC', + tag => ['ghostscript'], + } + + # BeyondCompare: Installs OK + exec { 'Beyond Compare': + command => "$win_software_repo\\TPS1166_Beyond_Compare\\beycomp_081407.exe /verysilent /sp-", + tag => ['beyondcompare'] + } + + # SecureCRT: Installs OK + package { 'SecureCRT': + source => "$win_software_repo\\TPS1284_SecureCRT_v6.63\\scrt663-x64.exe", + install_options => '/s /v"/qn"', + tag => ['securecrt'], + } + + # Apache Tomcat: Installs OK + windows::unzip { "$win_software_repo\\Apache-Tomcat-8.5.11\\apache-tomcat-8.5.11-windows-x64.zip": + destination => 'C:\Program Files', + creates => 'C:\Program Files\apache-tomcat-8.5.11', + tag => ['apachetomcat'], + } + + # DeepBurner: Installs OK + package { 'DeepBurner': + source => "$win_software_repo\\DeepBurner-1.9\\DeepBurner1.exe", + install_options => '/s', + tag => ['deepburner'], + } + + # GnuWin32: This "install" requires considerable hand configuration and also + # reaches out to the Internet to download packages. This will not fly behind + # a firewall and most of the functionality here is already provided in Cygwin. + # exec { 'GnuWin32': + # command => "$win_software_repo\\GnuWin32-0.6.21\\GetGnuWin32\\install.bat", + # creates => "???", + #} + + # Notepad++: Installs OK + package { 'Notepad++': + source => "$win_software_repo\\Notepad++7.5.6\\npp.7.5.6.Installer.exe", + install_options => '/S', + tag => ['notepadplusplus'], + } + + # Console2: Installs OK + windows::unzip { "$win_software_repo\\Console-2.00b148-Beta_64bit.zip": + destination => 'C:\Program Files', + creates => 'C:\Program Files\Console2', + tag => 'console2', + } + + # JDK: Installs OK + package { 'JDK': + source => "$win_software_repo\\jdk-8u172-windows-x64.exe", + install_options => '/s', + tag => 'jdk', + } + + # Eclipse: Installs OK + windows::unzip { "$win_software_repo\\Eclipse.zip": + destination => "C:\\", + creates => 'C:\Eclipse', + tag => ['eclipse'], + } + + windows::shortcut { 'C:\Users\All Users\Desktop\Eclipse.lnk': + target => 'C:\Eclipse\Eclipse.exe', + description => 'Eclipse IDE', + tag => ['eclipse'], + } + + # Microsoft SQL Server: I tried installing this but it was too old to run on + # 2012 R2 + # exec { 'Microsoft SQL Server': + # command => "$win_software_repo\\Microsoft-SQL-Server-2005-SP3-Express-Edition\\SQLEXPR64-SP3.exe", + # #creates => "???", + #} + + # Microsoft Visual Studio: Thought this was working. Turns out it doesn't work. + # Works by hand though :-( + exec { 'Microsoft Visual Studio': + command => "$win_software_repo\\TPS0004_Visual_studio_Pro_2010\\Setup\Setup.exe /q /full", + creates => 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe', + tag => ['visualstudio'], + timeout => 600, # Visual Studio takes some time to install + } + + exec { 'Console Emulator': + command => "$win_software_repo\\ConEmu-150813\\ConEmuSetup.150813g.exe /p:x64 /qr", + creates => 'C:\Program Files\ConEmu', + tag => ['conemu'], + } + + # Putty: Installs OK + exec { 'Putty': + command => "$win_software_repo\\TPS1288_PuTTY\\putty-0.63-installer.exe /verysilent /sp-", + tag => ['putty'], + } + + # Python 2.7.13: Installs OK + package { 'Python 2.7.13': + source => "$win_software_repo\\Python-2.7.13\\Windows\\python-2.7.13.amd64.msi", + install_options => '/qn', + tag => ['python2713'], + } + + # Pythong 3.6.4: Installs OK + exec { 'Python 3.6.4': + command => "$win_software_repo\\Python-3.6.4\\python-3.6.4-amd64.exe /quiet InstallAllUsers=1 PrependPath=1", + tag => ['python364'], + } + + # TeraTerm: Installs OK + package { 'TeraTerm': + source => "$win_software_repo\\TeraTerm-4.7.3\\teraterm-4.73.exe", + install_options => '/verysilent', + tag => ['teraterm'], + } + + # VIM 7.3: Installs OK + windows::unzip { "$win_software_repo\\VIM-7.3\\MSDOS\\vim73w32.zip": + destination => 'C:\Program Files', + creates => 'C:\Program Files\vim', + tag => ['vim'], + } + + # VNC: Installs OK + package { 'VNC': + source => "$win_software_repo\\VNC-Open-4.1.3\\vnc-4_1_3-x86_win32.exe", + install_options => '/verysilent', + tag => ['vnc'], + } + + # Microsoft Office: Installs OK + exec { 'Microsoft Office': + command => "$win_software_repo\\TPS1293_Office_Standard\\setup.exe /config Standard.WW\config.xml", + tag => ['office'], + } + + # Microsoft Visio: Installs OK + exec { 'Microsoft Visio': + command => "$win_software_repo\\TPS0003_Visio_Standard\\x86\\setup.exe /config Visio.WW\config.xml", + timeout => 600, # Microsoft Visio takes some time to install + tag => ['visio'], + } +} diff --git a/puppet/init.pp b/puppet/init.pp new file mode 100644 index 0000000..3346210 --- /dev/null +++ b/puppet/init.pp @@ -0,0 +1,248 @@ +# RDE Puppet Base config +# +# This is the base class for all machines. +class rde { + package { 'nis': + ensure => 'present', + } + + nis { 'domainname': + domainname => 'rde', + } + + file { '/etc/defaultdomain': + path => '/etc/defaultdomain', + owner => 'root', + group => 'sys', + mode => '0644', + content => 'rde', + notify => Service['nis/client'], + } + + service { 'nis/domain': + ensure => 'running', + enable => 'true', + provider => 'smf', + notify => Service['nis/client'], + } + + nsswitch { 'nsswitch': + alias => 'files nis', + automount => 'files nis', + default => 'files', + group => 'files nis', + host => 'files dns nis', + netgroup => 'files nis', + password => 'files nis', + notify => [Service['nis/client'], Service['autofs']], + } + + service { 'nis/client': + ensure => 'running', + enable => 'true', + provider => 'smf', + notify => Service['autofs'], + } + + service { 'dns/client': + ensure => 'running', + enable => 'true', + provider => 'smf', + } + + dns { 'dns/client': + #nameserver => ['10.100.13.21', '10.100.13.22'], + nameserver => ['10.100.0.10', '10.100.0.30'], + domain => 'gddsi.com', + search => ['gddsi.com'], + notify => [Service['dns/client'], Service['autofs']], + } + + package { 'ntp': + ensure => 'present', + } + + file { 'ntp.conf': + path => '/etc/inet/ntp.conf', + owner => 'root', + group => 'sys', + mode => '0444', + source => 'puppet:///modules/rde/ntp.conf', + notify => Service['ntp'] + } + + service { 'ntp': + ensure => 'running', + enable => 'true', + provider => 'smf', + } + + service { 'rpc/bind': ensure => 'running', } + + service { 'zones-proxy-client': + ensure => 'running', + enable => 'true', + provider => 'smf', + } + + # I'm not sure if this is needed on clients. It was needed for + # the NIS server and slave. + svccfg { 'binding': + fmri => 'svc:/network/rpc/bind', + property => 'config/local_only', + type => 'boolean', + value => 'false', + } + + service { 'autofs': + ensure => 'running', + enable => 'true', + provider => 'smf', + notify => Service['rpc/bind'], + } + + service { 'sendmail': + ensure => 'running', + enable => 'true', + provider => 'smf', + } + + if ($hostname = 'rdeadm1') { + file_line { 'sendmail_relay': + ensure => 'present', + path => '/etc/mail/sendmail.cf', + line => 'DSsmtp-west.gd-ms.us.', + notify => Service['sendmail'], + } + } else { + file_line { 'sendmail_relay': + ensure => 'present', + path => '/etc/mail/sendmail.cf', + line => 'DSrdeadm1.gddsi.com', + notify => Service['sendmail'], + } + } + + svccfg { 'sendmail': + fmri => 'svc:/network/smtp:sendmail', + property => 'config/local_only', + type => 'boolean', + value => 'false', + notify => Service['sendmail'], + } + + file { '/etc/passwd': + owner => 'root', + group => 'sys', + mode => '0644', + } + + file { '/etc/group': + owner => 'root', + group => 'sys', + mode => '0644', + } + + file { '/etc/shadow': + owner => 'root', + group => 'sys', + mode => '0400', + } + + host { 'rdeadm1': + ensure => 'present', + comment => 'NIS Master', + ip => '10.100.13.21', + } + + host { 'rdeadm2': + ensure => 'present', + comment => 'NIS Slave', + ip => '10.100.13.22', + } + + file { 'motd': + path => '/etc/motd', + owner => 'root', + group => 'sys', + mode => '0444', + source => 'puppet:///modules/rde/motd', + } + + file { 'issue': + path => '/etc/issue', + owner => 'root', + group => 'sys', + mode => '0444', + source => 'puppet:///modules/rde/issue', + } + + file { 'sudoers': + path => '/etc/sudoers.d/admins', + owner => 'root', + group => 'sys', + mode => '0444', + content => "+ccadms ALL=(ALL) ALL\np2282c ALL=(ALL) NOPASSWD:ALL\nhn06511 ALL=(ALL) NOPASSWD:ALL\n", + } + + # Add "+" to /etc/group + file_line { 'groups': + path => '/etc/group', + ensure => 'present', + line => '+', + } + + # Add "+" to /etc/shadow + file_line { 'shadow': + path => '/etc/shadow', + ensure => 'present', + line => '+', + } + + # Everybody mounts these + file_line { 'vob_storage', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/rdevob1 - /rdevob1 nfs - yes -', + } + file_line { 'view_storage', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/rdeview1 - /rdeview1 nfs - yes -', + } + + if ($hostname == 'rdevob1' || $hostname == 'rdevob2') { + file_line { 'transfer': + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/transfer - /transfer nfs - yes -', + } + file_line { 'rdevob2', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/rdevob2 - /rdevob2 nfs - yes -', + } + } + + if ($hostname == 'rdevob1') { + file_line { 'export', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/export - /export nfs - yes -', + } + } + + if ($hostname == 'rdevob1') { + file_line { 'rdeview2', + ensure => 'present', + path => '/etc/vfstab', + line => 'muosrdenas1:/rdeview2 - /rdeview2 nfs - yes -', + } + } + + $std_packages = ['vim', 'gvim', 'tcsh', 'xauth', 'xclock', 'xterm', 'top', 'rdesktop', 'firefox', 'telnet', 'git', 'expect', 'make', 'gcc', 'motif', 'libxp'] + + package { $std_packages: + ensure => 'present', + } +} diff --git a/puppet/server.pp b/puppet/server.pp new file mode 100644 index 0000000..66f629a --- /dev/null +++ b/puppet/server.pp @@ -0,0 +1,23 @@ +# RDE Puppet Server config + +# This subclass defines the configuration for RDE Servers +class rde::server { + # Remove any naked '+''s + file_line { 'all_users': + ensure => 'absent', + path => '/etc/passwd', + line => '# Remove +', + match => '^\+$', + match_for_absence => 'true', + replace => 'false', + tag => 'nis', + } + + # Make sure only members of the ccadms netgroup can log in + file_line { 'server_users': + path => '/etc/passwd', + ensure => 'present', + line => '+@ccadms', + tag => 'nis', + } +} diff --git a/puppet/wincbc.pp b/puppet/wincbc.pp new file mode 100644 index 0000000..734e96a --- /dev/null +++ b/puppet/wincbc.pp @@ -0,0 +1,46 @@ +# RDE Puppet Windows config + +# This subclass defines the configuration for RDE Windows machines +class rde::windows { + tag 'cbc' + + #$win_software_repo = '\\az251dp2ch2d\Software' # A software repo. Currently on the machine under test but can be on any share + + # Install Cygwin + $cyg_setup = "$win_software_repo\\Cygwin-2.9-Win64\\setup-x86_64.exe" + $cyg_repo = "-L -l $win_software_repo\\Cygwin-2.9-Win64" + $cyg_categories = "-C Base" + $cyg_root = 'C:\Cygwin' + $cyg_install_to = "-R $cyg_root" + $cyg_pkgs = "-P openssh,cygrunsrv,bzip2,unzip,zip,gcc-core,gcc-G++,git,git-gui,make,vim,vim-common,perl,perl_base,perl-Term-ReadLine-Gnu,perl-Term-ReadKey,php,python2,python3,dos2unix,rlwrap,wget,xorg-server,xorg-server-common,xorg-x11-fonts-dpi100,xauth,xclock,xload,xterm,gnome-terminal,dbus-x11" + + exec { 'Install Cygwin': + command => "$cyg_setup -q $cyg_repo $cyg_install_to $cyg_categories $cyg_pkgs", + creates => $cyg_root, + timeout => 600, # Cygwin takes some time to install + } + + exec { 'Setup sshd': + path => "$cyg_root\\bin", + command => "bash /usr/bin/ssh-host-config2 -y -u cyg_server -w 'Ranroot!'", + creates => "$cyg_root/etc/sshd_config", + logoutput => 'on_failure', + } + + windows::path { "$cyg_root\\bin": } + + windows::unzip { "$win_software_repo\\ProcessExplorer.zip": + destination => 'C:\Windows\System32', + creates => 'C:\Windows\System32\Procexp.exe', + } + + exec { 'Install Firefox': + command => "$win_software_repo\\FirefoxInstaller.exe -ms", + creates => 'C:\Program Files\Mozilla Firefox\firefox.exe', + } + + exec { 'Install Adobe Reader': + command => "$win_software_repo\\AcroRdrDC1801120040_en_US.exe /sAll", + creates => 'C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe', + } +} diff --git a/puppet/winclient.pp b/puppet/winclient.pp new file mode 100644 index 0000000..3073f55 --- /dev/null +++ b/puppet/winclient.pp @@ -0,0 +1,7 @@ +# RDE Puppet Windows Client config + +# This subclass defines the configuration for RDE Windows client machines +class rde::windows::client { + # Not sure what additional software is needed for a Windows Server to be a Domain + # Controller (DC) nor what added software might make it more useful. +} diff --git a/puppet/windc.pp b/puppet/windc.pp new file mode 100644 index 0000000..18f6df6 --- /dev/null +++ b/puppet/windc.pp @@ -0,0 +1,25 @@ +# RDE Puppet Windows Domain Controller config + +# This subclass defines the configuration for RDE Windows domain controller +class rde::windows::domain_controller { + tag 'dc' + + install => 'present', + installmanagementtools => true, + restart => true, + installflag => true, + configure => 'present', + configureflag => true, + domain => 'forest', + domainname => 'gddsi.com', + netbiosdomainname => 'rde', + domainlevel => '6', + forestlevel => '6', + databasepath => 'c:\windows\ntds', + logpath => 'c:\windows\ntds', + sysvolpath => 'c:\windows\sysvol', + installtype => 'domain', + dsrmpassword => '', + installdns => 'yes', + localadminpassword => '', +} \ No newline at end of file diff --git a/puppet/winserver.pp b/puppet/winserver.pp new file mode 100644 index 0000000..abf43c4 --- /dev/null +++ b/puppet/winserver.pp @@ -0,0 +1,7 @@ +# RDE Puppet Windows Server config + +# This subclass defines the configuration for RDE Windows server machines + +class rde::windows::server { + +} \ No newline at end of file diff --git a/puppet/wints.pp b/puppet/wints.pp new file mode 100644 index 0000000..6963e74 --- /dev/null +++ b/puppet/wints.pp @@ -0,0 +1,188 @@ +# RDE Puppet Windows Terminal config + +# This subclass defines the configuration for RDE Windows terminal server. Note that +# this server will have a lot of development tools installed on it as RDE developers +# use these machines to run Windows tools. +# +# Seems like there are a few ways to install Windows packages. One is just using exec. +# The other is just to unzip a file. Finally there's .msi files. I think we can use +# the package resource for .msi's and .exe's. Not as sure about being able to unsip +# applications that are just delivered as a zip file. I need a Windows machine to test +# things on. + +class rde::wints { + $win_software_repo = '\\az251dp2ch2d\Software' # A software repo. Currently on the machine under test but can be on any share + tag 'ts' + + # ActivePerl: Installs OK + windows::unzip { "$win_software_repo\\ActivePerl-5.24.3.2404-MSWin32-x64-404865.zip": + destination => "C:\\", + creates => 'C:\Perl', + tag => ['activeperl'], + } + + # PHP + file { 'C:\PHP': + ensure => 'directory', + tag => ['php'], + } + + # PHP: Installs OK + windows::unzip { "$win_software_repo\\PHP-5.6.31\\php-5.6.31-Win32-VC11-x86.zip": + destination => "C:\\PHP", + creates => "C:\\PHP\\bin", + require => File['C:\PHP'], + tag => ['php'], + } + + # Ghostscript: Installs OK + package { 'Ghostscript': + source => "$win_software_repo\\Ghostscript-9.0.9\\gs909w64.exe", + install_options => '/S /NCRC', + tag => ['ghostscript'], + } + + # BeyondCompare: Installs OK + exec { 'Beyond Compare': + command => "$win_software_repo\\TPS1166_Beyond_Compare\\beycomp_081407.exe /verysilent /sp-", + tag => ['beyondcompare'] + } + + # SecureCRT: Installs OK + package { 'SecureCRT': + source => "$win_software_repo\\TPS1284_SecureCRT_v6.63\\scrt663-x64.exe", + install_options => '/s /v"/qn"', + tag => ['securecrt'], + } + + # Apache Tomcat: Installs OK + windows::unzip { "$win_software_repo\\Apache-Tomcat-8.5.11\\apache-tomcat-8.5.11-windows-x64.zip": + destination => 'C:\Program Files', + creates => 'C:\Program Files\apache-tomcat-8.5.11', + tag => ['apachetomcat'], + } + + # DeepBurner: Installs OK + package { 'DeepBurner': + source => "$win_software_repo\\DeepBurner-1.9\\DeepBurner1.exe", + install_options => '/s', + tag => ['deepburner'], + } + + # GnuWin32: This "install" requires considerable hand configuration and also + # reaches out to the Internet to download packages. This will not fly behind + # a firewall and most of the functionality here is already provided in Cygwin. + # exec { 'GnuWin32': + # command => "$win_software_repo\\GnuWin32-0.6.21\\GetGnuWin32\\install.bat", + # creates => "???", + #} + + # Notepad++: Installs OK + package { 'Notepad++': + source => "$win_software_repo\\Notepad++7.5.6\\npp.7.5.6.Installer.exe", + install_options => '/S', + tag => ['notepadplusplus'], + } + + # Console2: Installs OK + windows::unzip { "$win_software_repo\\Console-2.00b148-Beta_64bit.zip": + destination => 'C:\Program Files', + creates => 'C:\Program Files\Console2', + tag => 'console2', + } + + # JDK: Installs OK + package { 'JDK': + source => "$win_software_repo\\jdk-8u172-windows-x64.exe", + install_options => '/s', + tag => 'jdk', + } + + # Eclipse: Installs OK + windows::unzip { "$win_software_repo\\Eclipse.zip": + destination => "C:\\", + creates => 'C:\Eclipse', + tag => ['eclipse'], + } + + windows::shortcut { 'C:\Users\All Users\Desktop\Eclipse.lnk': + target => 'C:\Eclipse\Eclipse.exe', + description => 'Eclipse IDE', + tag => ['eclipse'], + } + + # Microsoft SQL Server: I tried installing this but it was too old to run on + # 2012 R2 + # exec { 'Microsoft SQL Server': + # command => "$win_software_repo\\Microsoft-SQL-Server-2005-SP3-Express-Edition\\SQLEXPR64-SP3.exe", + # #creates => "???", + #} + + # Microsoft Visual Studio: Thought this was working. Turns out it doesn't work. + # Works by hand though :-( + exec { 'Microsoft Visual Studio': + command => "$win_software_repo\\TPS0004_Visual_studio_Pro_2010\\Setup\Setup.exe /q /full", + creates => 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe', + tag => ['visualstudio'], + timeout => 600, # Visual Studio takes some time to install + } + + exec { 'Console Emulator': + command => "$win_software_repo\\ConEmu-150813\\ConEmuSetup.150813g.exe /p:x64 /qr", + creates => 'C:\Program Files\ConEmu', + tag => ['conemu'], + } + + # Putty: Installs OK + exec { 'Putty': + command => "$win_software_repo\\TPS1288_PuTTY\\putty-0.63-installer.exe /verysilent /sp-", + tag => ['putty'], + } + + # Python 2.7.13: Installs OK + package { 'Python 2.7.13': + source => "$win_software_repo\\Python-2.7.13\\Windows\\python-2.7.13.amd64.msi", + install_options => '/qn', + tag => ['python2713'], + } + + # Pythong 3.6.4: Installs OK + exec { 'Python 3.6.4': + command => "$win_software_repo\\Python-3.6.4\\python-3.6.4-amd64.exe /quiet InstallAllUsers=1 PrependPath=1", + tag => ['python364'], + } + + # TeraTerm: Installs OK + package { 'TeraTerm': + source => "$win_software_repo\\TeraTerm-4.7.3\\teraterm-4.73.exe", + install_options => '/verysilent', + tag => ['teraterm'], + } + + # VIM 7.3: Installs OK + windows::unzip { "$win_software_repo\\VIM-7.3\\MSDOS\\vim73w32.zip": + destination => 'C:\Program Files', + creates => 'C:\Program Files\vim', + tag => ['vim'], + } + + # VNC: Installs OK + package { 'VNC': + source => "$win_software_repo\\VNC-Open-4.1.3\\vnc-4_1_3-x86_win32.exe", + install_options => '/verysilent', + tag => ['vnc'], + } + + # Microsoft Office: Installs OK + exec { 'Microsoft Office': + command => "$win_software_repo\\TPS1293_Office_Standard\\setup.exe /config Standard.WW\config.xml", + tag => ['office'], + } + + # Microsoft Visio: Installs OK + exec { 'Microsoft Visio': + command => "$win_software_repo\\TPS0003_Visio_Standard\\x86\\setup.exe /config Visio.WW\config.xml", + timeout => 600, # Microsoft Visio takes some time to install + tag => ['visio'], + } +} diff --git a/rc/bash_login b/rc/bash_login index d390e56..fcfa0a4 100644 --- a/rc/bash_login +++ b/rc/bash_login @@ -121,6 +121,12 @@ if [ -r /etc/bash_completion -a $ARCHITECTURE != "cygwin" ]; then source /etc/bash_completion fi +# Windows aliases +if [ $ARCHITECTURE = "cygwin" ]; then + alias ping=$(echo $SYSTEMROOT | tr '\\' '\/')/system32/ping + alias rdp=mstsc +fi + # We specify /home/$USER here so that when we sudo to another user # we will only trap logout if that user also has a ~/.rc/logout # (doubtfull). diff --git a/rc/clearcase b/rc/clearcase index 1c33ad1..14a3d88 100644 --- a/rc/clearcase +++ b/rc/clearcase @@ -132,11 +132,11 @@ function lllock { # View related functions function setview { if [ $ARCHITECTURE = 'cygwin' ]; then - if [[ $1 = -* ]]; then - echo "The setview command with options is not supported on Windows" - return - fi - + if [[ $1 = -* ]]; then + echo "The setview command with options is not supported on Windows" + return + fi + # Save off where we are back=$PWD @@ -148,7 +148,7 @@ function setview { fi # Setup $VOBTAG_PREFIX - mount -f -o binary $CLEARCASE_VIEW_DRIVE:/$1 $LINUX_VOBTAG_PREFIX + mount -f -o binary M:/$1 $LINUX_VOBTAG_PREFIX # Start a bash shell bash diff --git a/rc/client_scripts/GD b/rc/client_scripts/GD index 9b7163e..e9abf66 100755 --- a/rc/client_scripts/GD +++ b/rc/client_scripts/GD @@ -18,11 +18,6 @@ if [ -d /cleartrig/ent/SNSD/muos/ccadm_tools/vobs/ranccadm/scripts/lib ]; then export PERL5LIB=/cleartrig/ent/SNSD/muos/ccadm_tools/vobs/ranccadm/scripts/lib:$PERL5LIB fi -# This may need to be moved into bash_login -if [ "$ARCHITECTURE" = "cygwin" ]; then - alias ping=$SYSTEMROOT/System32/ping -fi - export QTDIR="/usr/local/Trolltech/Qt-4.2.2" export QMAKESPEC="$QTDIR/mkspecs/solaris-cc" export ORACLE="SID rancq" @@ -66,4 +61,5 @@ append_to_path "/cygcrive/d/Program Files/IBM/RationalSDLC/ClearCase/bin" append_to_path "/cygdrive/c/Program Files (x86)/ibm/gsk8/lib" # Common CDPATHS -CDPATH=$CDPATH:/vobs/ranccadm +export CT=/cleartrig/ent/SNSD/muos/ccadm_tools/vobs/ranccadm/scripts +CDPATH=$CDPATH:/vobs/ranccadm:$CT diff --git a/rc/git b/rc/git index c6253a2..341ca7b 100644 --- a/rc/git +++ b/rc/git @@ -32,10 +32,20 @@ function git () { # Need to reset title since we put the branch name in the titlebar git=$(which git) - if [ "$1" = "checkout" -o "$1" = "co" ]; then - $git $@ - set_title - else - $git $@ + if [ "${git:0:3}" != "no " ]; then + if [ "$1" = "checkout" -o "$1" = "co" ]; then + $git $@ + set_title + elif [ "$1" = "files" ]; then + if [ -z "$2" ]; then + echo "Files in git commit HEAD" + $git show --pretty="" --name-only HEAD + else + echo "Files in git commit $2" + $git show --pretty="" --name-only $2 + fi + else + $git $@ + fi fi } # git diff --git a/rc/gitconfig b/rc/gitconfig index 6fdaf4b..719fcef 100644 --- a/rc/gitconfig +++ b/rc/gitconfig @@ -17,6 +17,15 @@ diff=auto branch=auto +[diff] + tool = meld + +[difftool] + prompt = false + +[difftool "meld"] + cmd = meld "$LOCAL" "$REMOTE" + # Currently these are restating the default [color "branch"] current=green @@ -24,7 +33,7 @@ remote=red [color "diff"] - external = /usr/local/bin/git-meld + external = /bin/meld [color "status"] added=yellow diff --git a/test/testMDYHMS2SQLDatetime.pl b/test/testMDYHMS2SQLDatetime.pl new file mode 100755 index 0000000..aef0e3b --- /dev/null +++ b/test/testMDYHMS2SQLDatetime.pl @@ -0,0 +1,107 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use FindBin; +use lib "$FindBin::Bin/../lib"; + +use Display; +use CmdLine; + +sub _is_leap_year($) { + my ($year) = @_; + + return 0 if $year % 4; + return 1 if $year % 100; + return 0 if $year % 400; + + return 1; +} # _is_leap_year + +sub MDYHMS2SQLDatetime($) { + my ($datetime) = @_; + + $datetime =~ s/^\s+|\s+$//g; + + my ($year, $mon, $day, $hour, $min, $sec, $ampm); + + # For datetime format of MM/DD/YYYY HH:MM:SS [Am|Pm] + if ($datetime =~ /^(\d{1,2})\/(\d{1,2})\/(\d{4}) (\d{1,2}):(\d{1,2}):(\d{1,2}) (\w{2})$/) { + $mon = $1; + $day = $2; + $year = $3; + $hour = $4; + $min = $5; + $sec = $6; + $ampm = $7; + # For datetime format of MM/DD/YYYY HH:MM:SS + } elsif ($datetime =~ /^(\d{1,2})\/(\d{1,2})\/(\d{4}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/){ + $mon = $1; + $day = $2; + $year = $3; + $hour = $4; + $min = $5; + $sec = $6; + # For datetime format of MM/DD/YYYY + } elsif ($datetime =~ /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/) { + $mon = $1; + $day = $2; + $year = $3; + $hour = '00'; + $min = '00'; + $sec = '00'; + } else { + return + } # if + + # Range checks + return if $mon > 12 or $mon <= 0; + return if $day > 31 or $day <= 0; + return if $hour > 23 or $hour < 0; + return if $min > 59 or $min < 0; + + if ($day >= 31 and ($mon == 2 + or $mon == 4 + or $mon == 6 + or $mon == 9 + or $mon == 11)) { + return; + } # if + + return if $day > 29 and $mon == 2; + return if $day == 29 and $mon == 2 and not _is_leap_year($year); + + # Convert to 24 hour time if necessary + $hour += 12 if $ampm and $ampm =~ /pm/i; + + # Add any leading zeros + $mon = "0$mon" if length $mon == 1; + $day = "0$day" if length $day == 1; + $hour = "0$hour" if length $hour == 1; + $min = "0$min" if length $min == 1; + $sec = "0$sec" if length $sec == 1; + + return "$year-$mon-$day $hour:$min:$sec"; +} # MDYHMS2SQLDatetime + +local $| = 1; + +$CmdLine::cmdline->set_prompt('Enter datetime:'); + +while () { + my $datetime = $CmdLine::cmdline->get; + + last unless defined $datetime; + last if $datetime =~ /(exit|quit|e|q)/i; + + if ($datetime) { + my $newdatetime = MDYHMS2SQLDatetime $datetime; + + if ($newdatetime) { + display $newdatetime; + } else { + error "Date $datetime is invalid"; + } # if + } # if +} # while diff --git a/test/testMachinesMySQL.pl b/test/testMachinesMySQL.pl new file mode 100755 index 0000000..af13546 --- /dev/null +++ b/test/testMachinesMySQL.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Getopt::Long; +use Pod::Usage; + +use FindBin; + +use lib "$FindBin::Bin/../lib"; + +use Display; +use Machines::MySQL; +use Utils; + +my %opts = ( + usage => sub { podusage() } , + hostname => $ENV{HOST} || 'localhost', + username => $ENV{USERNAME} ? $ENV{USERNAME} : $ENV{USER}, + password => $ENV{PASSWORD}, + database => 0, +); + +sub AddSystems($) { + my ($machines) = @_; + + my @machines = $machines->ReadSystemsFile; + + for (@machines) { + my ($err, $msg) = $machines->AddSystem(%$_); + + error ($msg) if $err; + } # for +} # AddSystems + +GetOptions ( + \%opts, + 'usage', + 'host=s', + 'username=s', + 'password=s', + 'database', + 'filename=s', +); + +my $machines; + +unless ($opts{database}) { + require Machines; Machines->import; + + $machines = Machines->new(filename => $opts{filename}); +} else { + require Machines::MySQL; Machines::MySQL->import; + + $machines = Machines::MySQL->new; +} # if + +#for ($machines->select ("os = '2.4.21-50.Elsmp'")) { + +if (ref($machines) eq 'Machines') { + display "From file:"; +} elsif (ref($machines) eq 'Machines::MySQL') { + display "From database"; +} # if + +my %records = $machines->select; + +for (sort keys %records) { + display "Would execute command on $_ ($records{$_}{model})"; +} # for + +display "done"; diff --git a/test/testclearcase.pl b/test/testclearcase.pl index 545f3d0..512d372 100755 --- a/test/testclearcase.pl +++ b/test/testclearcase.pl @@ -43,17 +43,6 @@ $Date: 2011/01/09 01:01:32 $ -[no]uc|m: Perform UCM Clearcase tests (Default: noucm) -[no]clean: Cleanup after yourself (Default: clean) -if -ucm is specified then the following additional parameters should be set: - - -username: Username to connect to Clearquest with (Can set CQ_USERNAME) - -password: Password to use to connect to Clearquest (CQ_PASSWORD) - -weburl: Web URL to use for enabling Clearcase -> Clearquest - connection (CQ_WEBURL - Do not specify the trailing - "/oslc") - -database: Clearquest database to enable (CQ_DATABASE) - -dbset: Clearquest DBSet (CQ_DBSET) - -provider: Name of provider (Default: CQPROV) - =head1 DESCRIPTION Clearcase smoke tests. Perform simple Clearcase operations to validate that @@ -69,7 +58,7 @@ use warnings; use Cwd; use FindBin; use Getopt::Long; -use Pod::Usage; +#use Term::ANSIColor qw(:constants); use lib "$FindBin::Bin/../lib"; @@ -131,20 +120,11 @@ sub LogOpts() { ); for (sort keys %opts) { - next if /help/ || /usage/ || /password/; - if (ref $opts{$_} eq 'ARRAY') { my $name = $_; - - for (@{$opts{$_}}) { - $log->msg("$name:\t$_") if $_; - } # for + $log->msg("$name:\t$_") for @{$opts{$_}}; } else { - if ($opts{$_}) { - $log->msg("$_:\t$opts{$_}"); - } else { - $log->msg("$_:\t"); - } # if + $log->msg("$_:\t$opts{$_}"); } # if } # for @@ -208,28 +188,14 @@ sub DestroyVob($) { ($status, @output) = $Clearcase::CC->execute('cd'); - $log->err('Unable to perform cd command', 1) if $status; - $log->msg('Unmounting vob ' . $vob->tag); ($status, @output) = $vob->umount; - if ($status) { - $log->err('Unable to unmount vob ' . $vob->tag); - } else { - $log->msg('Umounted vob ' . $vob->tag); - } # if - $log->msg('Removing vob ' . $vob->tag); ($status, @output) = $vob->remove; - if ($status) { - $log->err("Failed to execute command " . - $Clearcase::CC->lastcmd . "\n" . - join "\t\n", @output); - } # if - $log->log($_) for @output; return $status; @@ -261,18 +227,6 @@ sub SetView($) { return $status; } # SetView -sub StopView($) { - my ($view) = @_; - - $log->msg('Stopping view ' . $view->tag); - - my ($status, @output) = $view->stop; - - $log->log($_) for @output; - - return $status; -} # StopView - sub DestroyView($) { my ($view) = @_; @@ -492,7 +446,7 @@ sub CleanupUCM() { ($rc, @output) = $test_activity->remove; $status += $rc; - + $log->log($_) for @output; # Need to remove baselines from streams first using rebase (Devstream) @@ -550,7 +504,7 @@ sub CleanupUCM() { $log->log($_) for @output; $status += DestroyView($test_intview); - + $log->msg('Removing '. $test_devstream->name); ($rc, @output) = $test_devstream->remove; @@ -640,71 +594,19 @@ sub SetupTest($$) { ($status, @output) = $Clearcase::CC->execute("cd $dir"); - $log->log($_) for @output; + if ($status != 0) { + $log->log($_) for @output; + } # if return $status; } # SetupTest -sub SetupAttributeTypes() { - my @CC_CMI_Types = qw(CONTEXT TASK PROVIDERS); - - my $status = SetView($test_intview); - - return $status if $status; - - for (@CC_CMI_Types) { - my $cmd = "mkattype -nc -vtype string CC_CMI_$_"; - - my ($rc, @output) = $Clearcase::CC->execute($cmd); - - $status += $rc; - - $log->log($_) for @output; - } # for - - return $status; -} # SetupAttributeTypes - -sub CRMRegister() { - my $cmd = "crmregister add -database $opts{database} -connection RDE " - . "-url $opts{weburl} -username $opts{username} " - . "-password $opts{password}"; - - my ($status, @output) = Execute $cmd; - - $log->log($_) for @output; - - return $status; -} # CRMRegister - -sub MakeCMProvider() { - my $cmd = 'mkcmprovider -vob ' . $test_pvob->tag - . '-type cmcq -version V1_0 -description ' - . '"RDE CMI CQ Provider" ' - . '-connection baseurl:' . $opts{weburl} . " $opts{provider}"; - - my ($status, @output) = $Clearcase::CC->execute($cmd); - - $log->log($_) for @output; - - return $status; -} # MakeCMProvider - sub SetupUCMTest() { my $status; - $log->msg("Register RDE://$opts{username}\@$opts{database}"); - - $status = CRMRegister; - - $log->err("Unable to register RDE://$opts{username}\@$opts{database} - Check logfile", $status) - if $status; + $log->msg("Creating UCM Pvob $Clearcase::VOBTAG_PREFIX/tc.pvob"); - $log->msg("Creating UCM Pvob ${Clearcase::VOBTAG_PREFIX}tc.pvob"); - - ($status, $test_pvob) = CreatePvob("${Clearcase::VOBTAG_PREFIX}tc.pvob"); - - MountVob $test_pvob; + ($status, $test_pvob) = CreatePvob("$Clearcase::VOBTAG_PREFIX/tc.pvob"); return $status; } # SetupUCMTest @@ -716,7 +618,7 @@ sub CreateUCMProject() { $test_project = Clearcase::UCM::Project->new('tc.project', $test_folder, $test_pvob); $test_project->remove if $test_project->exists; - + $log->msg('Creating UCM Project tc.project'); my ($status, @output) = $test_project->create; @@ -862,7 +764,6 @@ sub RunUCMTests() { $status += CreateUCMIntStream; $status += CreateUCMDevStream; $status += CreateUCMIntView; - $status += SetupAttributeTypes; $status += CreateUCMDevView; $status += CreateUCMComponent; $status += AddModifiableComponent; @@ -883,18 +784,8 @@ my $startTime = time; my $conf_file = "$FindBin::Bin/$script.conf"; my $status = 0; -$opts{help} = sub { pod2usage }; -$opts{usage} = sub { pod2usage (-verbose => 2)}; -$opts{base} = 1; -$opts{clean} = 1; -$opts{username} = $ENV{CQ_USERNAME}; -$opts{password} = $ENV{CQ_PASSWORD}; -$opts{weburl} = $ENV{CQ_WEBURL}; - -$opts{weburl} .= $opts{weburl} ? "/oslc" : undef; -$opts{database} = $ENV{CQ_DATABASE}; -$opts{dbset} = $ENV{CQ_DBSET}; -$opts{provider} = $ENV{CQ_PROVIDER} || 'CQPROV'; +$opts{base} = 1; +$opts{clean} = 1; GetOptions( \%opts, @@ -905,11 +796,7 @@ GetOptions( 'base!', 'ucm!', 'clean!', - 'username=s', - 'database=s', - 'dbset=s', - 'provider', -) || pod2usage; +) or Usage; # Read the config file if (-f $conf_file) { @@ -923,13 +810,6 @@ for (keys %default_opts) { $opts{$_} = $default_opts{$_} if !$opts{$_}; } # for -# Check CQ parameters -if ($opts{ucm}) { - for ('username', 'password', 'weburl', 'database', 'dbset', 'provider') { - pod2usage "In UCM mode you must specify -$_" unless $opts{$_}; - } # for -} # if - $log->msg("$script: Start"); LogOpts; @@ -937,12 +817,10 @@ LogOpts; # Since we are creating private vobs (to avoid complications with having to # know and code the registry password when making public vobs), we'll simply # change $Clearcase::VOBTAG_PREFIX -if ($ARCHITECTURE !~ /win/i) { - $Clearcase::VOBTAG_PREFIX = $ENV{TMP} . '/' || '/tmp'; -} # if +$Clearcase::VOBTAG_PREFIX = $ENV{TMP} || '/tmp'; if ($opts{base}) { - $status = SetupTest "${Clearcase::VOBTAG_PREFIX}tc.vob", 'tc.view'; + $status = SetupTest "$Clearcase::VOBTAG_PREFIX/tc.vob", 'tc.view'; if ($status == 0) { $status += RunTests; @@ -951,7 +829,7 @@ if ($opts{base}) { } # if # Note if we are doing UCM tests then we need the view and vob here... - $status += Cleanup($test_view, $test_vob) if $opts{clean} && !$opts{ucm}; + $status += Cleanup($test_view, $test_vob) if $opts{clean} and !$opts{ucm}; if ($status != 0) { $log->err("$script: Failed (Base Clearcase)"); @@ -1007,9 +885,11 @@ L L +L + =head2 ClearSCM Perl Modules -=begin man +=begin man Clearcase Clearcase::Element diff --git a/test/testclearquest.pl b/test/testclearquest.pl index df33056..571d9f5 100755 --- a/test/testclearquest.pl +++ b/test/testclearquest.pl @@ -313,7 +313,7 @@ sub CreateWOR() { RCLC_name => 'Test RCLC', Prod_Arch1 => 'testcode : N/A', work_product_name => '10 - Software', - #Engr_target => 'Test Engineering Target', + Engr_target => 'Test Engineering Target', work_code_name => 'RAN-RW2', ); @@ -502,7 +502,7 @@ DeleteRecord 'Component', $FindBin::Script if $opts{add}; $log->msg('Enable tc.project for integration with Clearquest'); -$test_pvob = Clearcase::UCM::Pvob->new("${Clearcase::VOBTAG_PREFIX}tc.pvob"); +$test_pvob = Clearcase::UCM::Pvob->new("${Clearcase::VOBTAG_PREFIX}/tc.pvob"); $test_project = Clearcase::UCM::Project->new('tc.project', 'tc.folder', $test_pvob); my ($rc, @output) = $test_project->change("-force -crmenable $opts{CQ_DATABASE}");