#!/bin/sh # # Restart with Tcl \ exec tclsh $0 $@ #------------------------------------------------------------------------ # $Id: ac,v 1.5 2011/01/30 08:37:36 robroy Exp $ # # "ac" is a simple command-line client to the Hitachi Command Suite # (H)ost (D)ata (C)ollector product. # # It interacts directly with the HDC server, which allows the # collection of host configuration information in XML format. This # is ideal for incorporating in your own scripts as an alternative to # the Hitachi Command Suite GUI. # # "ac" was originally written on OpenBSD/i386 4.7 using Tcl 8.5.7. # It requires the http, tls, base64, and cmdline packages. # # Copyright Robroy Gregg, Computer Consultant 2011. All rights reserved. #------------------------------------------------------------------------ set ::scriptName [file tail $argv0] set ::version 1.1 #---------------------------------------------------------------------- # You'll no doubt wish to update these defaults. #---------------------------------------------------------------------- set defaultTargetIP 192.168.16.2 set defaultServerIP 192.168.16.1 set defaultOperation GetStatus set defaultAccount root set defaultPassword LetMeIn set defaultServiceId n/a set defaultPort 23051 set zipDir ${env(HOME)}/${scriptName}ZipFiles #---------------------------------------------------------------------- # Check library dependencies. #---------------------------------------------------------------------- package require http ;# For HTTP POST operations package require tls ;# For SSL support package require base64 ;# For password encoding (from tcllib) package require cmdline ;# For parsing command-line arguments #---------------------------------------------------------------------- # This function prints usage/help information. #---------------------------------------------------------------------- proc ::Usage {} { set formatPattern { %-6s %-14s %-20s %33s } puts { } puts "How to use $::scriptName ${::version}: " puts { } puts {Synopsis: } puts { } puts -nonewline " $::scriptName " puts -nonewline {[-t IP] [-s IP] [-o op] [-u user] [-p pass]} puts { [-port n] [-i n] [-sudo] [-h]} puts { } puts {Flag Table: } puts { } puts [format $formatPattern Flag Value Default Description] puts -nonewline { --------------------------------------} puts -nonewline {-------------------------------------- } puts {} foreach {flag value default description} " -t {} $::defaultTargetIP {HDC target IP address} -s {} $::defaultServerIP {HDC server IP address} -o $::defaultOperation {HDC operation to request} -u $::defaultAccount {HDC target account} -p $::defaultPassword {HDC target password} -i {} $::defaultServiceId {HDC service ID} -port $::defaultPort {HDC server port number} -sudo n/a {Don't use sudo} {Gather using sudo} -h n/a n/a {Print this help message} " {puts [format $formatPattern $flag $value $default $description]} puts { } puts {Examples: } puts { } puts { 1. Start a Windows gather using many defaults. } puts { } puts " $::scriptName -t 172.17.78.82 -o Windows " puts { } puts { 2. Start a sudo Solaris gather as harvy/millyears. } puts { } puts " $::scriptName -t 172.17.75.99 -o Solaris -u harvy\ -p millyears -sudo" puts { } puts { 3. See the status of ID "srv_000000118" through the default\ HDC server.} puts { } puts " $::scriptName -i 118 " puts { } } #---------------------------------------------------------------------- # Process command-line arguments. #---------------------------------------------------------------------- set options " \"t.arg $defaultTargetIP {The HDC target's IP address} \" \"s.arg $defaultServerIP {The HDC server's IP address} \" \"o.arg $defaultOperation {The HDC operation to request} \" \"u.arg $defaultAccount {The HDC target's account name} \" \"p.arg $defaultPassword {The HDC target's password} \" \"i.arg $defaultServiceId {The HDC server's service ID} \" \"port.arg $defaultPort {The HDC server's port number} \" \"sudo {Use Sudo to gather} \" \"h {Print an elaborate help message} \" " #---------------------------------------------------------------------- # If zero arguments were specified, or if one or more arguments were # bogus (unrecognized), mention it and exit. # # Note that getKnownOptions removes everything it recognizes from argv. # I'm catching getKnownOptions here because if it crashes, it prints a # default usage message that I dislike. #---------------------------------------------------------------------- if {$argv == {}} { puts -nonewline stderr "${scriptName}: ${scriptName} requires at " puts stderr "least one flag\; please run ${scriptName} -h for help." exit 1 } if {[catch {array set arg [::cmdline::getKnownOptions argv $options]}]} { ::Usage exit 1 } if {$argv != {}} { puts -nonewline stderr "${scriptName}: Bogus option \"${argv}\"" puts stderr "\; please run ${scriptName} -h for help." exit 1 } #---------------------------------------------------------------------- # Any options that lack default values must be explicitly set on # the command line. #---------------------------------------------------------------------- set requiredOptions {t s o u p i sudo port h} foreach option $requiredOptions { if {$arg($option) == ""} { puts stderr "${scriptName}: Missing required option: $option" exit 1 } } #---------------------------------------------------------------------- # Print a help message and exit if "-h" was specified. #---------------------------------------------------------------------- if {$arg(h) == 1} {::Usage; exit 1} #---------------------------------------------------------------------- # Copy args to variables with names that make the script easy to read. #---------------------------------------------------------------------- set hdcIP $arg(s) set hdcOperation $arg(o) set targetIP $arg(t) set password $arg(p) set account $arg(u) set serviceId $arg(i) set hdcPort $arg(port) if {[regexp ^\[0-9\]+$ $serviceId] == 1} { ;# Handle value short-cuts. set serviceId srv_[format %09d $serviceId] } set passwordBase64 [::base64::encode $password] if {$arg(sudo) == 0} {set useSudo false} else {set useSudo true} #---------------------------------------------------------------------- # Normalize the capitalization of HDC operation names. #---------------------------------------------------------------------- switch -nocase $hdcOperation { Windows {set hdcOperation Windows } AIX {set hdcOperation AIX } HP-UX {set hdcOperation HP-UX } HPUX {set hdcOperation HP-UX } Solaris {set hdcOperation Solaris } Linux {set hdcOperation Linux } GetVersion {set hdcOperation GetVersion } GetResult {set hdcOperation GetResult } GetStatus {set hdcOperation GetStatus } } #---------------------------------------------------------------------- # Associate the http and tls package functions for https connections. #---------------------------------------------------------------------- ::http::register https $hdcPort ::tls::socket set url "https://${hdcIP}/services/AlpsBrokerService" #---------------------------------------------------------------------- # I found this stuff in an Axis log. The "ns1" tag has to be set # differently for GetResult operations than for all others. #---------------------------------------------------------------------- if {[string match $hdcOperation GetResult]} { set ns1 getProcessResult } else { set ns1 processRequest } set soapPrefix { } append soapPrefix " " append soapPrefix { } set soapSuffix {} #---------------------------------------------------------------------- # These ServiceRequest tags were found in an AXIS log. # # Since the AIX, Solaris, Linux and HP-UX XML is nearly identical, I've # combined them in "unix." #---------------------------------------------------------------------- set getVersion { } set getStatus " " set getResult " " set unix " " append unix { } append unix " " set windows " " append windows { } #---------------------------------------------------------------------- # Choose which ServiceRequest tag to send based on the operation type. #---------------------------------------------------------------------- switch $hdcOperation { Windows {set serviceRequest $windows } AIX {set serviceRequest $unix } Solaris {set serviceRequest $unix } HP-UX {set serviceRequest $unix } Linux {set serviceRequest $unix } GetVersion {set serviceRequest $getVersion} GetStatus {set serviceRequest $getStatus } GetResult {set serviceRequest $getResult } } #---------------------------------------------------------------------- # For any HDC operation other than GetResult, send the POST to HDC, # then print the ServiceResponse tag and exit. #---------------------------------------------------------------------- set query ${soapPrefix}${serviceRequest}${soapSuffix} if {[string match $hdcOperation GetResult] == 0} { if {[catch {set token [::http::geturl $url -query $query \ -headers "SOAPAction {}"]} token]} { puts stderr "${scriptName}: Can't reach ${hdcIP}: $token" exit 1 } set hdcOutput [lindex [array get $token body] 1] regexp () $hdcOutput notUsed \ serviceResponse puts $serviceResponse exit } #---------------------------------------------------------------------- # For the HDC GetResult operation, send the POST to HDC, store the # response in a uniquely named directory, unzip it, and print the XML. #---------------------------------------------------------------------- if {[file exists $zipDir] == 0} { if {[catch [file mkdir $zipDir] error]} { puts stderr "${scriptName}: failed to mkdir ${zipDir}: $error" exit 1 } } set timeStamp [clock format [clock seconds] -format %Y%b%d_%H%M] set dirNum 1 while {[file exists ${zipDir}/${env(USER)}_${timeStamp}_${dirNum}]} { incr dirNum } set instanceDir ${zipDir}/${env(USER)}_${timeStamp}_${dirNum} if {[catch [file mkdir $instanceDir] error]} { puts stderr "${scriptName}: failed to mkdir ${instanceDir}: $error" exit 1 } set fileName ${instanceDir}/${serviceId}.zip if {[catch {open $fileName w} fd]} { puts stderr "${scriptName}: Can't create ${fileName}: $fd" exit 1 } if {[catch {set token [::http::geturl $url -query $query -channel $fd \ -headers "SOAPAction {}"]} token]} { puts stderr "${scriptName}: Can't reach ${hdcIP}: $token" exit 1 } catch {close $fd} #---------------------------------------------------------------------- # Since both the text and binary portions of the POST response are # saved in the zip file, the unzip command always has non-fatal errors # while unzipping it. #---------------------------------------------------------------------- catch {exec unzip -d $instanceDir $fileName} if {[catch {open ${instanceDir}/${serviceId}/Filesystem.xml r} fd]} { puts stderr "${scriptName}: Can't open\ ${instanceDir}/${serviceId}/Filesystem.xml: $fd" exit 1 } while {[gets $fd line] != -1} {puts $line} catch {close $fd} exit