diff --git a/makermcrpm b/makermcrpm new file mode 100755 index 000000000..312799e11 --- /dev/null +++ b/makermcrpm @@ -0,0 +1,33 @@ +#!/bin/ksh +OSNAME=$(uname) +version='2.0' + +if [ "$OSNAME" = "AIX" ] +then + echo '.svn' > /tmp/xcat-excludes + tar -X /tmp/xcat-excludes -cvf /opt/freeware/src/packages/SOURCES/xCAT-rmc.tar xCAT-rmc + gzip /opt/freeware/src/packages/SOURCES/xCAT-rmc.tar + cd ./xCAT-rmc + rm -f /opt/freeware/src/packages/SRPMS/xCAT-rmc*rpm /opt/freeware/src/packages/RPMS/ppc/xCAT-rmc*rpm + rpm -ba xCAT-rmc.spec + #rpm -Uvh /opt/freeware/src/packages/RPMS/ppc/xCAT-rmc*rpm + +else + if [ -f /etc/redhat-release ] + then + pkg="redhat" + else + pkg="packages" + fi + source=$PWD + + # Trying to avoid having the version # (2.0) on the xCAT-rmc dir name in svn + set -x + cd /usr/src/$pkg/SOURCES + rm -f xCAT-rmc-$version; ln -s $source/xCAT-rmc xCAT-rmc-$version # have to make tar think it is in xCAT-rmc-2.0 + rm -f xCAT-rmc-$version.tar.gz + tar -czhf xCAT-rmc-$version.tar.gz --exclude=.svn --exclude=.project xCAT-rmc-$version + rm -f /usr/src/$pkg/SRPMS/xCAT-rmc-$version*rpm /usr/src/$pkg/RPMS/noarch/xCAT-rmc-$version*rpm + rpmbuild -ta xCAT-rmc-$version.tar.gz + #rpm -Uvh /usr/src/$pkg/RPMS/noarch/xCAT-rmc-$version*rpm +fi diff --git a/xCAT-rmc/plugin/rmcmon.pm b/xCAT-rmc/plugin/rmcmon.pm new file mode 100644 index 000000000..a3fc6efc0 --- /dev/null +++ b/xCAT-rmc/plugin/rmcmon.pm @@ -0,0 +1,356 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +package xCAT_monitoring::rmcmon; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl"; +use xCAT::NodeRange; +use Socket; +use xCAT::Utils; +use xCAT::GlobalDef; + +print "xCAT_monitoring::rmcmon loaded\n"; + +1; +#------------------------------------------------------------------------------- +=head1 xCAT_monitoring:rmcmon +=head2 Package Description + xCAT monitoring plugin package to handle RMC monitoring. +=cut +#------------------------------------------------------------------------------- + +#-------------------------------------------------------------------------------- +=head3 start + This function gets called by the monitorctrl module + when xcatd starts. It starts the daemons and does + necessary startup process for the RMC monitoring. + It also queries the RMC for its currently monitored + nodes which will, in tern, compared with the nodes + in the input parameter. It asks RMC to add or delete + nodes according to the comparison so that the nodes + monitored by RMC are in sync with the nodes currently + in the xCAT cluster. + Arguments: + monservers --A hash reference keyed by the monitoring server nodes + and each value is a ref to an array of [nodes, nodetype] arrays + monitored by the server. So the format is: + {monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...} + Returns: + (return code, message) +=cut +#-------------------------------------------------------------------------------- +sub start { + print "rmcmon::start called\n"; + + $noderef=shift; + if ($noderef =~ /xCAT_monitoring::rmcmon/) { + $noderef=shift; + } + + #TODO: get a list of monservers + nodes and compare them with RMC. remove/add + # if necessary. + + #assume the server is the current node. + #check if rsct is installed and running + if (! -e "/usr/bin/lsrsrc") { + return (1, "RSCT is not is not installed.\n"); + } + my $result=`/usr/bin/lssrc -s ctrmc`; + if ($result !~ /active/) { + #restart rmc daemon + $result=`startsrc -s ctrmc`; + if ($?) { + return (1, "rmc deamon cannot be started\n"); + } + } + + #get a list of managed nodes + $result=`/usr/bin/lsrsrc-api -s IBM.MngNode::::Name`; + chomp($result); + my @rmc_nodes=split(/\n/, $result); + + foreach (keys(%$noderef)) { + my $server=$_; + + my $mon_nodes=$noderef->{$_}; + foreach(@$mon_nodes) { + my $node_pair=$_; + my $node=$node_pair->[0]; + my $nodetype=$node_pair->[1]; + + } + } + + + + #TODO: start condition-response assosciations + + return (0, "started"); +} + + + +#-------------------------------------------------------------------------------- +=head3 stop + This function gets called by the monitorctrl module when + xcatd stops. It stops the monitoring on all nodes, stops + the daemons and does necessary cleanup process for the + RMC monitoring. + Arguments: + none + Returns: + (return code, message) +=cut +#-------------------------------------------------------------------------------- +sub stop { + print "rmcmon::stop called\n"; + + #TODO: stop condition-response associtations. + return (0, "stopped"); +} + + + + +#-------------------------------------------------------------------------------- +=head3 supportNodeStatusMon + This function is called by the monitorctrl module to check + if RMC can help monitoring and returning the node status. + + Arguments: + none + Returns: + 1 +=cut +#-------------------------------------------------------------------------------- +sub supportNodeStatusMon { + print "rmcmon::supportNodeStatusMon called\n"; + return 1; +} + + + +#-------------------------------------------------------------------------------- +=head3 startNodeStatusMon + This function is called by the monitorctrl module to tell + RMC to start monitoring the node status and feed them back + to xCAT. RMC will start setting up the condition/response + to monitor the node status changes. + + Arguments: + monservers --A hash reference keyed by the monitoring server nodes + and each value is a ref to an array of [nodes, nodetype] arrays + monitored by the server. So the format is: + {monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...} + Returns: + (return code, message) + +=cut +#-------------------------------------------------------------------------------- +sub startNodeStatusMon { + print "rmcmon::startNodeStatusMon called\n"; + return (0, "started"); +} + + +#-------------------------------------------------------------------------------- +=head3 stopNodeStatusMon + This function is called by the monitorctrl module to tell + RMC to stop feeding the node status info back to xCAT. It will + stop the condition/response that is monitoring the node status. + + Arguments: + none + Returns: + (return code, message) +=cut +#-------------------------------------------------------------------------------- +sub stopNodeStatusMon { + print "rmcmon::stopNodeStatusMon called\n"; + return (0, "stopped"); +} + + +#-------------------------------------------------------------------------------- +=head3 addNodes + This function gdds the nodes into the RMC cluster. + Arguments: + nodes --nodes to be added. It is a hash reference keyed by the monitoring server + nodes and each value is a ref to an array of [nodes, nodetype] arrays monitored + by the server. So the format is: + {monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...} + verbose -- verbose mode. 1 for yes, 0 for no. + Returns: + none +=cut +#-------------------------------------------------------------------------------- +sub addNodes { + $noderef=shift; + if ($noderef =~ /xCAT_monitoring::rmcmon/) { + $noderef=shift; + } + my $VERBOSE=shift; + + if ($VERBOSE) { print "rmcmon::addNodes called $noderef=$noderef\n"}; + + foreach (keys(%$noderef)) { + my $server=$_; + if ($VERBOSE) { print " monitoring server: $server\n";} + + #check if rsct is installed and running + if (! -e "/usr/bin/lsrsrc") { + print "RSCT is not is not installed.\n"; + next; + } + my $result=`/usr/bin/lssrc -s ctrmc`; + if ($result !~ /active/) { + #restart rmc daemon + $result=`startsrc -s ctrmc`; + if ($?) { + print "rmc deamon cannot be started\n"; + next; + } + } + + #enable remote client connection + `/usr/bin/rmcctrl -p`; + + #get ms node id, hostname, ip etc + #TODO: currently one server which is where xcatd is. later changes to use server for hierachy + my $ms_node_id=`head -n 1 /var/ct/cfg/ct_node_id`; + chomp($ms_node_id); + my $ms_host_name=`hostname`; + chomp($ms_host_name); + my ($ms_name,$ms_aliases,$ms_addrtype,$ms_length,@ms_addrs) = gethostbyname($ms_host_name); + chomp($ms_name); + + my $ms_ipaddresses="{"; + foreach (@ms_addrs) { + $ms_ipaddresses .= '"' .inet_ntoa($_) . '",'; + } + chop($ms_ipaddresses); + $ms_ipaddresses .= "}"; + + #if ($VERBOSE) { + # print " ms_host_name=$ms_host_name, ms_nam=$ms_name, ms_aliases=$ms_aliases, ms_ip_addr=$ms_ipaddresses, ms_node_id=$ms_node_id\n"; + #} + + my $mon_nodes=$noderef->{$_}; + foreach(@$mon_nodes) { + my $node_pair=$_; + my $node=$node_pair->[0]; + my $nodetype=$node_pair->[1]; + if ((!$nodetype) || ($nodetype =~ /$::NODETYPE_OSI/)) { + #RMC deals only with osi type. empty type is treated as osi type + + #TODO: check if the node is installed and ready for configuring monitor + `fping -a $node 2> /dev/null`; + if ($?) { + print "Cannot add the node $node into the RMC domian. The node is inactive.\n"; + next; + } + + #get info for the node + $mn_node_id=`psh $node "head -n 1 /var/ct/cfg/ct_node_id" 2>&1`; + $mn_node_id =~ s/.*([0-9 a-g]{16}).*/$1/s; + + my ($mn_name,$mn_aliases,$mn_addrtype,$mn_length,@mn_addrs) = gethostbyname($node); + chomp($mn_name); + my $mn_ipaddresses="{"; + foreach (@mn_addrs) { + $mn_ipaddresses .= '"'.inet_ntoa($_) . '",'; + } + chop($mn_ipaddresses); + $mn_ipaddresses .= "}"; + #if ($VERBOSE) { + # print " mn_name=$mn_name, mn_aliases=$mn_aliases, mn_ipaddr=$mn_ipaddresses, mn_node_id=$mn_node_id\n"; + #} + + # define resource in IBM.MngNode class on server + $result=`mkrsrc-api IBM.MngNode::Name::"$node"::KeyToken::"$node"::IPAddresses::"$mn_ipaddresses"::NodeID::0x$mn_node_id`; + print "define resource in IBM.MngNode class result=$result\n"; + + #copy the configuration script and run it locally + $result=`scp $::XCATROOT/lib/perl/xCAT_monitoring/rmc/configrmcnode $node:/tmp`; + if ($resul>0) { + print "rmcmon:addNodes: cannot copy the file configrmcnode to node $node\n"; + next; + } + + $result=`psh $node /tmp/configrmcnode -a $node $ms_host_name $ms_ipaddresses 0x$ms_node_id`; + print "$result\n"; + } + } + } + + + return 0; +} + +#-------------------------------------------------------------------------------- +=head3 removeNodes + This function removes the nodes from the RMC cluster. + Arguments: + nodes --nodes to be removed. It is a hash reference keyed by the monitoring server + nodes and each value is a ref to an array of [nodes, nodetype] arrays monitored + by the server. So the format is: + {monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...} + verbose -- verbose mode. 1 for yes, 0 for no. + Returns: + none +=cut +#-------------------------------------------------------------------------------- +sub removeNodes { + $noderef=shift; + if ($noderef =~ /xCAT_monitoring::rmcmon/) { + $noderef=shift; + } + my $VERBOSE=shift; + + #if ($VERBOSE) { print "rmcmon::removeNodes called $noderef=$noderef\n"}; + + foreach (keys(%$noderef)) { + $server=$_; + #print " monitoring server: $server\n"; + + my $mon_nodes=$noderef->{$_}; + foreach(@$mon_nodes) { + my $node_pair=$_; + my $node=$node_pair->[0]; + my $nodetype=$node_pair->[1]; + #if ($VERBOSE) { print " node=$node, nodetype=$nodetype\n"; } + if ((!$nodetype) || ($nodetype =~ /$::NODETYPE_OSI/)) { + #RMC deals only with osi type. empty type is treated as osi type + + #TODO: check if the node is installed and ready for configuring monitor + `fping -a $node 2> /dev/null`; + if ($?) { + print "Cannot remove node $node from the RMC domian. The node is inactive.\n"; + next; + } + + #remove resource in IBM.MngNode class on server + my $result=`rmrsrc-api -s IBM.MngNode::"Name=\\\"\"$node\\\"\""`; + if ($VERBOSE) { print "remove resource in IBM.MngNode class result=$result\n"; } + + #copy the configuration script and run it locally + $result=`scp $::XCATROOT/lib/perl/xCAT_monitoring/rmc/configrmcnode $node:/tmp`; + if ($resul>0) { + print "rmcmon:removeNodes: cannot copy the file configrmcnode to node $node\n"; + next; + } + + $result=`psh --nonodecheck $node /tmp/configrmcnode -d $node`; + print "$result\n"; + } + } + } + + + return 0; + +} + + diff --git a/xCAT-rmc/resources/mn/IBM.Sensor/ErrorLogSensor.pm b/xCAT-rmc/resources/mn/IBM.Sensor/ErrorLogSensor.pm new file mode 100644 index 000000000..78fa9d1ab --- /dev/null +++ b/xCAT-rmc/resources/mn/IBM.Sensor/ErrorLogSensor.pm @@ -0,0 +1,14 @@ +#!/usr/bin/perl +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} + +$RES::Sensor{'ErrorLogSensor'} = { + Name => q(ErrorLogSensor), + Command => "$::XCATROOT/lib/perl/xCAT_monitoring/rmc/monerrorlog", + UserName => q(root), + RefreshInterval => q(60), + ControlFlags => q(4), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AIXNodeCoreDump.pm b/xCAT-rmc/resources/ms/IBM.Condition/AIXNodeCoreDump.pm new file mode 100644 index 000000000..eaedfcbb9 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AIXNodeCoreDump.pm @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +$RES::Condition{'AIXNodeCoreDump'} = { + Name => q(AIXNodeCoreDump), + ResourceClass => q(IBM.Sensor), + EventExpression => q(String=?"%label = CORE_DUMP%"), + EventDescription => q(An event will be generated when a core dump is logged in the AIX Error log of a node in the cluster.), + SelectionString => q(Name="ErrorLogSensor"), + ManagementScope => q(4), + Severity => q(0), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AllServiceableEvents.pm b/xCAT-rmc/resources/ms/IBM.Condition/AllServiceableEvents.pm new file mode 100644 index 000000000..540b71e80 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AllServiceableEvents.pm @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +$RES::Condition{'AllServiceableEvents'} = { + Name => q(AllServiceableEvents), + ResourceClass => q(IBM.Sensor), + EventExpression => q(String=?"LSSVCEVENTS_ALL%"), + EventDescription => q(An event will be generated whenever there is outpout from running sensor related to any serviceable events.), + SelectionString => q(Name="CSMServiceableEventSensor"), + ManagementScope => q(4), + Severity => q(0), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeAnyLoggedError.pm b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeAnyLoggedError.pm new file mode 100644 index 000000000..27e922cb5 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeAnyLoggedError.pm @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +$RES::Condition{'AnyNodeAnyLoggedError'} = { + Name => q(AnyNodeAnyLoggedError), + ResourceClass => q(IBM.Sensor), + EventExpression => q(String != ""), + EventDescription => q(An event will be generated when an error is logged to either the AIX Error Log or the Linux Syslog of a node in the cluster.), + SelectionString => q(Name="ErrorLogSensor"), + ManagementScope => q(4), + Severity => q(0), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeFileSystemInodesUsed.pm b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeFileSystemInodesUsed.pm new file mode 100644 index 000000000..18fe9b4a5 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeFileSystemInodesUsed.pm @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +$RES::Condition{'AnyNodeFileSystemInodesUsed'} = { + Name => q(AnyNodeFileSystemInodesUsed), + ResourceClass => q(IBM.FileSystem), + EventExpression => q(PercentINodeUsed>90), + EventDescription => q(An event will be generated when more than 90 percent of the total inodes in the file system is in use.), + RearmExpression => q(PercentINodeUsed<75), + RearmDescription => q(A rearm event will be generated when the percentage of the inodes used in the file system falls below 75 percent.), + ManagementScope => q(4), + Severity => q(2), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeFileSystemSpaceUsed.pm b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeFileSystemSpaceUsed.pm new file mode 100644 index 000000000..09fec0f1e --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeFileSystemSpaceUsed.pm @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +$RES::Condition{'AnyNodeFileSystemSpaceUsed'} = { + Name => q(AnyNodeFileSystemSpaceUsed), + ResourceClass => q(IBM.FileSystem), + EventExpression => q(PercentTotUsed>90), + EventDescription => q(An event will be generated when more than 90 percent of the total space of the file system is in use.), + RearmExpression => q(PercentTotUsed<75), + RearmDescription => q(A rearm event will be generated when the percentage of the space used in the file system falls below 75 percent.), + ManagementScope => q(4), + Severity => q(2), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeNetworkInterfaceStatus.pm b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeNetworkInterfaceStatus.pm new file mode 100644 index 000000000..7d9912347 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeNetworkInterfaceStatus.pm @@ -0,0 +1,14 @@ +#!/usr/bin/perl + +$RES::Condition{'AnyNodeNetworkInterfaceStatus'} = { + Name => q(AnyNodeNetworkInterfaceStatus), + ResourceClass => q(IBM.NetworkInterface), + EventExpression => q(OpState!=1), + EventDescription => q(An event will be generated whenever any network interface on the node is not online.), + RearmExpression => q(OpState=1), + RearmDescription => q(A rearm event will be generated when the network interface on the node becomes online again), + ManagementScope => q(4), + Severity => q(2), + +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AnyNodePagingPercentSpaceFree.pm b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodePagingPercentSpaceFree.pm new file mode 100644 index 000000000..2d219090c --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodePagingPercentSpaceFree.pm @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +$RES::Condition{'AnyNodePagingPercentSpaceFree'} = { + Name => q(AnyNodePagingPercentSpaceFree), + ResourceClass => q(IBM.Host), + EventExpression => q(PctTotalPgSpFree<10), + EventDescription => q(An event will be generated when the total amount of free paging space falls below 10 percent.), + RearmExpression => q(PctTotalPgSpFree>15), + RearmDescription => q(A rearm event will be generated when the free paging space increases to 15 percent.), + ManagementScope => q(4), + Severity => q(2), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeProcessorsIdleTime.pm b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeProcessorsIdleTime.pm new file mode 100644 index 000000000..262b01511 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeProcessorsIdleTime.pm @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +$RES::Condition{'AnyNodeProcessorsIdleTime'} = { + Name => q(AnyNodeProcessorsIdleTime), + ResourceClass => q(IBM.Host), + EventExpression => q(PctTotalTimeIdle>=70), + EventDescription => q(An event will be generated when the average time all processors are idle at least 70 percent of the time.), + RearmExpression => q(PctTotalTimeIdle<10), + RearmDescription => q(A rearm event will be generated when the idle time decreases below 10 percent.), + ManagementScope => q(4), + Severity => q(0), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeTmpSpaceUsed.pm b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeTmpSpaceUsed.pm new file mode 100644 index 000000000..7c0af7881 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeTmpSpaceUsed.pm @@ -0,0 +1,14 @@ +#!/usr/bin/perl + +$RES::Condition{'AnyNodeTmpSpaceUsed'} = { + Name => q(AnyNodeTmpSpaceUsed), + ResourceClass => q(IBM.FileSystem), + EventExpression => q(PercentTotUsed>90), + EventDescription => q(An event will be generated when more than 90 percent of the total space in the /tmp file system is in use.), + RearmExpression => q(PercentTotUsed<75), + RearmDescription => q(A rearm event will be generated when the percentage of the space used in the /tmp file system falls below 75 percent.), + SelectionString => q(Name="/tmp"), + ManagementScope => q(4), + Severity => q(2), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeVarSpaceUsed.pm b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeVarSpaceUsed.pm new file mode 100644 index 000000000..483321698 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/AnyNodeVarSpaceUsed.pm @@ -0,0 +1,14 @@ +#!/usr/bin/perl + +$RES::Condition{'AnyNodeVarSpaceUsed'} = { + Name => q(AnyNodeVarSpaceUsed), + ResourceClass => q(IBM.FileSystem), + EventExpression => q(PercentTotUsed>90), + EventDescription => q(An event will be generated when more than 90 percent of the total space in the /var file system is in use.), + RearmExpression => q(PercentTotUsed<75), + RearmDescription => q(A rearm event will be generated when the percentage of the space used in the /var file system falls below 75 percent.), + SelectionString => q(Name="/var"), + ManagementScope => q(4), + Severity => q(2), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Condition/CFMRootModTimeChanged.pm b/xCAT-rmc/resources/ms/IBM.Condition/CFMRootModTimeChanged.pm new file mode 100644 index 000000000..c5306f4bb --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Condition/CFMRootModTimeChanged.pm @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +$RES::Condition{'CFMRootModTimeChanged'} = { + Name => q(CFMRootModTimeChanged), + ResourceClass => q(IBM.Sensor), + EventExpression => q(String!=String@P), + EventDescription => q(An event will be generated whenever a file under /cfmroot is added or modified.), + SelectionString => q(Name="CFMRootModTime"), + ManagementScope => q(1), + Severity => q(0), +}; +1; diff --git a/xCAT-rmc/resources/ms/IBM.Sensor/CFMRootModTime.pm b/xCAT-rmc/resources/ms/IBM.Sensor/CFMRootModTime.pm new file mode 100644 index 000000000..8aa141651 --- /dev/null +++ b/xCAT-rmc/resources/ms/IBM.Sensor/CFMRootModTime.pm @@ -0,0 +1,13 @@ +#!/usr/bin/perl +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} + +$RES::Sensor{'CFMRootModTime'} = { + Name => q(CFMRootModTime), + Command => "$::XCATROOT/lib/perl/xCAT_monitoring/rmc/mtime /cfmroot", + UserName => q(root), + RefreshInterval => q(60), +}; +1; diff --git a/xCAT-rmc/scripts/perl/NodeUtils.pm b/xCAT-rmc/scripts/perl/NodeUtils.pm new file mode 100644 index 000000000..8b69b6a83 --- /dev/null +++ b/xCAT-rmc/scripts/perl/NodeUtils.pm @@ -0,0 +1,341 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +package NodeUtils; + +1; + +#------------------------------------------------------------------------------- +=head1 NodeUtils module +=head2 NodeUtils module is used to store common functions for RMC monitoring on + xCAT clusters. +=cut +#------------------------------------------------------------------------------- + + +sub isHMC +{ + my $hmcfile = "/opt/hsc/data/hmcType.properties"; + if (-e $hmcfile) { return 1; } + else { return 0; } +} + +#-------------------------------------------------------------------------------- +=head3 runcmd + Run the given cmd and return the output in an array (already chopped). Alternatively, + if this function is used in a scalar context, the output is joined into a single string + with the newlines separating the lines. + Arguments: + command, exitcode and reference to output + Returns: + see below + Error: + Normally, if there is an error running the cmd, it will display the error msg + and exit with the cmds exit code, unless exitcode is given one of the + following values: + 0: display error msg, DO NOT exit on error, but set + $::RUNCMD_RC to the exit code. + -1: DO NOT display error msg and DO NOT exit on error, but set + $::RUNCMD_RC to the exit code. + -2: DO the default behavior (display error msg and exit with cmds + exit code. + number > 0: Display error msg and exit with the given code + Example: + my $outref = NodeUtils->runcmd($cmd, -2, 1); + Comments: + If refoutput is true, then the output will be returned as a reference to + an array for efficiency. +=cut +#-------------------------------------------------------------------------------- +sub runcmd +{ + my ($class, $cmd, $exitcode, $refoutput) = @_; + $::RUNCMD_RC = 0; + if (!$::NO_STDERR_REDIRECT) { + if (!($cmd =~ /2>&1$/)) { $cmd .= ' 2>&1'; } + } + my $outref = []; + @$outref = `$cmd`; + if ($?) + { + $::RUNCMD_RC = $? >> 8; + my $displayerror = 1; + my $rc; + if (defined($exitcode) && length($exitcode) && $exitcode != -2) + { + if ($exitcode > 0) + { + $rc = $exitcode; + } # if not zero, exit with specified code + elsif ($exitcode <= 0) + { + $rc = ''; # if zero or negative, do not exit + if ($exitcode < 0) { $displayerror = 0; } + } + } + else + { + $rc = $::RUNCMD_RC; + } # if exitcode not specified, use cmd exit code + if ($displayerror) + { + my $errmsg = ''; + if (($^O =~ /^linux/i) && $::RUNCMD_RC == 139) + { + $errmsg = "Segmentation fault $errmsg"; + } + else + { + # The error msgs from the -api cmds are pretty messy. Clean them up a little. + NodeUtils->filterRmcApiOutput($cmd, $outref); + $errmsg = join('', @$outref); + chomp $errmsg; + } + print "Exit code $::RUNCMD_RC from command: $cmd\nError message from cmd: $errmsg\n" + } + } + if ($refoutput) + { + chomp(@$outref); + return $outref; + } + elsif (wantarray) + { + chomp(@$outref); + return @$outref; + } + else + { + my $line = join('', @$outref); + chomp $line; + return $line; + } +} + +#-------------------------------------------------------------------------------- +=head3 runrmccmd + Runs an RMC commmand + Arguments: + $rmccmd, $resclass, $options, $select, $exitcode, $nodelist_ref + Returns: + the output from runcmd($cmd, -2, 1) + as a ref to the output array. + Error: + none + Example: + my $outref =NodeUtils->runrmccmd('lsrsrc-api', "-i -D ':|:'", $where); + Comments: + When $nodelist_ref is not null, break it up into smaller slices + and run RMC commands seperately for each slice. + Otherwise just run RMC commands with the arguments passed in. +=cut +#-------------------------------------------------------------------------------- +sub runrmccmd +{ + my ($class, $rmccmd, $options, $select, $exitcode, $nodelist_ref) = @_; + + my @nodelist; + my $return_ref = []; + + if (!defined($exitcode)) + { + $exitcode = -2; + } + + if(! grep /usr\/bin/, $rmccmd) + { + # add absolute path + $rmccmd = "/usr/bin/$rmccmd"; + } + + if ($nodelist_ref) + { + # check whether to break up nodelist for better scalability. + @nodelist = @$nodelist_ref; + my $divide = 500; # max number of nodes for each division + my @sublist; + my @newarray; + my ($start_index, $end_index, $nodestring); + + my $count = 0; + my $times = int(scalar(@nodelist) / $divide); + while ($count <= $times) + { + $start_index = $count * $divide; + $end_index = + ((scalar(@nodelist) - 1) < (($count + 1) * $divide - 1)) + ? (scalar(@nodelist) - 1) + : (($count + 1) * $divide - 1); + @sublist = @nodelist[$start_index .. $end_index]; + @newarray = (); + foreach my $node (@sublist) + { + my @vals = split ',|\s', $node; + push @newarray, @vals; + } + $nodestring = join("','", @newarray); + + # replace the pattern in select string with the broken up node string + my $select_new = $select; + $select_new =~ s/XXX/$nodestring/; + my $cmd = "$rmccmd $options $select_new"; + my $outref = NodeUtils->runcmd($cmd, $exitcode, 1); + push @$return_ref, @$outref; + $count++; + } + } + else + { + my $cmd = "$rmccmd $options $select"; + $return_ref = NodeUtils->runcmd($cmd, $exitcode, 1); + } + + # returns a reference to the output array + return $return_ref; +} +#-------------------------------------------------------------------------------- +=head3 quote + Quote a string, taking into account embedded quotes. This function is most + useful when passing string through the shell to another cmd. It handles one + level of embedded double quotes, single quotes, and dollar signs. + Arguments: + string to quote + Returns: + quoted string + Globals: + none + Error: + none + Example: + Comments: + none +=cut +#-------------------------------------------------------------------------------- +sub quote +{ + my ($class, $str) = @_; + + # if the value has imbedded double quotes, use single quotes. If it also has + # single quotes, escape the double quotes. + if (!($str =~ /\"/)) # no embedded double quotes + { + $str =~ s/\$/\\\$/sg; # escape the dollar signs + $str =~ s/\`/\\\`/sg; + $str = qq("$str"); + } + elsif (!($str =~ /\'/)) + { + $str = qq('$str'); + } # no embedded single quotes + else # has both embedded double and single quotes + { + # Escape the double quotes. (Escaping single quotes does not seem to work + # in the shells.) + $str =~ s/\"/\\\"/sg; #" this comment helps formating + $str =~ s/\$/\\\$/sg; # escape the dollar signs + $str =~ s/\`/\\\`/sg; + $str = qq("$str"); + } +} + + +#-------------------------------------------------------------------------------- +=head3 filterRmcApiOutput + filter RMC Api Output + Arguments: + RMC command + Output reference + Returns: + none + Globals: + none + Error: + none + Example: + NodeUtils->filterRmcApiOutput($cmd, $outref); + Comments: + The error msgs from the RPM -api cmds are pretty messy. + This routine cleans them up a little bit. +=cut +#-------------------------------------------------------------------------------- +sub filterRmcApiOutput +{ + my ($class, $cmd, $outref) = @_; + if ($::VERBOSE || !($cmd =~ m|^/usr/bin/\S+-api |)) { + return; + } # give as much info as possible, if verbose + + # Figure out the output delimiter + my ($d) = $cmd =~ / -D\s+(\S+)/; + if (length($d)) { + $d =~ s/^(\'|\")(.*)(\"|\')$/$2/; # remove any surrounding quotes + # escape any chars perl pattern matching would intepret as special chars + $d =~ s/([\|\^\*\+\?\.])/\\$1/g; + } + else + { + $d = '::'; + } # this is the default output delimiter for the -api cmds + $$outref[0] =~ s/^ERROR${d}.*${d}.*${d}.*${d}.*${d}//; +} + + +#-------------------------------------------------------------------------------- +=head3 readFile + Read a file and return its content. + Arguments: + filename + Returns: + file contents or undef + Globals: + none + Error: + undef + Comments: + none +=cut +#-------------------------------------------------------------------------------- +sub readFile +{ + my ($class, $filename) = @_; + open(FILE, "<$filename") or return undef; + my @contents; + @contents = ; + close(FILE); + if (wantarray) { return @contents; } + else { return join('', @contents); } +} + +#-------------------------------------------------------------------------------- + +=head3 touchFile + Arguments: $filename, $donotExit + Returns: non zero return code indicates error + Example: NodeUtils->touchFile("/var/opt/csm/touch"); +=cut + +#-------------------------------------------------------------------------------- +sub touchFile +{ + my ($class, $filename, $donotExit) = @_; + my $fh; + my $rc = 0; + if (!-e $filename) { + #if the file doesn't exist we need to open and close it + open($fh, ">>$filename") or $rc++; + if ($rc > 0 && !$donotExit) { + print "Touch of file $filename failed with: $!\n"; + return $rc; + } + close($fh) or $rc++; + } + else { + #if the file does exist we can just utime it (see the perlfunc man page entry on utime) + my $now = time; + utime($now, $now, $filename); + } + if ($rc > 0 && !$donotExit) { + print "Touch of file $filename failed with: $!\n"; + return $rc; + } + return 0; +} diff --git a/xCAT-rmc/scripts/perl/configrmcnode b/xCAT-rmc/scripts/perl/configrmcnode new file mode 100755 index 000000000..c29b17e86 --- /dev/null +++ b/xCAT-rmc/scripts/perl/configrmcnode @@ -0,0 +1,69 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +use Getopt::Long; + +################################################################# +# This script is used for RMC node configuration +################################################################## +sub usage +{ + my %rsp; + print "Usage: + configrmcnode -a node_name ms_name ms_ip_addresses ms_node_id + configrmcnode -d node_name + "; +} + +print "configrmcnode get called\n"; +if (!GetOptions( + 'a' => \$::ADD, + 'd' => \$::DELETE,)) { + &usage; + exit 1; +} + +if ($::ADD) { + if (@ARGV < 4) { + &usage; + exit 1; + } + + #check if rsct is installed and running + if (! -e "/usr/bin/lsrsrc") { + print "RSCT is not is not installed.\n"; + exit 1; + } + my $result=`/usr/bin/lssrc -s ctrmc`; + if ($result !~ /active/) { + #restart rmc daemon + $result=`startsrc -s ctrmc`; + if ($?) { + print "rmc deamon cannot be started\n"; + exit 1; + } + } + + #enable remote client connection + `/usr/bin/rmcctrl -p; /usr/bin/refrsrc IBM.MCP`; + + #define resource in IBM.MCP class on node + $result=`/usr/bin/mkrsrc-api IBM.MCP::MNName::"$ARGV[0]"::KeyToken::"$ARGV[1]"::IPAddresses::"$ARGV[2]"::NodeID::$ARGV[3]`; + print "define resource in IBM.MCP class result=$result\n"; + + exit 0 +} + +if ($::DELETE) { + if (@ARGV < 1) { + &usage; + exit 1; + } + + #remove resource in IBM.MCP class on the node + my $result= `/usr/bin/rmrsrc-api -s IBM.MCP::"MNName=\\\"\"$ARGV[0]\\\"\""`; + print "remove resource in IBM.MCP class result=$result\n"; + + exit 0; +} + diff --git a/xCAT-rmc/scripts/perl/errmsgque b/xCAT-rmc/scripts/perl/errmsgque new file mode 100755 index 000000000..e954544b7 --- /dev/null +++ b/xCAT-rmc/scripts/perl/errmsgque @@ -0,0 +1,40 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl/xCAT_monitoring/rmc"; + +use strict; +use locale; + +use Getopt::Std; +use IPC::SysV qw(IPC_STAT S_IRWXU IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR ); +use IPC::Msg; +use NodeUtils; + +my $m = ord('xcat_rmc'); +my $key = IPC::SysV::ftok("/var/adm/ras/errlog", $m); + +my $msg = new IPC::Msg($key, IPC_CREAT|S_IRUSR|S_IWUSR ); +my $message = join " ", @ARGV; +my $stat = $msg->stat; +my $qcurrentlen = $$stat[5]; +if ($qcurrentlen >= 10000) { + if (!-d "/var/opt/xcat_rmc_err_mon/") { + my $cmd = "mkdir -p \"/var/opt/xcat_rmc_err_mon\""; + NodeUtils->runcmd($cmd, -1); + } + open(FILE, ">>/var/opt/xcat_rmc_err_mon/errmsgqueerr.log"); + my $sdate = `/bin/date`; + chomp $sdate; + print FILE "$sdate:\n"; + print FILE "Can not write the message to queue because the queue is almost full, the message content is: $message\n\n\n"; + close FILE; + exit 0; +} +$msg->snd(1, "$message"); + +exit 0; diff --git a/xCAT-rmc/scripts/perl/mkrmcresources b/xCAT-rmc/scripts/perl/mkrmcresources new file mode 100755 index 000000000..0cc0f1f35 --- /dev/null +++ b/xCAT-rmc/scripts/perl/mkrmcresources @@ -0,0 +1,576 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +#------------------------------------------------------------------------------- +=head1 mkrmcresources +=head2 mkrmcresources is used to predefine RMC conditions, responses, associations, + sensors (and can be extended to support any RSCT resource + class). + To use the command, create perl modules in a directory. Each resource + should have its own perl module (so that it is easy to update a + resource without interfering with other resources), + and should be named .pm. + After the resource perl modules are installed, they will be created + by the next execution of the this command. + This command should be called by the post install scripts + of packaging files, script run after install or from the command line. +=cut +#------------------------------------------------------------------------------- +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl/xCAT_monitoring/rmc"; + +use Getopt::Long; +use NodeUtils; + + +$Getopt::Long::ignorecase = 0; #Checks case in GetOptions +Getopt::Long::Configure("bundling"); #allows short command line options to be grouped (e.g. -av) + +#-------------------------------------------------------------------------------- +=head3 queryResources + Queries all resources of a given class or classes. Places + results into a global hash for each resource class. + Arguments: a list of RSCT resource classes + Globals: %::EXISTS::{$resource} +=cut +#-------------------------------------------------------------------------------- +sub queryResources +{ + my @resources = @_; + + my $where = ""; + foreach my $res (@resources) + { + if ($res eq "IBM.Association") + { + #special case: run lscondresp because Associations do not have names + #cant run lsrsrc because Assoctation also does not store names of resources (just handles) + my @condresp = NodeUtils->runcmd("LANG=C /usr/bin/lscondresp"); + my $class = $res; + $class =~ s/^IBM\.//; + splice @condresp, 0, + 2; #delete first two lines -- they are just comments + foreach my $line (@condresp) + { + my ($condition, $response, $node, $state) = split ' ', $line; + $condition = &removeQuotes($condition); + $response = &removeQuotes($response); + my $key = "${condition}:_:${response}"; + my $ActiveFlag = 0; #assume offline + if ($state =~ m/Active/) + { + $ActiveFlag = 1; + } + #currently does not checked for locked + # This \%{typeglob} syntax auto-vivifies + # the hash table for us, and gives us a reference. + my $ref = \%{$::EXISTS::{$class}}; + $ref->{$key} = {ActiveFlag => $ActiveFlag,}; + } + } + else + { + $where .= " -s ${res}::::'*p0x0020'"; + } + } + + my $output = NodeUtils->runrmccmd("lsrsrc-api", "-i -m -n -D ':|:'", $where); + foreach my $line (@$output) + { + my @array = split(/:\|:/, $line); + my $class = shift @array; #the -m flag puts the class name in front + $class =~ s/^IBM\.//; + my %attrs = @array; + # This \%{typeglob} syntax auto-vivifies + # the hash table for us, and gives us a reference. + my $ref = \%{$::EXISTS::{$class}}; + my $key = $attrs{'Name'}; + $ref->{$key} = {%attrs}; #sets the EXISTS array with the info + } +} + +#-------------------------------------------------------------------------------- +=head3 traverseDirectories + Calls readFiles on each sub-directory of the given path. + Creates a global array with all target resource classes. + Arguments: A directory + Globals: @::DIRECTORIES (will hold all resource classes) +=cut +#-------------------------------------------------------------------------------- +sub traverseDirectories +{ + my ($dir) = @_; + my ($dir_fh, $file); + + opendir($dir_fh, $dir) + or die "Can not open directory $dir\n"; + while ($file = readdir($dir_fh)) + { + if ($file ne '.' and $file ne '..') + { + my $subdir = "$dir/$file"; + if (-d $subdir) + { #only look at directories + &readFiles($subdir); + push @::DIRECTORIES, $file; #file=just the filename + } + } + } + closedir($dir_fh) + or die "Can not close directory $dir\n"; +} + +#-------------------------------------------------------------------------------- +=head3 readFiles + Calls require on all .pm files in a given directory + Arguments: A directory +=cut +#-------------------------------------------------------------------------------- +sub readFiles +{ + my ($dir) = @_; + my ($dir_fh, $file); + opendir($dir_fh, $dir) + or die "Can not open directory $dir\n"; + while ($file = readdir($dir_fh)) + { + if ($file ne '.' and $file ne '..') + { + $file = "$dir/$file"; + if ($file =~ m/\.pm$/) + { + #its a perl module + require $file; + } + } + } + closedir($dir_fh) + or die "Can not close directory $dir\n"; +} + +#-------------------------------------------------------------------------------- +=head3 compareResources + Compares existing resources to those requiring definition. + Globals: uses %::EXISTS and %::RES and makes %::CHANGE and %::CREATE +=cut +#-------------------------------------------------------------------------------- +sub compareResources +{ + foreach my $class (@::DIRECTORIES) + { #this has all subdirectory names + $class =~ s/^IBM\.//; #the IBM prefix is not used in the hash name + local *exi = $::EXISTS::{$class}; #defined on system + local *res = $::RES::{$class}; #defined in file + foreach my $resource (keys %res) + { + if (defined $exi{$resource}) + { #exists on the system + if (defined $res{$resource}{'Locked'} + && $res{$resource}{'Locked'} == 1) + { + #only change the resource if it is supposed to be locked + foreach my $attr (keys %{$res{$resource}}) + { + if ($exi{$resource}{$attr} ne $res{$resource}{$attr}) + { + if (!($class eq "Association" && $attr eq "Locked")) + { # association locked attrs are not stored + # something has changed + if ($::VERBOSE) + { + print "Differs: Class=$class\tExists=$exi{$resource}{$attr}\tDefined=$res{$resource}{$attr}\n"; + } + $::CHANGE::{$class}{$resource} = $res{$resource}; + last; + } + } + } + } + } + else + { #resource is not defined on the system + $::CREATE::{$class}{$resource} = $res{$resource}; + } + } + } +} + +#-------------------------------------------------------------------------------- +=head3 removeQuotes + removes starting and ending quotes that are in the output of lsrsrc + Arguments: string + Returns: string with no leading or trailing quotes +=cut +#-------------------------------------------------------------------------------- +sub removeQuotes +{ + my ($string) = @_; + $string =~ s/^\"|^\'//; + $string =~ s/\"$|\'$//; + return $string; +} + +#-------------------------------------------------------------------------------- +=head3 createResources + Calls mkrsrc-api on all resources in the %::CREATE hash + Globals: %::CREATE +=cut +#-------------------------------------------------------------------------------- +sub createResources +{ + my $string; + my $counter = 0; + my @assoc_cmds; + my $sensorflg = 0; + foreach my $class (@::DIRECTORIES) + { #all the class names + local *cre = $::CREATE::{$class}; + if ($class eq "Sensor") + { + $sensorflg = 1; + } + else + { + $sensorflg = 0; + } + foreach my $resource (keys %cre) + { + if ($class eq "Association") + { #special case + my ($cond, $resp) = split ":_:", $resource; + if ($cre{$resource}{'ActiveFlag'} == 1) + { + push @assoc_cmds, "/usr/bin/startcondresp $cond $resp"; + if ($cre{$resource}{'Locked'} == 1) + { + push @assoc_cmds, "/usr/bin/startcondresp -L $cond $resp"; + } + } + else + { #not active + push @assoc_cmds, "/usr/bin/mkcondresp $cond $resp"; + #no need to lock stopped associations + } + } + else + { + $string .= " IBM.${class}::"; + foreach my $attr (keys %{$cre{$resource}}) + { + my $value = $cre{$resource}{$attr}; + $string .= "${attr}::" . NodeUtils->quote($value) . "::"; + } + if (($sensorflg == 1) && ($::INSTALL)) + { + # make the Sensor with no userid check + $string .= "::Options::1"; + } + # + # Only build up to 10 resources at a pass + # to avoid command line limit + # + $counter = $counter + 1; + if ($counter > 10) + { + if ($string =~ m/\w+/) + { + #my $cmd = "/usr/bin/mkrsrc-api $string"; + #print "running $cmd\n"; + #system($cmd); + NodeUtils->runrmccmd("mkrsrc-api", "", $string); + $string = ""; + $counter = 0; + } + } + } + } + } + if ($string =~ m/\w+/) # for any remaining resources + { + #my $cmd = "/usr/bin/mkrsrc-api $string"; + #print "running $cmd\n"; + #system($cmd); + NodeUtils->runrmccmd("mkrsrc-api", "", $string); + } + foreach my $cmd (@assoc_cmds) + { + #need to make associations after conds and resps have been made + NodeUtils->runcmd("$cmd"); + } +} + +#-------------------------------------------------------------------------------- +=head3 changeResources + Calls chrsrc-api on all resources in the %::CHANGE hash + Globals: %::CHANGE +=cut +#-------------------------------------------------------------------------------- +sub changeResources +{ + my $string; + my $ustring; #unlock + my @unlock; #unlock each class + my $where; #unlock each class + foreach my $class (@::DIRECTORIES) + { #all the class names + local *cha = $::CHANGE::{$class}; + foreach my $resource (keys %cha) + { + if ($class eq "Association") + { #special case + #code here is identical to createResource + my ($cond, $resp) = split ":_:", $resource; + if ($cre{$resource}{'ActiveFlag'} == 1) + { + NodeUtils->runcmd("/usr/bin/startcondresp $cond $resp"); + if ($cre{$resource}{'Locked'} == 1) + { + NodeUtils->runcmd( "/usr/bin/startcondresp -L $cond $resp"); + } + } + else + { #not active + NodeUtils->runcmd("/usr/bin/mkcondresp $cond $resp"); + #no need to lock stopped associations + } + } + else # not class association + { + $where = qq/"Name IN ('XXX')"/; + $string .= " -s IBM.${class}::${where}::"; + push @unlock, $cha{$resource}{'Name'}; + delete $cha{$resource}{'Name'}; + foreach my $attr (keys %{$cha{$resource}}) + { + my $value = $cha{$resource}{$attr}; + $string .= "${attr}::" . NodeUtils->quote($value) . "::"; + } + } + if (@unlock) + { + $where = qq/"Name IN ('XXX')"/; + $ustring .= " -s IBM.${class}::${where}::Locked::'0'"; + } + } # foreach resource + } # foreach key + # + # although @unlock contains the resource and not the node name + # this is a hack to use runrmccmd and the node_ref must + # be provided even though we are not really dealing with nodes + # here + + if ($ustring =~ m/\w+/) { + NodeUtils->runrmccmd("chrsrc-api", "", $ustring, undef, \@unlock); + } + if ($string =~ m/\w+/) { + NodeUtils->runrmccmd("chrsrc-api", "", $string, undef, \@unlock); + } +} + + +#-------------------------------------------------------------------------------- +=head3 writeAllFiles + creates all files for the given resources classes + Arguments: a array ref of class names, basedir +=cut +#-------------------------------------------------------------------------------- +sub writeAllFiles +{ + my @classes = @{shift()}; + my $basedir = shift; + print "classes=@classes, basedir=$basedir"; + foreach my $class (@classes) + { + my $output = NodeUtils->runrmccmd("lsrsrc-api", "-i", "-s ${class}::::Name"); + foreach my $line (@$output) + { + &writeFile("${class}::$line", $basedir); + } + } +} + +#-------------------------------------------------------------------------------- +=head3 writeFile + creates a file with the resource info in + $basedir/ + Arguments: class::resource_name, basedir +=cut +#-------------------------------------------------------------------------------- +sub writeFile +{ + my $input = shift; + my $basedir= shift; + print "input=$input, basedir=$basedir\n"; + + my ($class, $resourcefilename) = split "::", $input; + if (!$resourcefilename) { + print 'mkrmcresource --mkfile requires as input.\n'; + exit 1; + } + my $resource; + push(@$resource, $resourcefilename); + + if (!-e "$basedir/$class") { + `mkdir -p "$basedir/$class"`; + } + my $file = "$basedir/$class/$resourcefilename.pm"; + my $where = qq/"Name IN ('XXX')"/; + my $string = " -s ${class}::${where}::*p0x0002"; + my $output = NodeUtils->runrmccmd("lsrsrc-api", "-i -n -D ':|:'", + $string, undef, $resource); + $string = " -s ${class}::${where}::*p0x0008"; + my $optional = NodeUtils->runrmccmd("lsrsrc-api", "-i -n -D ':|:'", + $string, undef, $resource); + + #my @output = NodeUtils->runcmd("/usr/bin/lsrsrc -s $where $class"); + #uses lsrsrc instead of lsrsrc-api because format is almost right (just needs a few mods) + + my $fh; + open($fh, ">$file") + or die "Can not open this file for writing $file.\n"; + print $fh "#!/usr/bin/perl\n\n"; + $class =~ s/IBM\.//; + + print $fh '$RES::' . $class . "{" . "'" + . $resourcefilename . "'" + . "} = {\n"; + foreach my $line (@$output) + { + my %attrs = split /:\|:/, + $line; #can't go straight into a hash because -p creates extra fields + foreach my $attr (keys %attrs) + { + if ( $attr !~ m/ActivePeerDomain/ + && $attr !~ m/NodeNameList/ + && $attr !~ m/NodeIDs/) + { + my $value = $attrs{$attr}; + if ($value =~ m/\w/ || $value =~ m/\d/) + { + # print "value = |$value|\n"; + #$value = &removeQuotes($value); #quotes are not needed becaues of q() + #print "value = |$value|\n"; + my $line = "\t$attr => q($value),"; + print $fh "$line\n"; + } + } + } + } + foreach my $line (@$optional) + { + my %attrs = split /:\|:/, + $line; #can't go straight into a hash because -p creates extra fields + foreach my $attr (keys %attrs) + { + if ( $attr !~ m/ActivePeerDomain/ + && $attr !~ m/NodeNameList/ + && $attr !~ m/NodeIDs/) + { + my $value = $attrs{$attr}; + if ($value =~ m/\w/ || $value =~ m/\d/) + { + # print "value = |$value|\n"; + #$value = &removeQuotes($value); #quotes are not needed becaues of q() + #print "value = |$value|\n"; + my $line = "\t$attr => q($value),"; + print $fh "$line\n"; + } + } + } + } + + print $fh "};"; + print $fh "\n"; + print $fh "1;"; + print $fh "\n"; + close($fh) + or die "cabbit close file $file\n"; +} + + +#-------------------------------------------------------------------------------- +=head3 usage + Prints the command usage statement +=cut +#-------------------------------------------------------------------------------- +sub usage +{ + print "Usage: + mkrmcresources [--install|--mkfile classname::rsrcname|--mkall] \ + [-V|--verbose] directory\n\ + mkrmcresources -h|--help\n\ + directory a full path to a base directory for resurce files \ + to be created or to be read from. \ + -V|--verbose Verbose mode.\ + -h|--help shows usage information.\ + --install\ + The userid in the Sensor resource will not be verified.\n"; + +} + +####################################################################### +# main Main MAIN +####################################################################### + +# get arguments +if ( + !GetOptions( + 'h|help' => \$::HELP, + 'V|verbose' => \$::VERBOSE, + 'install' => \$::INSTALL, + 'mkfile=s' => \$::MKFILE, + 'mkall' => \$::MKALL, + ) + ) +{ + &usage; + exit 1; +} + +if ($::HELP) { &usage; exit; } +if (NodeUtils->isHMC() && ($ENV{'DC_ENVIRONMENT'} ne 1)) +{ + print "mkresources is not supported on HMC.\n"; +} + +# any function requested +if (@ARGV < 1) { + &usage; + exit 1; +} + +my $basedir = $ARGV[0]; + +if ($::MKFILE) { + &writeFile($::MKFILE, $basedir); + exit; +} +if ($::MKALL) { + @rsrc_classes=('IBM.Condition', 'IBM.EventResponse', 'IBM.Sensor'); + &writeAllFiles(\@rsrc_classes, $basedir); + exit; +} + + + +&traverseDirectories($basedir); + +#TODO: wait for RSCT to come online + +&queryResources(@::DIRECTORIES); + +#compares whats defined in the files to the existing resources +&compareResources(); + +&createResources(); + +&changeResources(); + +END +{ + +} +exit 0; + diff --git a/xCAT-rmc/scripts/perl/monerrorlog b/xCAT-rmc/scripts/perl/monerrorlog new file mode 100755 index 000000000..aaea1dae0 --- /dev/null +++ b/xCAT-rmc/scripts/perl/monerrorlog @@ -0,0 +1,240 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +#------------------------------------------------------------------------------ +=head1 monerrorlog +=head2 When first run (by the sensor) this script adds an entry to the AIX ODM + or Linux syslog.conf file so that it will be notified when an error is + logged (through a message queue on AIX and a named pipe on Linux). Then + it checks for any logged errors. On all subsequent runs this script just + checks for errors. +=cut +#------------------------------------------------------------------------------ +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl/xCAT_monitoring/rmc"; + +use strict; +use locale; + +use Getopt::Std; +use IPC::SysV qw(IPC_STAT S_IRWXU IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR ); +use IPC::Msg; +use NodeUtils; + +#do nothing on Linux when stopping. +if (($ENV{'SENSOR_MonitorStatus'} eq '2') && ($^O =~ /^linux/i)) { + exit 0; +} + +#normal +my $dirname = "xcat_rmc_err_mon"; +my $vardir = "/var/opt/$dirname" ; +my $runfile = "$vardir/.monerrorlog_run"; +my $fifo = "$vardir/syslog_fifo"; +my ($syslogconf, $embedinfo); +if (-e "/etc/SuSE-release") { #SLES 10 + $syslogconf = "/etc/syslog-ng/syslog-ng.conf"; + $embedinfo = "destination warn_fifo { pipe(\\\"$fifo\\\" group(root) perm(0644)); };\nlog { source(src); filter(f_warn); destination(warn_fifo); };"; +} +else { #others + $syslogconf = "/etc/syslog.conf"; + $embedinfo = "*.warn |$fifo"; +} +my $odmstanza = "$vardir/odmstanza"; + +if (!-d $vardir) { mkdir($vardir); } + +sub isRMrunning{ + my $resMan = $_[0]; + my @output = NodeUtils->runcmd("LANG=C /usr/bin/lssrc -s $resMan", -1); + if ($::RUNCMD_RC) { return 0; } # maybe we should try to catch real errors here + my ($subsys, $group, $pid, $status) = split(' ', $output[1]); + if (defined($status) && $status eq 'active') { + #now check to see if IBM.AuditRM is up + return 1; + } + return 0; +} +#check to see if this is the first time this script has been run +if (!-e $runfile){ + #first time + if ($^O =~ /^linux/i) { + NodeUtils->runcmd("grep $dirname $syslogconf", -1); + if ($::RUNCMD_RC == 1) { #grep did not find dirname + #update syslog.conf + if (!-d $vardir) { mkdir($vardir); } + NodeUtils->runcmd("/usr/bin/mkfifo $fifo"); + NodeUtils->runcmd("echo \"$embedinfo\" >> $syslogconf"); + my $cmd = service("syslog", "restart"); + NodeUtils->runcmd($cmd); + } + NodeUtils->touchFile($runfile); + } + elsif ($^O =~ /^aix/i) { + open(ODM, ">$odmstanza") or die $!; + print ODM ' +errnotify: + en_pid = 0 + en_name = "xcat_rmc_errlog_sensor" + en_persistenceflg = 1 + en_method = "' . "$::XCATROOT/lib/perl/xCAT_monitoring/rmc/errmsgque" . ' sequence = $1 error_id = $2 class = $3 type = $4 alert_flags = $5 res_name = $6 res_type = $7 res_class = $8 label = $9" +'; + close ODM or die $!; + NodeUtils->runcmd("/usr/bin/odmadd $odmstanza"); + NodeUtils->touchFile($runfile); + } + else { + print "unknown platform\n"; + exit 1; + } +} + +#Check for errors + +#see if at is running +verify_atd(); #TODO optimize this by not using at + +if ($^O =~ /^linux/i) { + local $SIG{ALRM} = sub { die "alarm\n" }; + eval { + alarm 4; + open(PIPE, $fifo) or die + print "Could not open $fifo.\n"; + alarm 0; + }; + if ($@ =~ /alarm/) { close PIPE; exit 0; } + + while (1) { + my $line; + eval { + alarm 2; + $line = ; + alarm 0; + }; + if ($@ =~ /alarm/) { close PIPE; exit 0; } + chomp($line); + + #print "String=\"$line\"\n"; + NodeUtils->runcmd( + "echo \"/usr/bin/refsensor ErrorLogSensor String=\'$line\' 1>/dev/null 2>/dev/null\" | at now",0); + } + close PIPE; +} +elsif ($^O =~ /^aix/i) { + # the monitoring is stopped + if ($ENV{'SENSOR_MonitorStatus'} eq '2') { + # stopsrc -s IBM.SensorRM will also + # set $ENV{'SENSOR_MonitorStatus'} to 2 + # should not do clean up when IBM.SensorRM is stopped + if (&isRMrunning("IBM.SensorRM")) { + NodeUtils->runcmd("/bin/odmdelete -o errnotify -q \" en_name=xcat_rmc_errlog_sens\"", -1); + if (-e $runfile) { + unlink($runfile); + } + } + exit 0; + } + + my $m = ord('xcat_rmc'); + my $key = IPC::SysV::ftok("/var/adm/ras/errlog", $m); + my $buf; + my $msg = new IPC::Msg($key, IPC_CREAT | S_IRUSR | S_IWUSR); + local $SIG{ALRM} = sub { die "alarm\n" }; + while (1) { + eval { + alarm 2; + my $rectype = $msg->rcv($buf, 256); + alarm 0; + }; + if ($@ =~ /alarm/) { close PIPE; exit 0; } + NodeUtils->runcmd( + "echo \"/usr/bin/refsensor ErrorLogSensor String=\'$buf\' 1>/dev/null 2>/dev/null\" | at now", 0); + } + + exit 0; +} + + + +#-------------------------------------------------------------------------------- +=head3 verify_atd + check for atd status. If it is not running, start it. + Arguments: + Returns: + $::RUNCMD_RC = 0 atd is running + $::RUNCMD_RC > 0 atd is not running +=cut + +#-------------------------------------------------------------------------------- +sub verify_atd +{ + my $cmd; + $cmd = service("atd", "status"); + NodeUtils->runcmd($cmd, -1); + if ($::RUNCMD_RC) { + $cmd = service("atd", "start"); + NodeUtils->runcmd($cmd, -1); + if ($::RUNCMD_RC) { + print "Warning: atd has failed to start!\n"; + } + elsif (!$::RUNCMD_RC) { + sleep(1); + } + } + else { + ;#??? + } + return $::RUNCMD_RC; +} + +#-------------------------------------------------------------------------------- +=head3 service + Send a service request to an init script. + Arguments: + $service - a service name such as 'inetd','xinetd' + $svcarg - arguments for the service such as 'start', + 'stop' or 'status'. + Returns: + A full cli for the service script. +=cut + +#-------------------------------------------------------------------------------- +sub service +{ + my ($service, $svcarg) = @_; + my $cmd; + my $SVCCLI = "/sbin/service"; + my $SVCDIR = "/etc/init.d"; + + # On SLES, nfs server script is "nfsserver". + if (((-e "/etc/SuSE-release") || NodeUtils->isHMC()) && $service eq "nfs") { + $service = "nfsserver"; + } + if (-f $SVCCLI) { + $cmd = "$SVCCLI $service $svcarg "; + } + else { + $cmd = "$SVCDIR/$service $svcarg"; + } + return $cmd; +} + +exit 0; + + + + + + + + + + + + + + + + diff --git a/xCAT-rmc/scripts/perl/mtime b/xCAT-rmc/scripts/perl/mtime new file mode 100755 index 000000000..5c1c6627b --- /dev/null +++ b/xCAT-rmc/scripts/perl/mtime @@ -0,0 +1,108 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +require 'open3.pl'; + +#This script is a modified version of mtime to be used as part of a sensor in the +#software managemnent system. This PERL script goes and finds the latest changed file via mtime +# It recurses the directory structure starting with the directory passed in via the command line +# (directory routine) and checks each file. +# +# Result is put to stdout + +$mtime = 0; +$startdir = @ARGV[0]; +chomp($startdir); + +if (-d $startdir) { #directory + &directory("/", *mtime); +} +elsif (-f $startdir) { #file + my ($dv, $in, $m, $nl, $u, $g, $rd, $siz, $at, $mtime1) = stat($startdir); + $mtime = $mtime1; +} +else { exit 1; } #not a recognized format + +print $mtime; +exit 0; + +# +# directory +# +# Goes through directory tree to find files we need to pay attention too. +# Each file is checked for mtime. +# +sub directory +{ + local ($dir, *mtime, $nlink) = @_; + local ($dev, $ino, $mode, $subcount, $dirtry, $namedirtry, $name1, $name, + $dir1, $mtime1, $dv, $in, $m, $nl, $u, $g, $rd, $siz, $at); + + ($dev, $ino, $nlink) = stat($dir) unless $nlink; + + $dirtry = $startdir; + $dirtry .= $dir; + + $dir1 = substr($dir, 1); + + opendir(DIR, $dirtry); + + local (@filenames) = readdir(DIR); + + if ($nlink == 2) { + for (@filenames) { + next if $_ eq '.'; + next if $_ eq '..'; + # + # Check to see if the mtime of this file is later than the current mtime + # + $name = "$dir/$_"; + $name1 = "$dir1/$_"; + $name2 = "/$startdir/$name1"; + + ($dv, $in, $m, $nl, $u, $g, $rd, $siz, $at, $mtime1) = stat($name2); + + if ($mtime1 > $mtime) { + $mtime = $mtime1; + } + } + } + else { + $subcount = $nlink - 2; + for (@filenames) { + next if $_ eq '.'; + next if $_ eq '..'; + + # + # Check to see if the mtime of this file is later than the current mtime + # + + $name = "$dir/$_"; + $name1 = "$dir1/$_"; + $name2 = "/$startdir/$name1"; + + ($dev, $ino, $m, $nl, $u, $g, $rd, $siz, $at, $mtime1) = stat($name2); + + if ($mtime1 > $mtime && !(-d $name2)) { + $mtime = $mtime1; + } + + next if $subcount == 0; + + # + # Recurse into next lower subdirectory + # + + $namedirtry = "/$startdir/"; + $namedirtry .= $name; + + ($dev, $ino, $mode, $nlink) = lstat($namedirtry); + + #next unless -d _; + next unless { $nlink > 1 } + &directory($name, *mtime, $nlink); + + --$subcount; + } + } +} diff --git a/xCAT-rmc/xCAT-rmc.spec b/xCAT-rmc/xCAT-rmc.spec new file mode 100644 index 000000000..9f3c4549e --- /dev/null +++ b/xCAT-rmc/xCAT-rmc.spec @@ -0,0 +1,49 @@ +Summary: RMC monitoring plug-in for xCAT +Name: xCAT-rmc +Version: 2.0 +Release: snap%(date +"%Y%m%d%H%M") +License: EPL +Group: System Environment/Libraries +Source: xCAT-rmc-2.0.tar.gz +Packager: IBM Corp. +Vendor: IBM Corp. +Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} +Prefix: /opt/xcat +BuildRoot: /var/tmp/%{name}-%{version}-%{release}-root +%ifos linux +BuildArch: noarch +%endif + +Provides: xCAT-rmc = %{version} + +%description +Provides RMC monitoring plug-in module for xCAT, configuration scripts, predefined conditions, responses and sensors. + +%prep +%setup -q +%build +%install + +rm -rf $RPM_BUILD_ROOT + +mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_monitoring/rmc +mkdir -p $RPM_BUILD_ROOT/%{prefix}/sbin/rmcmon + +cp plugin/* $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_monitoring +cp -r resources $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_monitoring/rmc + +cp scripts/perl/* $RPM_BUILD_ROOT/%{prefix}/sbin/rmcmon +chmod 755 $RPM_BUILD_ROOT/%{prefix}/sbin/rmcmon/* + +%clean +rm -rf $RPM_BUILD_ROOT + +#find $RPM_BUILD_ROOT -type f | sed -e "s@$RPM_BUILD_ROOT@/@" > files.list + +%files +%defattr(-, root, root) +%{prefix} + +%changelog + +