# Ocm.pm: OCM Command Package package RDA::UI::Ocm; # $Id: Ocm.pm,v 1.8 2015/04/29 13:54:32 RDA Exp $ # ARCS: $Header: /home/cvs/cvs/RDA_8/src/scripting/lib/RDA/UI/Ocm.pm,v 1.8 2015/04/29 13:54:32 RDA Exp $ # # Change History # 20150424 MSC Introduce the control agent concept. =head1 NAME RDA::UI::Ocm - OCM Command Package =head1 SYNOPSIS -XOcm ... -XOcm ... =head1 DESCRIPTION This user interface interacts with OCM. The commands returns a 0 (zero) exit status when no errors are detected. Otherwise, they return a nonzero exit status. Most commands support the following switch: =over 9 =item B< -t id> Specifies the RDA target name (the first relevant RDA target by default). =back The following commands are available: =cut use strict; BEGIN { use Exporter; use RDA::Text qw(get_string); use RDA::Agent; use RDA::Object::Message; use RDA::Object::Rda; use RDA::Object::Xml; use RDA::Options; } # Define the global public variables use vars qw($STRINGS $VERSION @ISA); $VERSION = sprintf('%d.%02d', q$Revision: 1.8 $ =~ /(\d+)\.(\d+)/); @ISA = qw(Exporter); # Define the global private constants my $SR = qr/^\d-\d+$/; # Define the global private variables my %tb_clr = ( diagcheck => [qw(disable_diagchecks)], diagchecks => [qw(disable_diagchecks)], target => [qw(disable_target)], targets => [qw(disable_target)], update => [qw(automatic_update off)], updates => [qw(automatic_update off)], ); my %tb_lst = ( collect => 'R', configuration => 'C', configurations => 'C', installation => 'I', installations => 'I', target => 'T', targets => 'T', ); my %tb_set = ( diagcheck => [qw(enable_diagchecks)], diagchecks => [qw(enable_diagchecks)], target => [qw(enable_target)], targets => [qw(enable_target)], update => [qw(automatic_update on)], updates => [qw(automatic_update on)], ); # Report the package version sub Version { return $VERSION; } =head2 S In the connected mode, this command clears diagnostic uploads. It supports additional command switches: =over 11 =item B< -c> Clears only completed uploads. =item B< -f> Clears uploads even if there are errors. =item B< -p path> Clears a particular upload. =item B< -s SR> Clears all uploads for the specified service request. =back =cut sub clear { my ($agt, @arg) = @_; my ($arg, $opt, @opt); $opt = RDA::Options::getopts('cfp:s:', \@arg); $arg = '-diagnostic'; if ($opt->{'s'}) { get_string('BAD_SR', $opt->{'s'}) unless $opt->{'s'} =~ $SR; $arg .= '=SR='.$opt->{'s'}; $arg .= ',FILE='.RDA::Object::Rda->quote($opt->{'p'}) if $opt->{'p'}; } push(@opt, $arg); push(@opt, '-complete') if $opt->{'c'}; push(@opt, '-force') if $opt->{'f'}; return &exec($agt, 'clear', @opt); ## no critic (Ampersand) } =head2 S This command performs an OCM collection. It supports an additional command switch: =over 11 =item B< -a text> Specifies an annotation string. =back =cut sub collect { my ($agt, @arg) = @_; my ($opt, @opt); $opt = RDA::Options::getopts('a:t:', \@arg); push(@opt, '-annotation='.$opt->{'a'}) if $opt->{'a'}; return _exec($agt, $opt->{'t'}, @opt, 'collect'); } =for stopwords diagchecks =head2 S In the connected mode, this command disables some functionality. It supports the following arguments: =over 14 =item B< diagchecks> Disables all diagnostic checks collections. =item B< targets> Disables the collection of configuration information for targets discovered by the Oracle Configuration Manager. =item B< updates> Disables the automatic retrieval of new software updates. =back =cut sub disable { my ($agt, @arg) = @_; my ($opt, $typ); $opt = RDA::Options::getopts('t:', \@arg); die get_string('BAD_FLAG') unless defined($typ = shift(@arg)) && exists($tb_clr{$typ}); return _exec($agt, $opt->{'t'}, @{$tb_clr{$typ}}); } =head2 S In the connected mode, this command enables some functionality. It supports the following arguments: =over 14 =item B< diagchecks> Enables all diagnostic checks collections. =item B< targets> Enables the collection of configuration information for targets discovered by the Oracle Configuration Manager. =item B< updates> Enables the automatic retrieval of new software updates. =back =cut sub enable { my ($agt, @arg) = @_; my ($opt, $typ); $opt = RDA::Options::getopts('t:', \@arg); die get_string('BAD_FLAG') unless defined($typ = shift(@arg)) && exists($tb_set{$typ}); return _exec($agt, $opt->{'t'}, @{$tb_set{$typ}}); } =for stopwords getupdates =head2 S In the connected mode, this command retrieves any new software updates from the content server and deploys the updates. It supports an additional command switch: =over 11 =item B< -a text> Specifies an annotation string. =back =cut sub getupdates { my ($agt, @arg) = @_; my ($opt, @opt); $opt = RDA::Options::getopts('a:t:', \@arg); push(@opt, '-annotation='.$opt->{'a'}) if $opt->{'a'}; return _exec($agt, $opt->{'t'}, @opt, 'getupdates'); } =head2 S This command displays the command syntax and the related explanations. =cut sub help { return shift->submit(q{.}, 'DISPLAY.DSP_POD', package => __PACKAGE__); } =head2 S In the connected mode, this command sets the OCM status to C. OCM will not collect or upload. =head2 S This command lists the OCM information. You can restrict the list by specifying the following switches: =over 6 =item B< -C> Lists the defined configured configurations in the F directory. =item B< -I> Lists the RDA targets where OCM is installed. =item B< -R> Lists the relevant RDA targets. =item B< -T> Lists the identified targets in the OCM configuration. =back or the following keywords: =over 18 =item B< collect> Lists the relevant RDA targets. =item B< configurations> Lists the defined configured configurations in the F directory. =item B< installations> Lists the RDA targets where OCM is installed. =item B< targets> Lists the identified targets in the OCM configuration. =back =cut sub list { my ($agt, @arg) = @_; my ($buf, $nam, $opt, $sep, $tbl, $tgt); # Determine the list types $opt = RDA::Options::getopts('CIRTt:', \@arg); foreach my $typ (@arg) { $typ = lc($typ); die get_string('BAD_LIST', $typ) unless exists($tb_lst{$typ}); $opt->{$tb_lst{$typ}} = 1; } # Get the OCM target $tbl = _get_ocm($agt, 'D_CCR_CONFIG'); if (exists($opt->{'t'})) { $nam = $opt->{'t'}; die get_string('BAD_COLLECTOR', $nam) unless exists($tbl->{$nam}); } else { ($nam) = sort keys(%{$tbl}); die get_string('NO_COLLECTOR') unless defined($nam); } $tgt = $tbl->{$nam}; # Produce requested lists $buf = q{}; $sep = ".N 1\n"; $buf .= _list_ccr($agt, $buf ? $sep : q{}) if exists($opt->{'I'}); $buf .= _list_rda($agt, $tbl, $buf ? $sep : q{}) if exists($opt->{'R'}); $buf .= _list_cfg($agt, $tgt, $buf ? $sep : q{}) if exists($opt->{'C'}); $buf .= _list_tgt($agt, $tgt, $buf ? $sep : q{}) if exists($opt->{'T'}); # Produce default lists unless ($buf) { $buf .= _list_cfg($agt, $tgt, $buf ? $sep : q{}); $buf .= _list_tgt($agt, $tgt, $buf ? $sep : q{}); } # Display the report and indicate a successful completion return $agt->submit(q{.}, RDA::Object::Message->new('DISPLAY.DSP_REPORT', page => 1)->add_data($buf)); } sub _list_ccr { my ($agt, $sep) = @_; my ($buf, $tbl); $buf = q{}; $tbl = _get_ocm($agt, 'D_CCR_HOME'); return ($buf = join(qq{\n}, map {$_.q{|}.$tbl->{$_}->get_first('T_TITLE')} sort keys(%{$tbl}))) ? $sep.q{.M 2 '}.get_string('Installations').qq{'\n}.$buf.qq{\n\n} : $sep.qq{.P\n}.get_string('NoInstallations').qq{\n\n}; } sub _list_cfg { my ($agt, $tgt, $sep) = @_; my ($buf, $dir); $buf = q{}; $dir = RDA::Object::Rda->cat_dir(_get_home($tgt), 'hosts'); if (opendir(OCM, $dir)) { foreach my $fil (readdir(OCM)) { next unless $fil !~ m/^\./ ## no critic (Unless) && -d RDA::Object::Rda->cat_dir($dir, $fil, 'config'); $buf .= $sep.q{.T'}.get_string('Configurations').qq{'\n} unless $buf; $buf .= sprintf(qq{.I' '\n%s\n\n}, RDA::Object::Rda->cat_dir($dir, $fil)); } closedir(OCM); } return $buf || $sep.qq{.P\n}.get_string('NoConfigurations').qq{\n\n}; } sub _list_rda { my ($agt, $tbl, $sep) = @_; my ($buf); $buf = q{}; return ($buf = join(qq{\n}, map {$_.q{|}.$tbl->{$_}->get_first('T_TITLE')} sort keys(%{$tbl}))) ? $sep.q{.M 2 '}.get_string('RdaTargets').qq{'\n}.$buf.qq{\n\n} : $sep.qq{.P\n}.get_string('NoRdaTargets').qq{\n\n}; } sub _list_tgt { my ($agt, $tgt, $sep) = @_; my ($buf, $tbl); $tbl = _get_targets($tgt); return ($buf = join(qq{\n}, map {$_.q{|}.$tbl->{$_}->{'file'}} sort keys(%{$tbl}))) ? $sep.q{.M 2 '}.get_string('OcmTargets')."'\n".$buf.qq{\n\n} : $sep.qq{.P\n}.get_string('NoOcmTargets').qq{\n\n}; } =head2 S In the connected mode, this command registers OCM. =head2 S In the connected mode, this command takes OCM off the C status and resumes collections and uploads. =head2 S In the connected mode, this command starts the OCM collector scheduler. =head2 S This command reports the status of the collector. =head2 S This command reports the status of the diagnostic uploads. You can restrict to a particular service request. =over 11 =item B< -p path> Specifies the full path to the diagnostic file. =item B< -s SR> Specifies the service request. =back =cut sub status { my ($agt, @arg) = @_; my ($arg, $opt, $typ, @opt); $opt = RDA::Options::getopts('p:s:t:', \@arg); if (defined($typ = shift(@arg)) && $typ ne 'collect') { die get_string('BAD_STATUS', $typ) unless $typ eq 'diagnostic'; $arg = '-diagnostic'; if ($opt->{'s'}) { get_string('BAD_SR', $opt->{'s'}) unless $opt->{'s'} =~ $SR; $arg .= '=SR='.$opt->{'s'}; $arg .= ',FILE='.RDA::Object::Rda->quote($opt->{'p'}) if $opt->{'p'}; } push(@opt, $arg); } return _exec($agt, $opt->{'t'}, 'status', @opt); } =head2 S In the connected mode, this command stops the OCM collector scheduler. =head2 S In the connected mode, this command tests the connection to the repository. It supports additional command switches: =over 6 =item B< -r> Registers the client during the test. =item B< -v> Displays detailed information about the connection process. =back =cut sub test { my ($agt, @arg) = @_; my ($opt, @opt); $opt = RDA::Options::getopts('t:v', \@arg); push(@opt, '-register') if $opt->{'r'}; push(@opt, '-verbose') if $opt->{'v'}; return _exec($agt, $opt->{'t'}, @opt, 'test'); } =head2 S This command updates OCM components. It supports additional command switches: =over 11 =item B< -d dir> Indicates the directory containing the OCM packages. =item B< -k path> Provides the OCM installation kit path. =item B< -q> Specifies the silent mode. =back =cut sub update { my ($agt, @arg) = @_; my ($opt, @opt); $opt = RDA::Options::getopts('d:k:qt:', \@arg); push(@opt, '-quiet') if $opt->{'q'}; return _exec($agt, $opt->{'t'}, 'update_components', @opt, '-staged_dir='.$opt->{'d'}) if $opt->{'d'}; return _exec($agt, $opt->{'t'}, 'update_components', @opt, '-distribution='.$opt->{'k'}) if $opt->{'k'}; die get_string('BAD_UPDATE'); } =head2 S In the connected mode, this command uploads the results of an OCM collection. It supports an additional command switch: =over 11 =item B< -a text> Specified an annotation string. =back =head2 S In the connected mode, this command uploads the results of an OCM collection. It supports additional command switches: =over 11 =item B< -f> Restarts the upload for a particular service request. =item B< -p path> Specifies the full path to the diagnostic file. =item B< -r> Continues the upload for a particular service request. =item B< -s SR> Specifies the service request. =back =cut sub upload { my ($agt, @arg) = @_; my ($arg, $opt, $typ, @cmd); $opt = RDA::Options::getopts('a:fp:rs:t:', \@arg); @cmd = ('upload'); if (!defined($typ = shift(@arg)) || $typ eq 'collect') { unshift(@cmd, '-annotation='.$opt->{'a'}) if $opt->{'a'}; } else { die get_string('BAD_UPLOAD', $typ) unless $typ eq 'diagnostic'; $arg = '-diagnostic'; if ($opt->{'s'}) { die get_string('BAD_SR', $opt->{'s'}) unless $opt->{'s'} =~ $SR; $arg .= '=SR='.$opt->{'s'}; $arg .= ',FILE='.RDA::Object::Rda->quote($opt->{'p'}) if $opt->{'p'}; } push(@cmd, $arg); if ($opt->{'r'}) { push(@cmd, '-restart'); } elsif ($opt->{'f'}) { push(@cmd, '-force'); } } return _exec($agt, $opt->{'t'}, @cmd); } # --- Command execution routines ---------------------------------------------- sub exec ## no critic (Builtin) { my ($agt, $cmd, @arg) = @_; my ($opt); # Get the RDA target $opt = RDA::Options::getopts('t:', \@arg); # Process the request return _exec($agt, $opt->{'t'}, $cmd, @arg); } sub _exec { my ($agt, $nam, @arg) = @_; my ($tbl, $tgt); # Get the OCM target $tbl = _get_ocm($agt, 'D_CCR_CONFIG'); if (defined($nam)) { die get_string('BAD_COLLECTOR', $nam) unless exists($tbl->{$nam}); } else { ($nam) = sort keys(%{$tbl}); die get_string('NO_COLLECTOR') unless defined($nam); } $tgt = $tbl->{$nam}; # Process the request return system(_get_command($tgt), @arg) >> 8; } # Return the path of the OCM command sub _get_command { return RDA::Object::Rda->cat_file(shift->get_first('D_CCR_HOME'), 'bin', RDA::Object::Rda->as_bat('emCCR', 1)), } # Return the OCM software home sub _get_home { return shift->get_first('D_CCR_HOME'); } # Return the OCM-related targets sub _get_ocm { my ($agt, $key) = @_; my ($def, $tbl); $def = $agt->get_collector->find('TARGET', 1); $tbl = {}; foreach my $tgt ($def->grep(q{^}.$key.q{$}, 'or')) { $tbl->{$1} = $def->find($tgt) if $tgt =~ m/(\w+)$/; } return $tbl; } # Return the target mapping as a hash reference sub _get_targets { my ($slf) = @_; my ($tbl, $xml); $tbl = {}; $xml = RDA::Object::Xml->new()->parse_file(RDA::Object::Rda->cat_file( $slf->get_first('D_CCR_CONFIG'), 'state', 'review', 'targetMap.xml')); foreach my $itm ($xml->find('.../Collection')) { $tbl->{$itm->get_value('name')} = { file => $itm->get_value('file'), timestamp => $itm->get_value('collection_timestamp'), }; } return $tbl; } 1; __END__ =head1 SEE ALSO L, L, L, L, L, L, L, L, 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