# MCxscf.ctl:240: Collects Extended System Control Facility (XSCF) Information # $Id: MCxscf.ctl,v 1.15 2015/08/21 15:40:48 RDA Exp $ # ARCS: $Header: /home/cvs/cvs/RDA_8/src/scripting/lib/collect/EXPLORER/MCxscf.ctl,v 1.15 2015/08/21 15:40:48 RDA Exp $ # # Change History # 20150821 MSC Improve time consistency. =head1 NAME EXPLORER:MCxscf - Collects Extended System Control Facility (XSCF) Information =head1 DESCRIPTION This module collects Extended System Control Facility (XSCF) information. The following reports can be generated and are regrouped under C: =cut use Buffer use Mrc use Remote # Initialization var $VALIDATE = true keep $VALIDATE section begin var $ERR = '---## Associated Errors' var $GRP = 'explorer:xscf' var $TOC = '%TOC%' var $TOP = '[[#Top][Back to top]]' var $WRN = ' * Links point to files that have been collected in their \ original format. Opening them directly in your browser can \ present risks. To prevent them, access the file outside the \ browser or use the link to save them and use an adequate \ viewer.' run EXPLORER:XPLRlib('xscfextended') # Get commands syntax var $PING = check(${RDA.T_OS},\ 'solaris',concat(${CMD.PING:'ping'},' %s'),\ 'linux', concat(${CMD.PING:'ping'},' -c 1 %s'),\ 'cygwin', concat(${CMD.PING:'ping'},' %s 64 1')) var $SU = concat(${CMD.SU:'su'},' - "%s"') #------------------------------------------------------------------------------ # XPLR_xscf section #------------------------------------------------------------------------------ section XPLR_xscf # Validate the execution context if !${B_GLOBAL:true} return call log_run('Processing XSCF sections ...') pretoc '2:Extended System Control Facility (XSCF)' # Define a macro to parse .explorer file macro parse_explorer {var ($buf,$dat) = @arg var ($hst,$usr) = split('\|',$dat,2) import %ARC keep %ARC var $sct = undef loop $lin ($buf->grep('^\s*($|#)','v')) {if match($lin,'^\s*\[') var ($sct) = match($lin,'^\s*\[XSCF:(\w[\w\-\.]*)\]') elsif ?$sct {if match($lin,'^\s*(CLN|DIR|HST|KEY|TYP|USR)\s*=\s*"(.*)"',true) {var ($key,$val) = last var $ARC{$hst,$usr,$sct,lc($key)} = $val } } } } # Define a macro to obtain and set archive host public key macro set_pub {var ($buf,$hst) = @arg import %PUB keep %PUB if $buf->grep('^\s*($|#)','vf') {var ($typ,$sig) = split('\s+',last,3) var $PUB{$hst} = concat($typ,' ',$sig) } } =head2 Extended System Control Facility (XSCF) Commands Connects through F or SSH to the specified user on the archive host to retrieve snapshot archival context from the F<${HOME}/.explorer> file. You should create that file in order to collect a snapshot. Since other XSCF or SP units can use the same archival user, each of them has a specific section in the F<${HOME}/.explorer> file. A typical section looks like this: [XSCF:m3000_103] CLN="FILE" DIR="xscfsnap" HST="xxx.xxx.xxx.xxx" KEY="m_103" TYP="SNP" USR="explo" For a XSCF section, we have: =over 2 =item o A section header C<[XSCF:name_of_section]> regroups a set of keywords and their values to describe a specific archival context. The section name must start with a word, which is composed of letters, digits, and underscores, possibly followed by letters, digits, underscores, dashes, and periods. =for stopwords hostname =item o C specifies the XSCF host. When a hostname[.domain] is used, the XSCF must be able to resolve it. An IP address is an alternative. =item o C specifies the XSCF user, used to take the snapshot. =item o C specifies the snapshot archival strategy. It supports the following ones: =over 2 =item o C: Log archival (default) =item o C: Snapshot archival =back =item o C indicates the snapshot directory. A relative path is taken from the user home directory. Its full path cannot contain single or double quotation marks. The snapshot directory should be owned by the archival user and its permissions should be 700. =item o C specifies the cleanup strategy. It supports the following strategies: =over 2 =item o C: Removes all files from destination directory. =item o C: Removes the snapshot file collected by Oracle Explorer. (default) =item o C: Disables any cleanup. =item o C: Removes all files from the destination directory, with a name matching the indicated pattern. For example, CLN="PAT:*.zip" =back =item o C specifies an optional identification key, which can be used to indicate that multiple entries are using the same password. =back Once it has retrieved the snapshot context, this module gathers the following Extended System Control Facility (XSCF) commands through SSH: =over 2 =item o C =item o C =back Using snapshot archival strategy (C) requires a working Java environment. ${HOST} represents the archive host. ${DIR} represents the location where the snapshot file will be placed in the archive host. ${KEY} represents the archive host public key. ${USER} represents the user to connect to the archive host. =cut var (%ARC,%DSC,%DUP,%PUB) = () # Treat all requests loop $set (@{MOD.XSCF.N_SET}) {var $nod = ${MOD.XSCF.T_HOST_${VAR.set}} next !?$nod # Validate the input parameters var ($a_f,$a_s,$snp) = (false) var $sct = ${MOD.XSCF.T_SECTION_${VAR.set}} if !match($sct,'^\w[\w\-\.]*$') next log_info(concat('Bad section name "',$sct,'".')) var $val = ${MOD.XSCF.T_USER_${VAR.set}} if !?$usr = isUser($val,true) next log_info(concat('Bad archive user name "',$val,'".')) if compare('eq',$nod,'-') var $hst = ${RDA.T_HOST} else {debug ' Inside XSCF collection, validating ',$nod,' access' if !?$hst = isHost($nod,true) next log_info(concat('Bad archive host name or IP "',$nod,'".')) call command(sprintf($PING,$hst)) if status() next log_info(concat('Host ',$hst,' is not reachable.')) var $a_s = addRemoteSession('ARC',$hst,$usr) if and($a_s->set_type('da'),$a_s->set_type('jsch')) {if $a_s->set_type('ssh') next log_info(concat('Cannot create a session to host ',$hst)) var $a_f = true } # Make sure SSH agent is running if !$a_s->has_agent call $a_s->set_agent # Ask for the password when necessary if and($a_s->need_password,\ not(hasPassword('host',$hst,$usr))) call setPassword('host',$hst,$usr,askPassword(concat('Enter ',$usr,\ ' password for Archive host ',$hst,': '),'')) } # Create temporary file to be used to store outputs debug ' Inside XSCF collection, obtaining information from ',$hst var $res = getTemp(concat('TMP',$hst)) # Obtain archive host information when necessary if missing($ARC{$hst,$usr,$sct}) {set $cod {if [ -x '/bin/uname' ] "then " OSN=`/bin/uname -s` "elif [ -x '/usr/bin/uname' ] "then " OSN=`/usr/bin/uname -s` "else " OSN='other' "fi "case "${OSN}" in " CYGWIN*) CMD_CAT='/bin/cat' " CMD_EGREP='/bin/egrep' " CMD_FIND='/bin/find' " CMD_GREP='/bin/grep' " CMD_LS='/bin/ls' " CMD_MKDIR='/bin/mkdir' " CMD_RM='/bin/rm' " CMD_SSH_KEYGEN='/bin/ssh-keygen' " ;; " Linux*) CMD_CAT='/bin/cat' " CMD_EGREP='/bin/egrep' " CMD_FIND='/usr/bin/find' " CMD_GREP='/bin/grep' " CMD_LS='/bin/ls' " CMD_MKDIR='/bin/mkdir' " CMD_RM='/bin/rm' " CMD_SSH_KEYGEN='/usr/bin/ssh-keygen' " ;; " SunOS*) CMD_CAT='/usr/bin/cat' " CMD_EGREP='/usr/bin/egrep' " CMD_FIND='/usr/bin/find' " CMD_GREP='/usr/bin/grep' " CMD_LS='/usr/bin/ls' " CMD_MKDIR='/usr/bin/mkdir' " CMD_RM='/usr/bin/rm' " CMD_SSH_KEYGEN='/usr/bin/ssh-keygen' " ;; " *) CMD_CAT='/bin/cat' " CMD_EGREP='/bin/egrep' " CMD_FIND='/usr/bin/find' " CMD_GREP='/bin/grep' " CMD_LS='/bin/ls' " CMD_MKDIR='/bin/mkdir' " CMD_RM='/bin/rm' " CMD_SSH_KEYGEN='/usr/bin/ssh-keygen' " ;; "esac " "echo "---# RDA:SET VARIABLE:XSCF:HOME=\"${HOME}\"" "echo "---# RDA:SET VARIABLE:XSCF:CMD_CAT=\"${CMD_CAT}\"" "echo "---# RDA:SET VARIABLE:XSCF:CMD_EGREP=\"${CMD_EGREP}\"" "echo "---# RDA:SET VARIABLE:XSCF:CMD_FIND=\"${CMD_FIND}\"" "echo "---# RDA:SET VARIABLE:XSCF:CMD_GREP=\"${CMD_GREP}\"" "echo "---# RDA:SET VARIABLE:XSCF:CMD_LS=\"${CMD_LS}\"" "echo "---# RDA:SET VARIABLE:XSCF:CMD_MKDIR=\"${CMD_MKDIR}\"" "echo "---# RDA:SET VARIABLE:XSCF:CMD_RM=\"${CMD_RM}\"" " "if [ -r '/etc/ssh/ssh_host_rsa_key.pub' ] "then " FIL='/etc/ssh/ssh_host_rsa_key.pub' "elif [ -r '/etc/ssh2/hostkey.pub' ] "then " FIL='/etc/ssh2/hostkey.pub' "else " FIL='' "fi "if [ -n "${FIL}" ] "then " echo '---# RDA:BEGIN' " if "${CMD_GREP}" 'BEGIN SSH2 PUBLIC KEY' "${FIL}" >/dev/null 2>&1 " then " "${CMD_SSH_KEYGEN}" -i -f "${FIL}" " else " "${CMD_CAT}" "${FIL}" " fi " echo '---# RDA:END MACRO set_pub::1' "fi "FIL="${HOME}/.explorer" "if [ ! -f "${FIL}" ] "then " echo '---# RDA:BEGIN CAPTURE:TEST' " echo 'NO_EXPLORER' " echo '---# RDA:END CAPTURE' "elif ! [ -O "${FIL}" ] "then " echo '---# RDA:BEGIN CAPTURE:TEST' " echo 'OWNER_ERROR' " echo '---# RDA:END CAPTURE' "elif "${CMD_LS}" -ldn "${FIL}" 2>/dev/null | \ "${CMD_EGREP}" '^-r[-w]-------' >/dev/null 2>&1 "then " echo '---# RDA:BEGIN CAPTURE:TEST' " echo 'CORRECT' " echo '---# RDA:END CAPTURE' " echo '---# RDA:BEGIN' " "${CMD_CAT}" "${FIL}" " echo '---# RDA:END MACRO parse_explorer::1|:2' "else " echo '---# RDA:BEGIN CAPTURE:TEST' " echo 'PERMISSIONS_ERROR' " echo '---# RDA:END CAPTURE' "fi } var $cod = bind($cod,$hst,$usr) # Provide step information as password may be requested by SSH if $a_f call log_critical(concat('Obtaining information from ',$hst)) # Run the code if !?$a_s {output | concat(sprintf($SU,$usr),'>',quote($res)) write $cod close } else call rcollect('ARC',$cod,$res) # Analyze the results call writeRemoteResult($res,'ARC') var $DSC{$hst,$usr} = {getRemoteGroup('XSCF')} # Verify home directory for the archive user was found if missing($DSC{$hst,$usr,'HOME'}) next log_info(concat('Unable to find home directory for archive user ',$usr)) # Verify that .explorer file exists var $buf = getRemoteBuffer('TEST',true) if !$buf->grep('^CORRECT$') {var $fil = catFile($DSC{$hst,$usr,'HOME'},'.explorer') if $buf->grep('^OWNER_ERROR') next log_info(concat('The ',$fil,' file is not owned by user ',$usr)) if $buf->grep('^PERMISSIONS_ERROR') next log_info(concat('Access to the ',$fil,\ ' file is not restricted to its owner')) next log_info(concat('Unable to find a valid ',$fil,' file at archive host')) } call $buf->close # Verify .explorer file was successfully parsed if !?$rec = $ARC{$hst,$usr,$sct} next log_info($ARC{$hst,$usr,$sct} = \ concat('Unable to obtain information on ',$sct,' from ',\ catFile($DSC{$hst,$usr,'HOME'},'.explorer'))) } elsif !ref($rec = $ARC{$hst,$usr,$sct}) next log_info($rec) # Obtain section information for later use var $dsc = $DSC{$hst,$usr} var ($cln,$dir,$key,$typ,$v_h,$v_u) = ($rec->{'cln'},\ $rec->{'dir'},\ $rec->{'key'},\ $rec->{'typ'},\ $rec->{'hst'},\ $rec->{'usr'}) var $pub = nvl($PUB{$hst},'NONE') var $hom = $DSC{$hst,$usr,'HOME'} # Reject a duplicate request if ?$DUP{$v_h} next log_info(concat('Already tried snapshot collection from XSCF ',$v_h)) var $DUP{$v_h} = true # Ensure archive directory fullfils the requirements debug ' Inside XSCF collection, validating required setup at ',$hst if !isAbsolute($dir = nvl($rec->{'dir'},catDir($hom,'xscf_snapshot'))) var $dir = catDir($hom,$dir) if match($dir,'[\042\047]') next log_info(concat('The ',$dir,\ ' directory contains unsupported characters')) set $cod {if ! [ -e ':1' ] "then " "${CMD_MKDIR}" -m 700 -p ':1' && echo 'CREATED' "elif ! [ -O ':1' ] "then " echo 'OWNER_ERROR' "elif "${CMD_LS}" -ldn ':1' 2>/dev/null | \ "${CMD_EGREP}" '^drwx------' >/dev/null 2>&1 "then " echo 'CORRECT' "else " echo 'DIRECTORY_ERROR' "fi } var $cod = bind($cod,$dir) # Provide step information as password may be requested by SSH if $a_f call log_critical(concat('Validating required setup at ',$hst)) # Run the code if ?$a_s call rcollect('ARC',$cod,$res,{CMD_EGREP => $dsc->{'CMD_EGREP'},\ CMD_LS => $dsc->{'CMD_LS'},\ CMD_MKDIR => $dsc->{'CMD_MKDIR'}}) else {output | concat(sprintf($SU,$usr),'>',quote($res)) write 'CMD_EGREP="',$dsc->{'CMD_EGREP'},'"' write 'CMD_LS="', $dsc->{'CMD_LS'},'"' write 'CMD_MKDIR="',$dsc->{'CMD_MKDIR'},'"' write $cod close } # Verify required archive directory exists and has the correct permissions if !grepFile($res,'^(CORRECT|CREATED)$') {if grepFile($res,'^OWNER_ERROR') next log_info(concat('Archive directory ',$dir,\ ' is not owned by user ',$usr)) elsif grepFile($res,'^DIRECTORY_ERROR') next log_info(concat($dir,' is not a valid or access-restricted archive \ directory')) next log_info(concat('Missing directory ',$dir)) } # Connect to the service controller if !?$v_h next log_info('Missing XSCF host name') if !?$v_u next log_info('Missing XSCF user name') if !?$x_h = isHost($v_h,true) next log_info(concat('Bad XSCF host name or IP "',$v_h,'".')) if !?$x_u = isUser($v_u,true) next log_info(concat('Bad XSCF user name "',$v_u,'".')) debug ' Inside XSCF collection, validating ',$x_h,' access' call command(sprintf($PING,$x_h)) if status() next log_info(concat('Host ',$x_h,' is not reachable.')) debug ' Inside XSCF collection, gathering ',$x_h,' information (can take time)' call log_critical(concat('Collecting snapshot from ',$x_h,' (can take time)')) var ($x_f,$x_s) = (false,addRemoteSession('XSCF',$x_h,$x_u)) if and($x_s->set_type('da'),$x_s->set_type('jsch')) {if $x_s->set_type('ssh') next log_info(concat('Cannot create a session with host ',$x_h)) var $x_f = true } # Request password when needed if $x_s->need_password {# Share key password if ?$key call samePassword($key,'host',$GRP,[$x_h,$x_u]) # Request missing password if !hasPassword('host',$x_h,$x_u) call setPassword('host',$x_h,$x_u,\ askPassword(concat('Enter ',$x_u,' password for XSCF ',$x_h,': '),'')) } # Login to the service controller when needed if !$x_f {if !$x_s->open next log_warning($x_s->get_message) if !?$x_s->login($x_u,{dis=>'exit',\ pat=>'m/>[\x20]?$/'}) next log_warning($x_s->get_message) } # Run the snapshot command if compare('ne',$typ,'SNP') {var $cmd = concat('snapshot -T -D ',quote($dir),' -L F -k ',quote($pub)) if $x_f {call $x_s->command({cmd => $cmd,\ max => 600},\ true) var $buf = $x_s->get_input } else {var $buf = new('Buffer','S') call $buf->set_handle('eol',false) call $x_s->collect($buf,{\ cln => true,\ cmd => $cmd,\ max => 600,\ pat => 'm/>[\x20]?$/',\ skp => true}) } } elsif $x_f next log_error(concat('Unable to run snapshot at ',$x_h)) else {var $cmd = \ concat('snapshot -t ',quote(concat($usr,'@',$hst,':',$dir)),' -L F -k ',\ quote($pub)) var $buf = new('Buffer','S') call $buf->set_handle('eol',false) call $x_s->collect($buf,{\ awp => ["%s\012",'host',$hst,$usr,\ concat('Enter ',$usr,' password for archive host ',$hst,': '),''],\ cln => true,\ cmd => $cmd,\ max => 600,\ nxt => 'm/enter\s+.*password\s+.*:\s*$/i',\ pat => 'm/>[\x20]?$/',\ skp => true}) } # Close the connection call $x_s->close # Genererate the collected command report pretoc '3:',$x_h,' Information' report concat('xscf_',$x_h,'_cmd') title '---+!! Extended System Control Facility (XSCF)' title '---## ',$x_h,' Commands' title $TOC call do_exec(\ {cmd => 'BUFFER',\ buf => $buf,\ det => $cmd,\ nam => join('/','xscf',$x_h,'snapshot.out'),\ ttl => '---++ Snapshot Execution Output'}) if isCreated(true) toc '4:[[',getFile(),'][rda_report][Snapshot Execution]]' =head2 Extended System Control Facility (XSCF) Files Produces an overview report of the collected snapshot files. =cut debug ' Inside XSCF collection, obtaining snapshot file from ',$hst if !$buf->grep('^data collection complete','i') call log_error(concat('Snapshot not received from ',$x_h)) elsif !$buf->grep(concat(verbatim($dir),'\/([\w\.\-\_]+\.zip)'),'f1') call log_error(concat('Snapshot not received from ',$x_h)) else {var ($snp) = last var $tmp = createTemp('TMP') if !?$a_s {output | concat(sprintf($SU,$usr),' >',quote($tmp)) write 'CMD_CAT="',$dsc->{'CMD_CAT'},'"' write "cd \042",$dir,"\042 && \042$\173CMD_CAT\175\042 \042",$snp,"\042" close } else call $a_s->get($dir,$snp,dirname($tmp),basename($tmp)) if getSize($tmp) {# Genererate the collected snapshot file report report concat('xscf_',$x_h,'_fil') prefix {write '---+!! Extended System Control Facility (XSCF)' write '---## ',$x_h,' Files' write $WRN write '|*File Name*| *Size*|*Last Modified Date*|' } call collectData(join('/','xscf',$x_h,$snp),$tmp,\ ['C',concat('XSFC snapshot (',$snp,')')]) write '|[[../',last,'][_blank][',encode($snp),']] | ',getSize($tmp),\ '|',getLastModify($tmp,''),' |' if isCreated(true) {write $TOP toc '4:[[',getFile(),'][rda_report][Snapshot Files]]' } # Cleanup files debug ' Inside XSCF collection, cleaning files from ',$hst if compare('eq',$cln,'ALL') var $pat = '*' elsif compare('eq',$cln,'NONE') var $pat = undef elsif match($cln,'^PAT:([\w\*][\w\*\.\-\_]*)$') var ($pat) = last else var $pat = $snp if ?$pat {set $cod {"${CMD_FIND}" ':1/.' -name . -o -prune -name ':2' -type f \ -exec "${CMD_RM}" -f '{}' \; 2>/dev/null } var $cod = bind($cod,$dir,$pat) # Provide step information when password can be requested by SSH if $a_f call log_critical('Cleaning files from archive directory') # Perform the cleanup if ?$a_s call rcollect('ARC',$cod,$res,{CMD_FIND => $dsc->{'CMD_FIND'},\ CMD_RM => $dsc->{'CMD_RM'}}) else {output | concat(sprintf($SU,$usr),'>',quote($res)) write 'CMD_FIND="',$dsc->{'CMD_FIND'},'"' write 'CMD_RM="', $dsc->{'CMD_RM'},'"' write $cod close } } # Indicate the successful completion call log_critical(concat('Data gathering complete for ',$x_h)) } else call log_error(concat('Empty snapshot received from ',$x_h)) call unlinkTemp('TMP') } call $buf->close # Free the resources if ?$a_s call $a_s->close call unlinkTemp($res) unpretoc } # Adjust the table of content unpretoc #------------------------------------------------------------------------------ # Input file conversion section #------------------------------------------------------------------------------ section input # Define the input file parser macro macro parse_input {var ($fil,$flg) = @arg import $GRP keep $GRP var @sta = getStat($fil) if !expr('&',$sta[2],077) {# Parse the input file var ($set,@set) = (0) loop $lin (grepFile($fil,'^\s*#','v')) {if match($lin,'^\s*A\s+') {var (undef,$hst,$usr,$sct,$pwd) = split('\s+',trim($lin),5) if !compare('eq',$hst,'-') next !?$hst = isHost($hst,true) next !?$usr = isUser($usr,true) next !match($sct,'^\w[\w\-\.]*$') call push(@set,incr($set)) var ${RUN.EXPLORER.XPLR.XSCF.T_HOST_${VAR.set}} = $hst var ${RUN.EXPLORER.XPLR.XSCF.T_USER_${VAR.set}} = $usr var ${RUN.EXPLORER.XPLR.XSCF.T_SECTION_${VAR.set}} = $sct # Save archive host password if ?$pwd call setPassword('host',cond(compare('eq',$hst,'-'),${RDA.T_HOST},$hst),\ $usr,$pwd) } elsif match($lin,'^\s*T\s+') {var (undef,$usr,$pwd) = split('\s+',trim($lin),3) # Save XSCF key password if ?$pwd call setPassword('host',$GRP,$usr,$pwd) } elsif match($lin,'^\s*X\s+') {var (undef,$hst,$usr,$pwd) = split('\s+',trim($lin),4) # Save XSCF host password if ?$pwd call setPassword('host',$hst,$usr,$pwd) } } # Save the parsing results if $set {var ${RUN.EXPLORER.XPLR.XSCF.F_CFG} = $fil var ${RUN.EXPLORER.XPLR.XSCF.N_SET} = [@set] var ${RUN.EXPLORER.B_USE_XSCF} = true } else var ${RUN.EXPLORER.B_USE_XSCF} = $flg } } # Parse the input file if and(defined($fil = ${ENV.EXP_XSCFINPUT_CONFIG}),\ defined(testFile('frs',catFile($fil)))) call parse_input(lastTestFile(),true) elsif ?testFile('frs',catFile(${RUN.EXPLORER.D_ETC},'xscfinput.txt')) call parse_input(lastTestFile(),false) =head1 SEE ALSO L, L =head1 COPYRIGHT NOTICE Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. =head1 TRADEMARK NOTICE Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. =cut