2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-30 01:26:38 +00:00

Initial xCAT 2.0 import

git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@2 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
jbjohnso 2007-10-26 22:44:33 +00:00
parent abc365a315
commit c99d72a179
516 changed files with 46103 additions and 0 deletions

42
QUICKSTART Normal file
View File

@ -0,0 +1,42 @@
This is at this point essentially a demo of xCAT 2.0 concepts.
Currently, all it can do is the set of out-of-band management of IPMI systems.
To see how it works:
./rpminstallperlxcat
./rpminstallserver
(at this point it will list failed dependencies probably, have fun filling those,
SLES10 includes the SSL one, and SLES10 sdk has perl-XML-Simple,
the details of making these deps easy is a TODO for 1.3 release)
./rpminstallclient
Now that it is installed, setup of the security for 1.2 like operation:
/usr/share/xcat/scripts/setup-xcat-ca.sh
(put whatever common name you want)
/usr/share/xcat/scripts/setup-server-cert.sh
(name something for your server, say y twice)
/usr/share/xcat/scripts/setup-local-client.sh
(use the name root for now)
chtab key=xcatdport site.value=3002 (using 3002 so you can use it on an xcat 1.2 server without worry)
(now assuming setup for a node called node1 with a bmc called node1-bmc)
chtab node=node1 nodelist.groups=ipmi
chtab node=ipmi nodehm.mgt=ipmi ipmi.bmc='/\z/-bmc/'
(start xcatd)
xcatd & (the warnings are not actually useful to correct now, so don't worry)
export XCATHOST=localhost:3002
testclient power node1 stat
(should work, number of commands will work, obviously the name indicates I haven't bother with the shorter
rpower/rinv/rvitals names yet, but it will come, also obviously since the client can do everything,
it will be busybox like most likely)
To add another node2 with same name scheme as node1:
chtab node=node2 nodelist.groups=ipmi
(can immediately start rpowering)

27
doc/configuration.pod Normal file
View File

@ -0,0 +1,27 @@
=pod
=head1 xCAT configuration core architecture
xCAT configuration spans a number of tables, some with records associated with particular nodes (such as nodelist and nodehm) and others that do not have a direct relationship with any given node.
The tables not associated with a given node are straightforward, the data is stored and retrieved as-is from the database without interpretation, and without any configuration layer inheritance (though some calling code may have an internal concept of inheritance with such fields, the core configuration will have no facilities to explicitly aid this.
The tables with records typically retrieved by node name have some extra features to enable a more template-based style to be used:
=over
=item *
Any tagname can be used in lieu of a node name under the node field, and that record will then be taken to be applicable to any node with that tag. If a field is requested for a specific node, and either a record doesn't exist specifically for that nodename or a record exists, but has no definition for the requested field, that nodes tags are then used to search for general level records. If multiple records could apply from two different tags, the precedence is TBD. This is nearly identical to most xCAT 1.x tab file conventions. This is useful in tables such as noderes, where typical configurations have exactly the same field values for large sets of nodes.
=item *
xCAT 2 extends the above to be made useful where a field will vary for every node with a given tag, but in ways that would be trivial to describe. If a field is of the format /I<pattern>/I<replacement>/, it is taken to be a perl regular expression, to be performed on the nodename. For example, the bmc field of the ipmi table might be /\z/-bmc/ for a record with node=ipmi to specify that the BMC hostname is derived by appending -bmc to the end of the nodename of every node tagged ipmi. This is useful in tables such as ipmi.
=item *
As an extension to the above, a regular expression extended with arithmetic operators is available, by using the format |I<pattern>|I<replacement>|. This behaves similarly to the above, but () enclosed parts in I<replacement> are taken to signify arithmetic operations and substituted in. All operations are integer arithmetic, so 5/4 would come out as 1. The typical perl positional variables are available in such expressions. For example, the mpa field of the mp table for node=blade might be |\D+(\d+)|bc((${1}-1)/14+1)|. Specifically in this case, if you had a node named blade572 tagged blade, the 572 would be set to ${1} by the left hand parentheses, and on the right hand, that would become bc((572-1/14+1)), and finally evaluated and returned as bc41. To complete the example, the id field of mp would be |\D+(\d+)|((${1}-1)%14+1)|, which upon evaluation indicates slot 12. This is useful for tables that call out infrastructure devices/port numbers, such as switch, nodehm (for terminal servers), and mp (for IBM Bladecenter configurations).
=back
An administrator may chose to ignore any and all of the functions. For example, an administrator may chose to only make use of the first mentioned feature, and preserve an xCAT 1.x layout for their tables.

29
makeclientrpm Executable file
View File

@ -0,0 +1,29 @@
#!/bin/ksh
OSNAME=$(uname)
if [ "$OSNAME" = "AIX" ]
then
tar -cvf xCAT-client-2.0.tar xCAT-client-2.0
gzip xCAT-client-2.0.tar
cp xCAT-client-2.0.tar.gz /opt/freeware/src/packages/SOURCES
cd ./xCAT-client-2.0
rm /opt/freeware/src/packages/RPMS/ppc/xCAT-client-2.0*rpm
rpm -ba xCAT-client.spec
#rpm -Uvh /opt/freeware/src/packages/RPMS/ppc/xCAT-client-2.0*rpm
else
if [ -f /etc/redhat-release ]
then
pkg="redhat"
else
pkg="packages"
fi
tar czvf xCAT-client-2.0.tar.gz xCAT-client-2.0;
rm /usr/src/$pkg/RPMS/noarch/xCAT-client-2.0*rpm
rpmbuild -ta xCAT-client-2.0.tar.gz ;
#rpm -Uvh /usr/src/$pkg/RPMS/noarch/xCAT-client-2.0*rpm
fi

28
makeperlxcatrpm Executable file
View File

@ -0,0 +1,28 @@
#!/bin/ksh
OSNAME=$(uname)
if [ "$OSNAME" = "AIX" ]
then
tar -cvf perl-xCAT-2.0.tar perl-xCAT-2.0
gzip perl-xCAT-2.0.tar
cp perl-xCAT-2.0.tar.gz /opt/freeware/src/packages/SOURCES
cd ./perl-xCAT-2.0
rm /opt/freeware/src/packages/RPMS/ppc/perl-xCAT-2.0*rpm
rpm -ba perl-xCAT.spec
#rpm -Uvh /opt/freeware/src/packages/RPMS/ppc/perl-xCAT-2.0*rpm
else
if [ -f /etc/redhat-release ]
then
pkg="redhat"
else
pkg="packages"
fi
tar --exclude .svn -czvf perl-xCAT-2.0.tar.gz perl-xCAT-2.0/;
rm /usr/src/$pkg/RPMS/noarch/perl-xCAT-2.0*rpm
rpmbuild -ta perl-xCAT-2.0.tar.gz ;
#rpm -Uvh /usr/src/$pkg/RPMS/noarch/perl-xCAT-2.0*rpm
fi

28
makeserverrpm Executable file
View File

@ -0,0 +1,28 @@
#!/bin/ksh
OSNAME=$(uname)
if [ "$OSNAME" = "AIX" ]
then
tar -cvf xCAT-server-2.0.tar xCAT-server-2.0
gzip xCAT-server-2.0.tar
cp xCAT-server-2.0.tar.gz /opt/freeware/src/packages/SOURCES
cd ./xCAT-server-2.0
rm /opt/freeware/src/packages/RPMS/ppc/xCAT-server-2.0*rpm
rpm -ba xCAT-server.spec
#rpm -Uvh /opt/freeware/src/packages/RPMS/ppc/xCAT-server-2.0*rpm
else
if [ -f /etc/redhat-release ]
then
pkg="redhat"
else
pkg="packages"
fi
tar czvf xCAT-server-2.0.tar.gz xCAT-server-2.0;
rm /usr/src/$pkg/RPMS/noarch/xCAT-server-2.0*rpm
rpmbuild -ta xCAT-server-2.0.tar.gz ;
#rpm -Uvh /usr/src/$pkg/RPMS/noarch/xCAT-server-2.0*rpm
fi

326
perl-xCAT-2.0/LICENSE.html Normal file
View File

@ -0,0 +1,326 @@
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=ProgId content=Word.Document>
<meta name=Generator content="Microsoft Word 9">
<meta name=Originator content="Microsoft Word 9">
<title>Eclipse Public License - Version 1.0</title>
<!--[if gte mso 9]><xml>
<o:DocumentProperties>
<o:Revision>2</o:Revision>
<o:TotalTime>3</o:TotalTime>
<o:Created>2004-03-05T23:03:00Z</o:Created>
<o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
<o:Pages>4</o:Pages>
<o:Words>1626</o:Words>
<o:Characters>9270</o:Characters>
<o:Lines>77</o:Lines>
<o:Paragraphs>18</o:Paragraphs>
<o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
<o:Version>9.4402</o:Version>
</o:DocumentProperties>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:TrackRevisions/>
</w:WordDocument>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:553679495 -2147483648 8 0 66047 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p
{margin-right:0in;
mso-margin-top-alt:auto;
mso-margin-bottom-alt:auto;
margin-left:0in;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p.BalloonText, li.BalloonText, div.BalloonText
{mso-style-name:"Balloon Text";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:8.0pt;
font-family:Tahoma;
mso-fareast-font-family:"Times New Roman";}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
</head>
<body lang=EN-US style='tab-interval:.5in'>
<div class=Section1>
<p align=center style='text-align:center'><b>Eclipse Public License - v 1.0</b>
</p>
<p><span style='font-size:10.0pt'>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE,
REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
OF THIS AGREEMENT.</span> </p>
<p><b><span style='font-size:10.0pt'>1. DEFINITIONS</span></b> </p>
<p><span style='font-size:10.0pt'>&quot;Contribution&quot; means:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
in the case of the initial Contributor, the initial code and documentation
distributed under this Agreement, and<br clear=left>
b) in the case of each subsequent Contributor:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
changes to the Program, and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
additions to the Program;</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>where
such changes and/or additions to the Program originate from and are distributed
by that particular Contributor. A Contribution 'originates' from a Contributor
if it was added to the Program by such Contributor itself or anyone acting on
such Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in conjunction
with the Program under their own license agreement, and (ii) are not derivative
works of the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Contributor&quot; means any person or
entity that distributes the Program.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Licensed Patents &quot; mean patent
claims licensable by a Contributor which are necessarily infringed by the use
or sale of its Contribution alone or when combined with the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Program&quot; means the Contributions
distributed in accordance with this Agreement.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Recipient&quot; means anyone who
receives the Program under this Agreement, including all Contributors.</span> </p>
<p><b><span style='font-size:10.0pt'>2. GRANT OF RIGHTS</span></b> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
Subject to the terms of this Agreement, each Contributor hereby grants Recipient
a non-exclusive, worldwide, royalty-free copyright license to<span
style='color:red'> </span>reproduce, prepare derivative works of, publicly
display, publicly perform, distribute and sublicense the Contribution of such
Contributor, if any, and such derivative works, in source code and object code
form.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide,<span style='color:green'> </span>royalty-free
patent license under Licensed Patents to make, use, sell, offer to sell, import
and otherwise transfer the Contribution of such Contributor, if any, in source
code and object code form. This patent license shall apply to the combination
of the Contribution and the Program if, at the time the Contribution is added
by the Contributor, such addition of the Contribution causes such combination
to be covered by the Licensed Patents. The patent license shall not apply to
any other combinations which include the Contribution. No hardware per se is
licensed hereunder. </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>c)
Recipient understands that although each Contributor grants the licenses to its
Contributions set forth herein, no assurances are provided by any Contributor
that the Program does not infringe the patent or other intellectual property
rights of any other entity. Each Contributor disclaims any liability to Recipient
for claims brought by any other entity based on infringement of intellectual
property rights or otherwise. As a condition to exercising the rights and
licenses granted hereunder, each Recipient hereby assumes sole responsibility
to secure any other intellectual property rights needed, if any. For example,
if a third party patent license is required to allow Recipient to distribute
the Program, it is Recipient's responsibility to acquire that license before
distributing the Program.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>d)
Each Contributor represents that to its knowledge it has sufficient copyright
rights in its Contribution, if any, to grant the copyright license set forth in
this Agreement. </span></p>
<p><b><span style='font-size:10.0pt'>3. REQUIREMENTS</span></b> </p>
<p><span style='font-size:10.0pt'>A Contributor may choose to distribute the
Program in object code form under its own license agreement, provided that:</span>
</p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it complies with the terms and conditions of this Agreement; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
its license agreement:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
effectively disclaims on behalf of all Contributors all warranties and
conditions, express and implied, including warranties or conditions of title
and non-infringement, and implied warranties or conditions of merchantability
and fitness for a particular purpose; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
effectively excludes on behalf of all Contributors all liability for damages,
including direct, indirect, special, incidental and consequential damages, such
as lost profits; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iii)
states that any provisions which differ from this Agreement are offered by that
Contributor alone and not by any other party; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iv)
states that source code for the Program is available from such Contributor, and
informs licensees how to obtain it in a reasonable manner on or through a
medium customarily used for software exchange.<span style='color:blue'> </span></span></p>
<p><span style='font-size:10.0pt'>When the Program is made available in source
code form:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it must be made available under this Agreement; and </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b) a
copy of this Agreement must be included with each copy of the Program. </span></p>
<p><span style='font-size:10.0pt'>Contributors may not remove or alter any
copyright notices contained within the Program. </span></p>
<p><span style='font-size:10.0pt'>Each Contributor must identify itself as the
originator of its Contribution, if any, in a manner that reasonably allows
subsequent Recipients to identify the originator of the Contribution. </span></p>
<p><b><span style='font-size:10.0pt'>4. COMMERCIAL DISTRIBUTION</span></b> </p>
<p><span style='font-size:10.0pt'>Commercial distributors of software may
accept certain responsibilities with respect to end users, business partners
and the like. While this license is intended to facilitate the commercial use
of the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create potential
liability for other Contributors. Therefore, if a Contributor includes the
Program in a commercial product offering, such Contributor (&quot;Commercial
Contributor&quot;) hereby agrees to defend and indemnify every other
Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and
costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other
legal actions brought by a third party against the Indemnified Contributor to
the extent caused by the acts or omissions of such Commercial Contributor in
connection with its distribution of the Program in a commercial product
offering. The obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In order
to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
Contributor in writing of such claim, and b) allow the Commercial Contributor
to control, and cooperate with the Commercial Contributor in, the defense and
any related settlement negotiations. The Indemnified Contributor may participate
in any such claim at its own expense.</span> </p>
<p><span style='font-size:10.0pt'>For example, a Contributor might include the
Program in a commercial product offering, Product X. That Contributor is then a
Commercial Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance claims and
warranties are such Commercial Contributor's responsibility alone. Under this
section, the Commercial Contributor would have to defend claims against the
other Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.</span> </p>
<p><b><span style='font-size:10.0pt'>5. NO WARRANTY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
responsible for determining the appropriateness of using and distributing the
Program and assumes all risks associated with its exercise of rights under this
Agreement , including but not limited to the risks and costs of program errors,
compliance with applicable laws, damage to or loss of data, programs or
equipment, and unavailability or interruption of operations. </span></p>
<p><b><span style='font-size:10.0pt'>6. DISCLAIMER OF LIABILITY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
<p><b><span style='font-size:10.0pt'>7. GENERAL</span></b> </p>
<p><span style='font-size:10.0pt'>If any provision of this Agreement is invalid
or unenforceable under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this Agreement, and without
further action by the parties hereto, such provision shall be reformed to the
minimum extent necessary to make such provision valid and enforceable.</span> </p>
<p><span style='font-size:10.0pt'>If Recipient institutes patent litigation
against any entity (including a cross-claim or counterclaim in a lawsuit)
alleging that the Program itself (excluding combinations of the Program with
other software or hardware) infringes such Recipient's patent(s), then such
Recipient's rights granted under Section 2(b) shall terminate as of the date
such litigation is filed. </span></p>
<p><span style='font-size:10.0pt'>All Recipient's rights under this Agreement
shall terminate if it fails to comply with any of the material terms or
conditions of this Agreement and does not cure such failure in a reasonable
period of time after becoming aware of such noncompliance. If all Recipient's
rights under this Agreement terminate, Recipient agrees to cease use and
distribution of the Program as soon as reasonably practicable. However,
Recipient's obligations under this Agreement and any licenses granted by
Recipient relating to the Program shall continue and survive. </span></p>
<p><span style='font-size:10.0pt'>Everyone is permitted to copy and distribute
copies of this Agreement, but in order to avoid inconsistency the Agreement is
copyrighted and may only be modified in the following manner. The Agreement
Steward reserves the right to publish new versions (including revisions) of
this Agreement from time to time. No one other than the Agreement Steward has
the right to modify this Agreement. The Eclipse Foundation is the initial
Agreement Steward. The Eclipse Foundation may assign the responsibility to
serve as the Agreement Steward to a suitable separate entity. Each new version
of the Agreement will be given a distinguishing version number. The Program
(including Contributions) may always be distributed subject to the version of
the Agreement under which it was received. In addition, after a new version of
the Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly stated
in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
the intellectual property of any Contributor under this Agreement, whether
expressly, by implication, estoppel or otherwise. All rights in the Program not
expressly granted under this Agreement are reserved.</span> </p>
<p><span style='font-size:10.0pt'>This Agreement is governed by the laws of the
State of New York and the intellectual property laws of the United States of
America. No party to this Agreement will bring a legal action under this
Agreement more than one year after the cause of action arose. Each party waives
its rights to a jury trial in any resulting litigation.</span> </p>
<p class=MsoNormal><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>
</div>
</body>
</html>

View File

@ -0,0 +1,5 @@
use ExtUtils::MakeMaker;
WriteMakefile(
'NAME' => 'xCAT',
'VERSION' => '2.0',
);

View File

@ -0,0 +1,62 @@
Summary: xCAT perl libraries
Name: perl-xCAT
Version: 2.0
Release: snap%(date +"%Y%m%d%H%M")
License: EPL
Group: System Environment/Libraries
Source: perl-xCAT-2.0.tar.gz
Packager: IBM Corp.
Vendor: IBM Corp.
Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
Prefix: %{_prefix}
BuildRoot: /var/tmp/%{name}-%{version}-%{release}-root
%ifos linux
BuildArch: noarch
%endif
Provides: perl(xCAT) = %{version}
%description
Provides perl xCAT libraries for core functionality. Required for all xCAT installations.
Includes xCAT::Table, xCAT::NodeRange, among others.
%prep
%setup -q -n perl-xCAT-%{version}
%build
perl Makefile.PL
%{__make} %{?mflags}
%install
%{__make} install DESTDIR=$RPM_BUILD_ROOT %{?mflags_install}
test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT/%{_datadir} ||:
test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT/%{_libdir}/perl5/5* ||:
find %{buildroot} -name "perllocal.pod" \
-o -name ".packlist" \
-o -name "*.bs" \
|xargs -i rm -f {}
# ndebug - this seems to break the AIX build - need to investigate
%ifos linux
find %{buildroot}%{_prefix} \
-type d -depth \
-exec rmdir {} \; 2>/dev/null
%endif
find $RPM_BUILD_ROOT -type f | sed -e "s@$RPM_BUILD_ROOT@/@" > files.list
%clean
test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT
%files -f files.list
%defattr(-, root, root)
%doc LICENSE.html
%changelog
* Wed May 2 2007 - Norm Nott nott@us.ibm.com
- Made changes to make this work on AIX
* Wed Jan 24 2007 Jarrod Johnson <jbjohnso@us.ibm.com>
-It begins

View File

@ -0,0 +1,380 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::Client;
use xCAT::NodeRange;
use IO::Socket::SSL;
use XML::Simple;
use Data::Dumper;
use Storable qw(dclone);
my $xcathost='localhost:3001';
my $plugins_dir='/usr/lib/xcat/plugins';
my %resps;
1;
#################################
# submit_request will take an xCAT command and pass it to the xCAT
# server for execution.
#
# If the XCATBYPASS env var is set, the connection to the server/daemon
# will be bypassed and the plugin will be called directly. If it is
# set to one or more directories (separated by ":"), all perl modules
# in those directories will be loaded in as plugins (for duplicate
# commands, last one in wins). If it is set to any other value
# (e.g. "yes", "default", whatever string you want) the default plugin
# directory /usr/lib/xcat/plugins will be used.
#
# Input:
# Request hash - A hash ref containing the input command and args to be
# passed to the plugin. The the xcatd daemon (or this routine when
# XCATBYPASS) reads the {noderange} entry and builds a flattened array
# of nodes that gets added as request->{node}
# The format for the request hash is:
# { command => [ 'xcatcmd' ],
# noderange => [ 'noderange_string' ],
# arg => [ 'arg1', 'arg2', '...', 'argn' ]
# }
# Callback - A subroutine ref that will be called to process the output
# from the plugin.
#
# NOTE: The request hash will get converted to XML when passed to the
# xcatd daemon, and will get converted back to a hash before being
# passed to the plugin. The XMLin ForceArray option is used to
# force all XML constructs to be arrays so that the plugin code
# and callback routines can access the data consistently.
# The input request and the response hash created by the plugin should
# always create hashes with array values.
#################################
sub submit_request {
my $request = shift;
my $callback = shift;
# If XCATBYPASS is set, invoke the plugin process_request method directly
# without going through the socket connection to the xcatd daemon
if ($ENV{XCATBYPASS}) {
# Load plugins from either specified or default dir
my %cmd_handlers;
my @plugins_dirs = split('\:',$ENV{XCATBYPASS});
if (-d $plugins_dirs[0]) {
foreach (@plugins_dirs) {
$plugins_dir = $_;
scan_plugins();
}
} else {
scan_plugins();
}
# don't do XML transformation -- assume request is well-formed
# my $xmlreq=XMLout($request,RootName=>xcatrequest,NoAttr=>1,KeyAttr=>[]);
# $request = XMLin($xmlreq,SuppressEmpty=>undef,ForceArray=>1) ;
# Call the plugin directly
# ${"xCAT_plugin::".$modname."::"}{process_request}->($request,$callback);
plugin_command($request,undef,$callback);
return 0;
}
# No XCATBYPASS, so establish a socket connection with the xcatd daemon
# and submit the request
if ($ENV{XCATHOST}) {
$xcathost=$ENV{XCATHOST};
}
my $client = IO::Socket::SSL->new(
PeerAddr => $xcathost,
SSL_key_file => $ENV{HOME}."/.xcat/client-key.pem",
SSL_cert_file => $ENV{HOME}."/.xcat/client-cert.pem",
SSL_ca_file => $ENV{HOME}."/.xcat/ca.pem",
SSL_use_cert => 1,
);
die "Connection failure: $!\n" unless ($client);
my $msg=XMLout($request,RootName=>xcatrequest,NoAttr=>1,KeyAttr=>[]);
print $client $msg;
my $response;
my $rsp;
while (<$client>) {
$response .= $_;
if ($response =~ m/<\/xcatresponse>/) {
$rsp = XMLin($response,SuppressEmpty=>undef,ForceArray=>1);
$response='';
if ($rsp->{warning}) {
printf ("Warning: ".$rsp->{warning}->[0]."\n");
}
if ($rsp->{error}) {
printf "Error: ". $rsp->{error}->[0]."\n";
}
$callback->($rsp);
if ($rsp->{serverdone}) {
last;
}
}
}
###################################
# scan_plugins
# will load all plugin perl modules and build a list of supported
# commands
#
# NOTE: This is copied from xcatd (last merge 10/3/07).
# Will eventually move to using common source....
###################################
sub scan_plugins {
my @plugins=glob($plugins_dir."/*.pm");
foreach (@plugins) {
/.*\/([^\/]*).pm$/;
my $modname = $1;
require "$_";
no strict 'refs';
my $cmd_adds=${"xCAT_plugin::".$modname."::"}{handled_commands}->();
foreach (keys %$cmd_adds) {
my $value = $_;
if (defined($cmd_handlers{$_})) {
my $add=1;
#This next bit of code iterates through the handlers.
#If the value doesn't contain an equal, and has an equivalent entry added by
# another plugin already, don't add (otherwise would hit the DB multiple times)
# a better idea, restructure the cmd_handlers as a multi-level hash
# prove out this idea real quick before doing that
foreach (@{$cmd_handlers{$_}}) {
if (($_->[1] eq $cmd_adds->{$value}) and (($cmd_adds->{$value} !~ /=/) or ($_->[0] eq $modname))) {
$add = 0;
}
}
if ($add) { push @{$cmd_handlers{$_}},[$modname,$cmd_adds->{$_}]; }
#die "Conflicting handler information from $modname";
} else {
$cmd_handlers{$_} = [ [$modname,$cmd_adds->{$_}] ];
}
}
}
}
###################################
# plugin_command
# will invoke the correct plugin
#
# NOTE: This is copied from xcatd (last merge 10/3/07).
# Will eventually move to using common source....
###################################
sub plugin_command {
my $req = shift;
my $sock = shift;
my $callback = shift;
my %handler_hash;
# use xCAT::NodeRange;
$Main::resps={};
my @nodes;
if ($req->{node}) {
@nodes = @{$req->{node}};
} elsif ($req->{noderange}) {
@nodes = noderange($req->{noderange}->[0]);
if (nodesmissed) {
# my $rsp = {errorcode=>1,error=>"Invalid nodes in noderange:".join(',',nodesmissed)};
print "Invalid nodes in noderange:".join(',',nodesmissed);
# if ($sock) {
# print $sock XMLout($rsp,RootName=>'xcatresponse' ,NoAttr=>1);
# }
# return ($rsp);
return 1;
}
}
if (@nodes) { $req->{node} = \@nodes; }
if (defined($cmd_handlers{$req->{command}->[0]})) {
my $hdlspec;
foreach (@{$cmd_handlers{$req->{command}->[0]}}) {
$hdlspec =$_->[1];
my $ownmod = $_->[0];
if ($hdlspec =~ /:/) { #Specificed a table lookup path for plugin name
my $table;
my $cols;
($table,$cols) = split(/:/,$hdlspec);
my @colmns=split(/,/,$cols);
my @columns;
my $hdlrtable=xCAT::Table->new($table);
unless ($hdlrtable) {
#TODO: proper error handling
}
my $node;
my $colvals = {};
foreach my $colu (@colmns) {
if ($colu =~ /=/) { #a value redirect to a pattern/specific name
my $coln; my $colv;
($coln,$colv) = split(/=/,$colu,2);
$colvals->{$coln} = $colv;
push (@columns,$coln);
} else {
push (@columns,$colu);
}
}
foreach $node (@nodes) {
my $attribs = $hdlrtable->getNodeAttribs($node,\@columns);
unless (defined($attribs)) { next; } #TODO: This really ought to craft an unsupported response for this request
foreach (@columns) {
my $col=$_;
if (defined($attribs->{$col})) {
if ($colvals->{$col}) { #A pattern match style request.
if ($attribs->{$col} =~ /$colvals->{$col}/) {
$handler_hash{$ownmod}->{$node} = 1;
last;
}
} else {
$handler_hash{$attribs->{$col}}->{$node} = 1;
last;
}
}
}
}
} else {
unless (@nodes) {
$handler_hash{$hdlspec} = 1;
}
foreach (@nodes) { #Specified a specific plugin, not a table lookup
$handler_hash{$hdlspec}->{$_} = 1;
}
}
}
} else {
print "$req->{command}->[0] xCAT command not found \n";
return 1; #TODO: error back that request has no known plugin for it
}
## FOR NOW, DON'T FORK CHILD PROCESS TO MAKE BYPASS SIMPLER AND EASIER TO DEBUG
# my $children=0;
# $SIG{CHLD} = sub {while (waitpid(-1, WNOHANG) > 0) { $children--; } };
# my $check_fds;
# if ($sock) {
# $check_fds = new IO::Select;
# }
foreach (keys %handler_hash) {
my $modname = $_;
if (-r $plugins_dir."/".$modname.".pm") {
require $plugins_dir."/".$modname.".pm";
# $children++;
# my $pfd; #will be referenced for inter-process messaging.
# my $child;
# if ($sock) { #If $sock not passed in, don't fork..
# socketpair($pfd, $parent_fd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!";
# #pipe($pfd,$cfd);
# $parent_fd->autoflush(1);
# $pfd->autoflush(1);
# $child = fork;
# } else {
# $child = 0;
# }
# unless (defined $child) { die "Fork failed"; }
# if ($child == 0) {
# if ($sock) { close $pfd; }
unless ($handler_hash{$_} == 1) {
my @nodes = sort {($a =~ /(\d+)/)[0] <=> ($b =~ /(\d+)/)[0] || $a cmp $b } (keys %{$handler_hash{$_}});
$req->{node}=\@nodes;
}
no strict "refs";
${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request);
# if ($sock) {
# close($parent_fd);
# exit(0);
# }
# } else {
# close $parent_fd;
# $check_fds->add($pfd);
# }
}
}
unless ($sock) { return $Main::resps };
# while ($children > 0) {
# relay_fds($check_fds,$sock);
# }
# #while (relay_fds($check_fds,$sock)) {}
# my %done;
# $done{serverdone} = {};
# if ($req->{transid}) {
# $done{transid}=$req->{transid}->[0];
# }
# if ($sock) { print $sock XMLout(\%done,RootName => 'xcatresponse',NoAttr=>1); }
}
###################################
# do_request
# called from a plugin to execute another xCAT plugin command internally
#
# NOTE: This is copied from xcatd (last merge 10/3/07).
# Will eventually move to using common source....
###################################
sub do_request {
my $req = shift;
my $second = shift;
my $rsphandler = \&build_response;
my $sock = undef;
if ($second) {
if (ref($second) eq "CODE") {
$rsphandler = $second;
} elsif (ref($second) eq "GLOB") {
$sock = $second;
}
}
#my $sock = shift; #If no sock, will return a response hash
if ($cmd_handlers{$req->{command}->[0]}) {
return plugin_command($req,$sock,$rsphandler);
} elsif ($req->{command}->[0] eq "noderange" and $req->{noderange}) {
my @nodes = noderange($req->{noderange}->[0]);
my %resp;
if (nodesmissed) {
$resp{warning}="Invalid nodes in noderange:".join ',',nodesmissed;
}
$resp{serverdone} = {};
@{$resp{node}}=@nodes;
if ($req->{transid}) {
$resp{transid}=$req->{transid}->[0];
}
if ($sock) {
print $sock XMLout(\%resp,RootName => 'xcatresponse',NoAttr=>1);
} else {
return (\%resp);
}
} else {
my %resp=(error=>"Unsupported request");
$resp{serverdone} = {};
if ($req->{transid}) {
$resp{transid}=$req->{transid}->[0];
}
if ($sock) {
print $sock XMLout(\%resp,RootName => 'xcatresponse',NoAttr=>1);
} else {
return (\%resp);
}
}
}
###################################
# build_response
# This callback handles responses from nested level plugin calls.
# It builds a merged hash of all responses that gets passed back
# to the calling plugin.
# Note: Need to create a "deep clone" of this response to add to the
# return, otherwise next time through the referenced data is overwritten
#
###################################
sub build_response {
my $rsp = shift;
foreach (keys %$rsp) {
my $subresp = dclone($rsp->{$_});
push (@{$Main::resps->{$_}}, @{$subresp});
}
}
}

277
perl-xCAT-2.0/xCAT/MacMap.pm Executable file
View File

@ -0,0 +1,277 @@
#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::MacMap;
use xCAT::Table;
use IO::Select;
use IO::Handle;
use Sys::Syslog;
use Data::Dumper;
use SNMP;
openlog("MacMap",'','local0');
my %cisco_vlans; #Special hash structure to reflect discovered VLANS on Cisco equip
#use IF-MIB (1.3.6.1.2.1.2) for all switches
# 1.3.6.1.2.1.31.1.1 - ifXtable
# 1.3.6.1.2.1.31.1.1.1.1.N = name - ifName
#Using BRIDGE-MIB for most switches( 1.3.6.1.2.1.17 )
# 1.3.6.1.2.1.17.1.4 - dot1dBasePortTable
# 1.3.6.1.2.1.17.1.4.1.1.X = N - dot1dBasePort
# 1.3.6.1.2.1.17.4.3 - dot1dTpFdbTable #FAILS on FORCE10,
#
#If particular result fails, fallback to Q-BRIDGE-MIB for Force10 (1.3.6.1.2.1.17.7)
# 1.3.6.1.2.1.17.7.1.2.2 - dot1qTpFdbTable
sub namesmatch {
=pod
MacMap attempts to do it's best to determine whether or not a particular SNMP description of
a port matches the user specified value in the configuration. Generally, if the configuration
consists of non-stacked switches without line cards, the user should only need to specify the
port number without any characters or / characters. If the configuration contains line cards
or stacked switches, use of that particular switch's appropriate / syntax in generally called
for. The exception being stacked SMC 8848 switches, in which all ports are still single
numbers, and the ports on the second switch begin at 57.
If difficulty is encountered, or a switch is attempted with a format that doesn't match any
existing rule, it is recommended to use snmpwalk on the switch with the .1.3.6.1.2.1.31.1.1.1.1
OID, and have the switch table port value match exactly the format suggested by that OID.
=cut
my $namepercfg = shift;
my $namepersnmp = shift;
if ($namepercfg eq $namepersnmp) {
return 1; # They matched perfectly
}
#Begin guessing, first off, all tested scenarios have likely correct guesses ending
#in the cfg string, with some non-numeric prefix before it.
unless ($namepersnmp =~ /[^0123456789]$namepercfg\z/) {
#Most common case, won't match at all
return 0;
}
#stop contemplating vlan, Nu, and console interfaces
if (($namepersnmp =~ /vl/i) or ($namepersnmp =~ /Nu/) or ($namepersnmp =~ /onsole/)) {
return 0;
}
#broken up for code readablitiy, don't check port channel numbers or CPU
#have to distinguish betweer Port and Po and PortChannel
if (($namepersnmp !~ /Port #/) and ($namepersnmp !~ /Port\d/) and ($namepersnmp =~ /Po/) or ($namepersnmp =~ /LAG/) or ($namepersnmp =~ /CPU/)) {
return 0;
}
#don't contemplate ManagementEthernet
if (($namepersnmp =~ /Management/)) {
return 0;
}
#The blacklist approach has been exhausted. For now, assuming that means good,
#if something ambiguous happens, the whitelist would have been:
#'Port','Port #','/' (if namepercfg has no /, then / would be...),
#'Gi','Te','GigabitEthernet','TenGigabitEthernet'
return 1;
}
sub new {
my $self = {};
my $proto = shift;
my $class = ref($proto) || $proto;
$self->{switchtab} = xCAT::Table->new('switch', -create => 1);
$self->{sitetab} = xCAT::Table->new('site');
bless ($self, $class);
return $self;
}
sub find_mac {
# This function is given a mac address, checks for given mac address
# and returns undef if unable to find the node, and the nodename otherwise
my $self = shift;
my $mac = shift;
# For now HARDCODE (TODO, configurable?) a cache as stale after five minutes
# Also, if things are changed in the config, our cache could be wrong,
# invalidate on switch table write?
if ($self->{mactable}->{lc($mac)} and ($self->{timestamp} > (time() - 300))) {
my $reftbl = 0;
foreach (keys %{$self->{mactable}}) {
if ((lc($mac) ne $_) and ($self->{mactable}->{lc($mac)} eq $self->{mactable}->{$_})) {
$reftbl = 1;
#The cache indicates confusion, flush it..
}
}
unless ($reftbl) { return $self->{mactable}->{lc($mac)};}
}
$self->refresh_table; #not cached or stale cache, refresh
if ($self->{mactable}->{lc($mac)}) {
return $self->{mactable}->{lc($mac)};
}
return undef;
}
sub refresh_table {
$self->{mactable}={};
my $self = shift;
my $community = "public";
my $tmp = $self->{sitetab}->getAttribs({key=>'snmpc'},'value');
if ($tmp and $tmp->{value}) { $community = $tmp->{value} }
else { #Would warn here..
}
my %checked_pairs;
my @entries = $self->{switchtab}->getAllNodeAttribs(['port','switch']);
#Build hash of switch port names per switch
$self->{switches} = {};
foreach $entry (@entries) {
$self->{switches}->{$entry->{switch}}->{$entry->{port}}=$entry->{node};
}
my $children = 0;
my $inputs = new IO::Select;
$SIG{CHLD}= sub { while(waitpid(-1,WNOHANG) > 0) { $children-- } };
foreach $entry (@entries) {
if ($checked_pairs{$entry->{switch}}) {
next;
}
$checked_pairs{$entry->{switch}}=1;
pipe my $child,my $parent;
$child->autoflush(1);
$parent->autoflush(1);
$children++;
$cpid = fork;
unless (defined $cpid) { die "Cannot fork" };
if ($cpid == 0) {
close($child);
$self->refresh_switch($parent,$community,$entry->{switch});
exit(0);
}
close($parent);
$inputs->add($child);
}
while($children) {
$self->handle_output($inputs);
}
while ($self->handle_output($inputs)) {}; #Drain the pipes
$self->{timestamp}=time;
}
sub handle_output {
my $self = shift;
my $inputs = shift;
my @readied = $inputs->can_read(1);
my $rc = @readied;
my $ready;
foreach $ready (@readied) {
my $line = <$ready>;
unless ($line) {
$inputs->remove($ready);
close($ready);
next;
}
$line =~ m/^([^|]*)\|(.*)/;
$self->{mactable}->{$1}=$2;
}
return $rc;
}
sub walkoid {
my $session = shift;
my $oid = shift;
my $retmap = undef;
my $varbind = new SNMP::Varbind([$oid,'']);
$session->getnext($varbind);
if ($session->{ErrorStr}) {
syslog("local6|err","Error communicating with ".$session->{DestHost}.": ".$session->{ErrorStr});
return undef;
}
my $count=0;
while ($varbind->[0] =~ /^$oid\.?(.*)/) {
$count++;
if ($1) {
$retmap->{$1.".".$varbind->[1]}=$varbind->[2]; #If $1 is set, means key should
} else {
$retmap->{$varbind->[1]}=$varbind->[2]; #If $1 is set, means key should
}
$session->getnext($varbind);
}
return $retmap;
}
sub refresh_switch {
my $self = shift;
my $output = shift;
my $community = shift;
my $switch = shift;
$session = new SNMP::Session(
DestHost => $switch,
Version => '1',
Community => $community,
UseNumeric => 1
);
#if ($error) { die $error; }
unless ($session) { syslog("err","Failed to communicate with $switch"); return; }
my $namemap = walkoid($session,'.1.3.6.1.2.1.31.1.1.1.1');
unless ($namemap) {
# walkoid errored...
return;
}
#Above is valid without community string indexing, on cisco, we need it on the next one and onward
my $iftovlanmap = walkoid($session,'.1.3.6.1.4.1.9.9.68.1.2.2.1.2');
my %vlans_to_check;
if (defined($iftovlanmap)) { #We have a cisco, the intelligent thing is to do SNMP gets on the ports
# that we can verify are populated per switch table
my $portid;
foreach $portid (keys %{$namemap}) {
my $portname;
my $switchport = $namemap->{$portid};
foreach $portname (keys %{$self->{switches}->{$switch}}) {
unless (namesmatch($portname,$switchport)) { next }
$vlans_to_check{$iftovlanmap->{$portid}} = 1;
}
}
} else {
$vlans_to_check{'NA'}=1;
}
my $vlan;
foreach $vlan (keys %vlans_to_check) {
unless ($vlan eq 'NA') {
$session = new SNMP::Session(
DestHost => $switch,
Version => '1',
Community => $community."@".$vlan,
UseNumeric => 1
);
}
unless ($session) { return; }
my $bridgetoifmap = walkoid($session,'.1.3.6.1.2.1.17.1.4.1.2'); # Good for all switches
# my $mactoindexmap = walkoid($session,'.1.3.6.1.2.1.17.4.3.1.2');
my $mactoindexmap = walkoid($session,'.1.3.6.1.2.1.17.7.1.2.2.1.2');
unless (defined($mactoindexmap)) { #if no qbridge defined, try bridge mib, probably cisco
#$mactoindexmap = walkoid($session,'.1.3.6.1.2.1.17.7.1.2.2.1.2');
$mactoindexmap = walkoid($session,'.1.3.6.1.2.1.17.4.3.1.2');
} #Ok, time to process the data
foreach my $oid (keys %$namemap) {
#$oid =~ m/1.3.6.1.2.1.31.1.1.1.1.(.*)/;
my $ifindex = $oid;
my $portname;
my $switchport = $namemap->{$oid};
foreach $portname (keys %{$self->{switches}->{$switch}}) { # a little redundant, but
# computationally trivial
unless (namesmatch($portname,$switchport)) { next }
#if still running, we have match
foreach my $boid (keys %$bridgetoifmap) {
unless ($bridgetoifmap->{$boid} == $ifindex) { next; }
my $bridgeport = $boid;
foreach (keys %$mactoindexmap) {
if ($mactoindexmap->{$_} == $bridgeport) {
my @tmp = split /\./, $_;
my @mac = @tmp[-6 .. -1];
printf $output "%02x:%02x:%02x:%02x:%02x:%02x|%s\n",@mac,$self->{switches}->{$switch}->{$portname};
}
}
}
}
}
}
}
1;

View File

@ -0,0 +1,355 @@
#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::MsgUtils;
use strict;
use locale;
use Socket;
use File::Path;
my $msgs;
my $distro;
$::XCATLOG = "/var/log/xcat";
$::NOK = -1;
$::OK = 0;
umask(0022); # This sets umask for all files so that group and world only
#--------------------------------------------------------------------------------
=head1 xCAT::MsgUtils
=head2 Package Description
This program module file, supports the xcat messaging and logging
=cut
#--------------------------------------------------------------------------------
=head2 Package Dependancies
use strict;
use Fcntl qw(:flock);
use File::Basename;
use File::Find;
use File::Path; # Provides mkpath()
=cut
#--------------------------------------------------------------------------------
=head1 Subroutines by Functional Group
=cut
=head3 message
Display a msg stdout, stderr, or a log file.
If callback routine is provide, the message will be returned to the callback
routine and logged, if logging is requested.
This function is primarily meant for commands and other code that is sending
output directly to the user. Even the log is really a capture of this
interactive output.
Arguments:
The arguments of the message() function are:
if $::VERBOSE is set, the message will be displayed.
If $::LOG_FILE_HANDLE is set, the message goes to both
the screen and that log file. (Verbose msgs will be sent to
the log file even if $::VERBOSE is not set.)
A timestamp will automatically be put in front on any message
that is logged unless the T option is specified.
if address of the call_back is provided,
then the message will be returned
as data to the call_back routine.
- The argument is the message to be displayed/logged.
Here's the meaning of the 1st character:
I - informational goes to stdout
E - error. This type of message will be sent to stderr.
V - verbose. This message should only be displayed,
if $::VERBOSE is set.
T - Do not log timestamp,
If $::LOG_FILE_HANDLE is set, the message goes to both
the screen and that log file. (Verbose msgs will be sent to
the log file even if $::VERBOSE is not set.)
A timestamp will automatically be put in front on any message
that is logged.
Optionally a T can be put before any of the above characters
"not" put a timestamp on
before the message when it is logged.
Note: T must be the first character.
Returns:
none
Error:
_none
Example:
xCAT::MsgUtils->message('E', "Operation $value1 failed\n");
Use of T flag
xCAT::MsgUtils->message('TI', "Operation $value1 failed\n");
Use of callback
xCAT::MsgUtils->message('I', $rsp,$call_back);
where $rsp is a data response structure for the callback function
Comments:
Returns:
none
=cut
#--------------------------------------------------------------------------------
sub message
{
# Process the arguments
shift; # get rid of the class name
my $sevcode = shift;
my $msg = shift;
my $call_back = shift; # optional
# Parse the severity code
my $i = 1;
my $notimestamp = 0;
my $sev = substr($sevcode, 0, 1);
# should be I, E, V, T
if ($sev eq 'T') # do not put timestamp
{
$notimestamp = 1; # no timestamp
$i = 2; # logically shift everything by 1 char
$sev = substr($sevcode, 1, 1); # now should be either I,E,V
}
my $stdouterrf = \*STDOUT;
my $stdouterrd = '';
if (my $sev =~ /[E]/)
{
$stdouterrf = \*STDERR;
$stdouterrd = '1>&2';
}
if (defined($::LOG_FILE_HANDLE))
{
if ($notimestamp == 0)
{ # print a timestamp
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
localtime(time);
my $time = $hour . ":" . $min . ":" . $sec . " ";
print $::LOG_FILE_HANDLE $time;
print $::LOG_FILE_HANDLE " ";
}
print $::LOG_FILE_HANDLE $msg;
}
# if V option and $::VERBOSE set or not V option then display
# Note Verbose messages, will be thrown away if verbose is not
# turned on and there is no logging.
if (($sev eq 'V' && $::VERBOSE) || ($sev ne 'V'))
{
if ($::DSH_API)
{
$::DSH_API_MESSAGE = $::DSH_API_MESSAGE . $msg;
}
else
{
if ($call_back) { # callback routine provided
$call_back->($msg);
} else {
print $stdouterrf $msg; # print the message
}
}
}
return 0;
}
#--------------------------------------------------------------------------------
=head2 Message Logging Routines
=cut
#--------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
=head3 backup_logfile
Backup the current logfile. Move logfile to logfile.1. Shift all other logfiles
(logfile.[1-3]) up one number. The original logfile.4 is removed as in a FIFO.
Arguments:
$logFileName
Returns:
$::OK
Error:
undefined
Example:
xCAT::MsgUtils->backup_logfile($logfile);
Comments:
Never used outside of ServerUtils.
=cut
#--------------------------------------------------------------------------------
sub backup_logfile
{
my ($class, $logfile) = @_;
my ($logfile1) = $logfile . ".1";
my ($logfile2) = $logfile . ".2";
my ($logfile3) = $logfile . ".3";
my ($logfile4) = $logfile . ".4";
if (-f $logfile)
{
rename($logfile3, $logfile4) if (-f $logfile3);
rename($logfile2, $logfile3) if (-f $logfile2);
rename($logfile1, $logfile2) if (-f $logfile1);
rename($logfile, $logfile1);
}
return $::OK;
}
#--------------------------------------------------------------------------------
=head3 start_logging
Start logging messages to a logfile. Return the log file handle so it
can be used to close the file when done logging.
Arguments:
$logFile
Returns:
$::LOG_FILE_HANDLE
Globals:
$::LOG_FILE_HANDLE
$::XCATLOG
Error:
$::NOK
Example:
xCAT::MsgUtils->start_logging($cfmupdatenode.log);
Comments:
Common method for logging script runtime output.
=cut
#--------------------------------------------------------------------------------
sub start_logging
{
my ($class, $logfile) = @_;
my ($cmd, $rc);
xCAT::MsgUtils->backup_logfile($logfile);
# create the log directory if it's not already there
if (!-d $::XCATLOG)
{
mkdir($::XCATLOG, 0755);
}
# open the log file
unless (open(LOGFILE, ">>$logfile"))
{
# Cannot open file
xCAT::MsgUtils->message("E", "Cannot open file: $logfile.\n");
return $::NOK;
}
$::LOG_FILE_HANDLE = \*LOGFILE;
# Print the date to the top of the logfile
my $sdate = localtime(time);
chomp $sdate;
my $program = xCAT::Utils->programName();
xCAT::MsgUtils->message(
"TV",
"#--------------------------------------------------------------------------#\n"
);
xCAT::MsgUtils->message("TV", "$program: Logging Started:$sdate\n");
xCAT::MsgUtils->message("TV", "Input: $::command_line\n");
xCAT::MsgUtils->message(
"TV",
"#--------------------------------------------------------------------------#\n"
);
return ($::LOG_FILE_HANDLE);
}
#--------------------------------------------------------------------------------
=head3 stop_logging
Turn off message logging close file. Routine expects to have a file handle
passed in via the global $::LOG_FILE_HANDLE.
Arguments:
Returns:
$::OK
Globals:
$::LOG_FILE_HANDLE
Error:
none
Example:
xCAT::MsgUtils->stop_logging($cfmupdatenode.log);
Comments:
closes the logfile and undefines $::LOG_FILE_HANDLE
even on error.
=cut
#--------------------------------------------------------------------------------
sub stop_logging
{
my ($class) = @_;
if (defined($::LOG_FILE_HANDLE))
{
my $sdate = localtime(time);
chomp $sdate;
my $program = xCAT::Utils->programName();
xCAT::MsgUtils->message(
"TV",
"#--------------------------------------------------------------------------#\n"
);
xCAT::MsgUtils->message("TV", "$program: Logging Stopped: $sdate\n");
xCAT::MsgUtils->message(
"TV",
"#--------------------------------------------------------------------------#\n"
);
close($::LOG_FILE_HANDLE);
undef $::LOG_FILE_HANDLE;
}
return $::OK;
}
1;

View File

@ -0,0 +1,325 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::NodeRange;
use xCAT::Table;
use Data::Dumper;
require Exporter;
use strict;
#Perl implementation of noderange
our @ISA = qw(Exporter);
our @EXPORT = qw(noderange nodesmissed);
my $missingnodes=[];
my $nodelist; #=xCAT::Table->new('nodelist',-create =>1);
my $nodeprefix = "node";
sub subnodes (\@@) {
#Subtract set of nodes from the first list
my $nodes = shift;
my $node;
foreach $node (@_) {
@$nodes = (grep(!/^$node$/,@$nodes));
}
}
sub nodesmissed {
return @$missingnodes;
}
sub expandatom {
my $atom = shift;
my $verify = (scalar(@_) == 1 ? shift : 1);
my @nodes= ();
my $nprefix=(defined ($ENV{'XCAT_NODE_PREFIX'}) ? $ENV{'XCAT_NODE_PREFIX'} : 'node');
my $nsuffix=(defined ($ENV{'XCAT_NODE_SUFFIX'}) ? $ENV{'XCAT_NODE_PREFIX'} : '');
if ($nodelist->getAttribs({node=>$atom},'node')) {
#The atom is a plain old nodename
return ($atom);
}
if ($atom =~ /^\(.*\)$/) {
$atom =~ s/^\((.*)\)$/$1/;
return noderange($atom);
}
foreach($nodelist->getAllAttribsWhere("groups like '%".$atom."%'",'node','groups')) {
my @groups=split(/,/,$_->{groups}); #The where clause doesn't guarantee the atom is a full group name, only that it could be
if (grep { $_ eq "$atom" } @groups ) {
push @nodes,$_->{node};
}
}
if ($atom =~ m/^[0-9]+\z/) {
my $nodename=$nprefix.$atom.$nsuffix;
return expandatom($nodename,$verify);
}
my $nodelen=@nodes;
if ($nodelen > 0) {
return @nodes;
}
if ($atom =~ m/(.*)\[(.*)\](.*)/) { #bracket range
#for the time being, we are only going to consider one [] per atom
#xcat 1.2 does no better
my @subelems = split(/([\,\-\:])/,$2);
my $subrange="";
while (my $subelem = shift @subelems) {
my $subop=shift @subelems;
$subrange=$subrange."$1$subelem$3$subop";
}
foreach (split /,/,$subrange) {
my @newnodes=expandatom($_,$verify);
@nodes=(@nodes,@newnodes);
}
return @nodes;
}
if ($atom =~ m/\+/) {#process + operator
$atom =~ m/^([^0-9]*)([0-9]+)([^\+]*)\+([0-9]+)/;
my $pref=$1;
my $startnum=$2;
my $suf=$3;
my $end=$4+$startnum;
my $endnum = sprintf("%d",$end);
if (length ($startnum) > length ($endnum)) {
$endnum = sprintf("%0".length($startnum)."d",$end);
}
if (($pref eq "") && ($suf eq "")) {
$pref=$nprefix;
$suf=$nsuffix;
}
foreach ("$startnum".."$endnum") {
my @addnodes=expandatom($pref.$_.$suf,$verify);
@nodes=(@nodes,@addnodes);
}
return (@nodes);
}
if ($atom =~ m/[-:]/) {#process - range operator
my $left;
my $right;
if ($atom =~ m/:/) {
($left,$right)=split /:/,$atom;
} else {
my $count= ($atom =~ tr/-//);
if (($count % 2)==0) { #can't understand even numbers of - in range context
if ($verify) {
push @$missingnodes,$atom;
return ();
} else { #but we might not really be in range context, if noverify
return ($atom);
}
}
my $expr="([^-]+?".("-[^-]*"x($count/2)).")-(.*)";
$atom =~ m/$expr/;
$left=$1;
$right=$2;
}
if ($left eq $right) { #if they said node1-node1 for some strange reason
return expandatom($left,$verify);
}
my @leftarr=split(/(\d+)/,$left);
my @rightarr=split(/(\d+)/,$right);
if (scalar(@leftarr) != scalar(@rightarr)) { #Mismatch formatting..
if ($verify) {
push @$missingnodes,$atom;
return (); #mismatched range, bail.
} else { #Not in verify mode, just have to guess it's meant to be a nodename
return ($atom);
}
}
my $prefix = "";
my $suffix = "";
foreach (0..$#leftarr) {
my $idx = $_;
if ($leftarr[$idx] =~ /^\d+$/ and $rightarr[$idx] =~ /^\d+$/) { #pure numeric component
if ($leftarr[$idx] ne $rightarr[$idx]) { #We have found the iterator (only supporting one for now)
my $prefix = join('',@leftarr[0..($idx-1)]); #Make a prefix of the pre-validated parts
my $luffix; #However, the remainder must still be validated to be the same
my $ruffix;
if ($idx eq $#leftarr) {
$luffix="";
$ruffix="";
} else {
$ruffix = join('',@rightarr[($idx+1)..$#rightarr]);
$luffix = join('',@leftarr[($idx+1)..$#leftarr]);
}
if ($luffix ne $ruffix) { #the suffixes mismatched..
if ($verify) {
push @$missingnodes,$atom;
return ();
} else {
return ($atom);
}
}
foreach ($leftarr[$idx]..$rightarr[$idx]) {
my @addnodes=expandatom($prefix.$_.$luffix,$verify);
@nodes=(@nodes,@addnodes);
}
return (@nodes); #the return has been built, return, exiting loop and all
}
} elsif ($leftarr[$idx] ne $rightarr[$idx]) {
if ($verify) {
push @$missingnodes,$atom;
return ();
} else {
return ($atom);
}
}
$prefix .= $leftarr[$idx]; #If here, it means that the pieces were the same, but more to come
}
#I cannot conceive how the code could possibly be here, but whatever it is, it must be questionable
if ($verify) {
push @$missingnodes,$atom;
return (); #mismatched range, bail.
} else { #Not in verify mode, just have to guess it's meant to be a nodename
return ($atom);
}
}
if ($atom =~ m/^\//) { #A regex
unless ($verify) { #If not in verify mode, regex makes zero possible sense
return ($atom);
}
#TODO: check against all groups
$atom = substr($atom,1);
foreach ($nodelist->getAllAttribs('node')) {
if ($_->{node} =~ m/^${atom}$/) {
push(@nodes,$_->{node});
}
}
return(@nodes);
}
push @$missingnodes,$atom;
if ($verify) {
return ();
} else {
return ($atom);
}
}
sub noderange {
$missingnodes=[];
#We for now just do left to right operations
#TODO: Parentheses... A parenthetical group to the right of an intersection makes the obvious
#answer not work
my $range=shift;
my $verify = (scalar(@_) == 1 ? shift : 1);
$nodelist =xCAT::Table->new('nodelist',-create =>1);
my %nodes = ();
my %delnodes = ();
my $op = ",";
#my @elems = split(/(,(?![^[]*?])|@)/,$range); #, or @ but ignore , within []
my @elems = split(/(,(?![^[]*?])(?![^\(]*?\))|@(?![^\(]*?\)))/,$range); #, or @ but ignore , within []
while (my $atom = shift @elems) {
if ($atom =~ /^-/) {
$atom = substr($atom,1);
$op = $op."-";
}
if ($atom =~ /^\^(.*)$/) {
open(NRF,$1);
while (<NRF>) {
my $line=$_;
unless ($line =~ m/^[\^#]/) {
$line =~ m/^([^: ]*)/;
my $newrange = $1;
chomp($newrange);
my @filenodes = noderange($newrange);
foreach (@filenodes) {
$nodes{$_}=1;
}
}
}
close(NRF);
next;
}
my %newset = map { $_ =>1 } expandatom($atom,$verify);
if ($op =~ /@/) {
foreach (keys %nodes) {
unless ($newset{$_}) {
delete $nodes{$_};
}
}
} elsif ($op =~ /,-/) {
foreach (keys %newset) {
$delnodes{$_}=1; #delay removal to end
}
} else {
foreach (keys %newset) {
$nodes{$_}=1;
}
}
$op = shift @elems;
}
foreach (keys %nodes) {
if ($delnodes{$_}) {
delete $nodes{$_};
}
}
undef $nodelist;
return sort (keys %nodes);
}
1;
=head1 NAME
xCAT::NodeRange - Perl module for xCAT noderange expansion
=head1 SYNOPSIS
use xCAT::NodeRange;
my @nodes=noderange("storage@rack1,node[1-200],^/tmp/nodelist,node300-node400,node401+10,500-550");
=head1 DESCRIPTION
noderange interprets xCAT noderange formatted strings and returns a list of xCAT nodelists. The following two operations are supported on elements, and interpreted left to right:
, union next element with everything to the left.
@ take intersection of element to the right with everything on the left (i.e. mask out anything to the left not belonging to what is described to the right)
Each element can be a number of things:
A node name, i.e.:
=item * node1
A hyphenated node range (only one group of numbers may differ between the left and right hand side, and those numbers will increment in a base 10 fashion):
node1-node200 node1-compute-node200-compute
node1:node200 node1-compute:node200-compute
A noderange denoted by brackets:
node[1-200] node[001-200]
A regular expression describing the noderange:
/d(1.?.?|200)
A node plus offset (this increments the first number found in nodename):
node1+199
And most of the above substituting groupnames.
3C
3C
NodeRange tries to be intelligent about detecting padding, so you can:
node001-node200
And it will increment according to the pattern.
=head1 AUTHOR
Jarrod Johnson (jbjohnso@us.ibm.com)
=head1 COPYRIGHT
Copyright 2007 IBM Corp. All rights reserved.
TODO: What license is this?
=cut

View File

@ -0,0 +1,334 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::NotifHandler;
use File::Basename qw(fileparse);
#%notif is a cache that holds the info from the "notification" table.
#the format of it is:
# {tablename=>{'a'=>[filename,...]
# 'u'=>[filename,,..]
# 'd'=>[filename,...]
# }
# }
%notif;
$masterpid=$$;
1;
#-------------------------------------------------------------------------------
=head1 xCATi::NotifHandler
=head2 Package Description
This mondule caches the notification table and tracks the changes of it.
It also handles the event notification when xCAT database changes.
=cut
#-------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
=head3 setup
It is called by xcatd to get set the pid of the parent of all this object.
Setup the signal to trap any changes in the notification table. It also
initializes the cache with the current data in the notification table.
table and store it into %notif variable.
Arguments:
pid -- the process id of the caller.
Returns:
none
=cut
#-------------------------------------------------------------------------------
sub setup
{
$masterpid=shift;
if ($masterpid =~ /xCAT::NotifHandler/) {
$masterpid=shift;
}
refreshNotification();
$SIG{USR1}=\&handleNotifSigal;
}
#--------------------------------------------------------------------------------
=head3 handleNotifSigal
It is called when the signal is received. It then update the cache with the
latest data in the notification table.
Arguments:
none.
Returns:
none
=cut
#-------------------------------------------------------------------------------
sub handleNotifSigal {
refreshNotification();
$SIG{USR1}=\&handleNotifSigal;
}
#--------------------------------------------------------------------------------
=head3 sendNotifSignal
It is called by any module that has made changes to the notification table.
Arguments:
none.
Returns:
none
=cut
#-------------------------------------------------------------------------------
sub sendNotifSignal {
kill('USR1', $masterpid);
}
#--------------------------------------------------------------------------------
=head3 refreshNotification
It loads the notification info from the "notification"
table and store it into %notif variable.
The format of it is:
{tablename=>{filename=>{'ops'=>['y/n','y/n','y/n'], 'disable'=>'y/n'}}}
Arguments:
none
Returns:
none
=cut
#-------------------------------------------------------------------------------
sub refreshNotification
{
#flush the cache
%notif=();
my $table=xCAT::Table->new("notification", -create =>0);
if ($table) {
#get array of rows out of the notification table
my @row_array= $table->getTable;
if (@row_array) {
#store the information to the cache
foreach(@row_array) {
my $module=$_->{filename};
my $ops=$_->{tableops};
my $disable= $_->{disable};
my @tablenames=split(/,/, $_->{tables});
foreach(@tablenames) {
if (!exists($notif{$_})) {
$notif{$_}={};
}
my $tempdisable=0;
if ($disable) {
if ($disable =~ m/^(yes|YES|Yes|Y|y|1)$/) {
$tempdisable=1;
}
}
if (!$disable) {
if ($ops) {
if ($ops =~ m/a/) {
if (exists($notif{$_}->{a})) {
my $pa=$notif{$_}->{a};
push(@$pa, $module);
} else {
$notif{$_}->{a}=[$module];
}
}
if ($ops =~ m/d/) {
if (exists($notif{$_}->{d})) {
my $pa=$notif{$_}->{d};
push(@$pa, $module);
} else {
$notif{$_}->{d}=[$module];
}
}
if ($ops =~ m/u/) {
if (exists($notif{$_}->{u})) {
my $pa=$notif{$_}->{u};
push(@$pa, $module);
} else {
$notif{$_}->{u}=[$module];
}
}
} #end if
}
} #end foreach
} #end foreach(@row_array)
}end if (@row_array)
} #end if ($table)
return 1;
}
#--------------------------------------------------------------------------------
=head3 dumpNotificationCache
It print out the content of the notification cache for debugging purpose.
Arguments:
none
Returns:
0
=cut
#-------------------------------------------------------------------------------
sub dumpNotificationCache {
print "dump the notification cache:\n";
foreach(keys(%notif)) {
my $tmptn=$_;
print " $tmptn: \n";
if (exists($notif{$_}->{a})) {
print " a--:";
my $files=$notif{$_}->{a};
print "@$files\n";
}
if (exists($notif{$_}->{u})) {
print " u--:";
my $files=$notif{$_}->{u};
print "@$files\n";
}
if (exists($notif{$_}->{d})) {
print " d--:";
my $files=$notif{$_}->{d};
print "@$files\n";
}
}
return 0;
}
#--------------------------------------------------------------------------------
=head3 needToNotify
It check if the given table has interested parties watching for its changes.
Arguments:
tablename - the name of the table to be checked.
tableop - the operation on the table. 'a' for add, 'u' for update
and 'd' for delete.
Returns:
1 - if the table has interested parties.
0 - if no parties are interested in its changes.
=cut
#-------------------------------------------------------------------------------
sub needToNotify {
if (!defined %notif) {
# print "notif not defined\n";
refreshNotification();
}
my $tablename=shift;
if ($tablename =~ /xCAT::NotifHandler/) {
$tablename=shift;
}
my $tableop=shift;
if (%notif) {
if (exists($notif{$tablename})) {
if (exists($notif{$tablename}->{$tableop})) {
return 1;
}
}
}
return 0;
}
#--------------------------------------------------------------------------------
=head3 notify
It notifies the registered the modules with the latest changes in
a DB table.
Arguments:
action - table action. It can be d for rows deleted, a for rows added
or u for rows updated.
tablename - string. The name of the DB table whose data has been changed.
old_data - an array reference of the old row data that has been changed.
The first element is an array reference that contains the column names.
The rest of the elelments are also array references each contains
attribute values of a row.
It is set when the action is u or d.
new_data - a hash refernce of new row data; only changed values are present
in the hash. It is keyed by column names.
It is set when the action is u or a.
Returns:
0
Comments:
If the curent table is watched by a perl module, the module must implement
the following routine:
processTableChanges(action, table_name, old_data, new_data)
If it is a watched by a command, the data will be passed to the command
through STDIN. The format is:
action
table_name
[old data]
col1_name,col2_name,...
col1_value,col2_value,...
...
[new data]
col1_name,col2_name,...
col1_value,col2_value,...
...
=cut
#-------------------------------------------------------------------------------
sub notify {
my $action=shift;
if ($action =~ /xCAT::NotifHandler/) {
$action=shift;
}
my $tablename=shift;
my $old_data=shift;
my $new_data=shift;
# print "notify called: tablename=$tablename, action=$action\n";
my @filenames=();
if (%notif) {
if (exists($notif{$tablename})) {
if (exists($notif{$tablename}->{$action})) {
my $pa=$notif{$tablename}->{$action};
@filenames=@$pa;
}
}
}
foreach(@filenames) {
my ($modname, $path, $suffix) = fileparse($_, ".pm");
# print "modname=$modname, path=$path, suffix=$suffix\n";
if ($suffix =~ /.pm/) { #it is a perl module
my $pid;
if ($pid=fork()) { }
elsif (defined($pid)) {
if (($path eq "") || ($path eq ".\/")) {
#default path is /usr/lib/xcat/monitoring/ if there is no path specified
require "/usr/lib/xcat/monitoring/".$modname.".pm";
} else {
require $_;
}
${"xCAT_monitoring::".$modname."::"}{processTableChanges}->($action, $tablename, $old_data, $new_data);
exit 0;
}
}
else { #it is a command
my $pid;
if ($pid=fork()) { }
elsif (defined($pid)) {
# print "command=$_\n";
if (open(CMD, "|$_")) {
print(CMD "$action\n");
print(CMD "$tablename\n");
print(CMD "[old data]\n");
foreach (@$old_data) {
print(CMD join(',', @$_)."\n");
}
print(CMD "[new data]\n");
if (%$new_data) {
print(CMD join(',', keys %$new_data) . "\n");
print(CMD join(',', values %$new_data) . "\n");
}
close(CMD) or print "Cannot close the command $_\n";
}
else {
print "Command $_ cannot be found\n";
}
exit 0;
} #elsif
}
} #foreach
return 0;
}

View File

@ -0,0 +1,297 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::Postage;
use xCAT::Table;
use xCAT::NodeRange;
use Data::Dumper;
my $depsfile = "/etc/xcat/postscripts.dep";
my $rulesfile = "/etc/xcat/postscripts.rules";
my $rules;
my $deps;
my $rulec;
my $node;
sub writescript {
if (scalar(@_) eq 3) { shift; } #Discard self
$node = shift;
my $scriptfile = shift;
my $script;
open($rules,"<",$rulesfile);
open($deps,"<",$depsfile);
unless($rules) {
return undef;
}
open($script,">",$scriptfile);
unless ($scriptfile) {
return undef;
}
#Some common variables...
my $noderestab=xCAT::Table->new('noderes');
my $typetab=xCAT::Table->new('nodetype');
unless ($noderestab and $typetab) {
die "Unable to open noderes or nodetype table";
}
my $master;
my $sitetab = xCAT::Table->new('site');
(my $et) = $sitetab->getAttribs({key=>"master"},'value');
if ($et and $et->{value}) {
$master = $et->{value};
}
$et = $noderestab->getNodeAttribs($node,['xcatmaster']);
if ($et and $et->{'xcatmaster'}) {
$master = $et->{'xcatmaster'};
}
unless ($master) {
die "Unable to identify master for $node";
}
print $script "MASTER=".$master."\n";
print $script "export MASTER\n";
my $et = $typetab->getNodeAttribs($node,['os','arch']);
unless ($et and $et->{'os'} and $et->{'arch'}) {
die "No os/arch setting in nodetype table for $node";
}
print $script "OSVER=".$et->{'os'}."\n";
print $script "ARCH=".$et->{'arch'}."\n";
print $script "export OSVER ARCH\n";
print $script 'PATH=`dirname $0`:$PATH'."\n";
print $script "export PATH\n";
$rulec="";
my @scripts;
my $inlist = 0;
my $pushmode = 0;
my $critline="";
while (<$rules>) {
my $line = $_;
$line =~ s/^\s*//;
$line =~ s/\s*$//;
$line =~ s/#.*//;
if ($line =~ /^$/) {
next;
}
# we are left with content lines..
my $donewithline=0;
while (not $donewithline) {
if ($line =~ /^\s*$/) {
$donewithline=1;
next;
}
if ($inlist) {
if ($line =~/^[^\}]*\{/) {
#TODO: error unbalanced {} in postscripts.rules
die "Unbalanced {}";
return undef;
}
if ($pushmode) {
my $toadd;
($toadd) = $line =~ /(^[^\}]*)/;
$line =~ s/(^[^\}]*)//;
unless ($toadd =~ /^\s*$/) {
push @scripts,$toadd;
}
} else { #strip non } characters leading
$line =~ s/^[^\}]*//;
}
if ($line =~ /\}/) {
$line =~ s/\}//;
$inlist=0;
}
} else {
if ($line =~/^[^\{]*\}/) {
#TODO: error unbalanced {} in postscripts.rules
return undef;
}
(my $tcritline) = $line =~ /^([^\{]*)/;
$critline .= $tcritline . " ";
if ($line =~ /\{/) {
if (criteriamatches($critline)) {
$pushmode=1;
} else {
$pushmode=0;
}
$critline = "";
$inlist = 1;
$line =~ s/[^\{]*\{//;
} else {
$donewithline=1;
}
}
}
}
foreach (@scripts) {
print $script $_."\n";
}
close($script);
chmod 0755,$scriptfile;
}
#shamelessly brought forth from postrules.pl in xCAT 1.3
sub criteriamatches {
my $cline = shift;
my $level=0;
my $pline;
my @opstack;
my @expstack;
my $r;
$cline =~ s/\{//g;
$cline =~ s/(\(|\))/ $1 /g;
$cline =~ s/\s*=\s*/=/g;
$cline =~ s/^\s*//;
$cline =~ s/\s*$//;
$cline =~ s/\s+/ /;
if ($cline =~ /^ALL$/) {
return 1;
}
my @tokens = split('\s+',$cline);
my $token;
foreach $token (@tokens) {
if ($token eq ')') {
$level--;
if ($level == 0) {
push @expstack,criteriamatches($pline);
$pline="";
next;
} elsif ($level < 0) {
die "Unbalanecd () in postrules";
}
}
if ($level) {
$pline .= " $token";
}
if ($token eq '(') {
$level++;
next;
}
if ($level) {
next;
}
if ($token =~ /=/) {
push(@expstack,$token);
next;
}
if ($token =~ /^(and|or|not)$/i) {
push (@opstack,$token);
next;
}
die "Syntax error in postscripts rules, bad token $token";
}
if ($level) {
die "Unbalanced () in postscripts rules";
}
while (@opstack) {
my $op;
my $r1 = 0;
my $r2 = 0;
$op = pop(@opstack);
unless (defined $op) {
die "Stack underflow in postscripts rules";
}
if ($op =~ /and/i) {
$r1 = popeval(\@expstack);
$r2 = popeval(\@expstack);
if ($r1 && $r2) {
push(@expstack,1);
} else {
push(@expstack,0);
}
} elsif ($op =~ /or/i) {
$r1 = popeval(\@expstack);
$r2 = popeval(\@expstack);
if ($r1 || $r2) {
push(@expstack,1);
} else {
push(@expstack,0);
}
} elsif ($op =~ /not/i) {
$r1 = popeval(\@expstack);
if ($r1==0) {
push(@expstack,1);
} else {
push (@expstack,0);
}
}
}
if (@expstack == 1) {
$r = popeval(\@expstack);
push(@expstack,$r);
}
$r = pop(@expstack);
unless (defined $r) {
die "Stack underflow in postscripts processing";
}
if (@expstack != 0 || @opstack != 0) {
die "Stack underflow in postscripts processing";
}
return $r;
}
sub popeval {
my ($expstack) = @_;
my $exp;
my $v;
my $r;
$exp = pop(@$expstack);
if (defined ($exp)) {
if ($exp =~ /=/) {
my @eqarr = split(/=/,$exp);
$r = $eqarr[$#eqarr];
$v = join('=',@eqarr[0..($#eqarr-1)]);
#($v,$r) = split(/=/,$exp);
if ($v =~ /^OSVER$/) { #OSVER is redundant, but a convenient shortcut
$v = 'TABLE:nodetype:$NODE:os';
}
if ($v =~ /^NODERANGE$/i) {
my @nr = noderange $r;
foreach (@nr) {
if ($node eq $_) {
return 1;
}
}
return 0;
}
if ($v =~ /^TABLE:/) {
my $table;
my $key;
my $field;
($table,$key,$field) = $v =~ m/TABLE:([^:]+):([^:]+):(.*)/;
my $tabref = xCAT::Table->new($table);
unless ($tabref) { return 0; }
my $ent;
if ($key =~ /^\$NODE/) {
$ent = $tabref->getNodeAttribs($node,[$field]);
} else {
my @keys = split /,/,$key;
my %keyh;
foreach (@keys) {
my $keycol;
my $keyval;
($keycol,$keyvol)=split /=/,$_;
$keyh{$keycol}=$keyvol;
}
($ent)=$tabref->getAttribs(\%keyh,$field);
}
unless ($ent and $ent->{$field}) { return 0; }
if ($ent->{$field} =~ /^$r$/) {
return 1;
} else {
return 0;
}
}
#TODO? support for env vars? Don't see much of a point now, but need input
} elsif ($exp == 0 || $exp == 1) {
return ($exp);
} else {
die "Invalid expression $exp in postcripts rules";
}
} else {
die "Stack underflow in postscripts rules...";
}
}
1;

View File

@ -0,0 +1,347 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::Schema;
#Note that the SQL is far from imaginative. Fact of the matter is that
#certain SQL backends don't ascribe meaning to the data types anyway.
#New format, not sql statements, but info enough to describe xcat tables
%tabspec = (
nodetype => {
cols => [qw(node os arch profile comments disable)],
keys => [qw(node)],
},
nodepos => {
cols => [qw(node rack u chassis slot room comments disable)],
keys => [qw(node)],
},
vpd => {
cols => [qw(node serial mtm comments disable)],
keys => [qw(node)],
},
nodehm => {
cols => [qw(node power mgt cons termserver termport conserver serialspeed serialflow getmac comments disable)],
keys => [qw(node)],
},
hosts => {
cols => [qw(node ip hostnames comments disable)],
keys => [qw(node)],
},
mp => {
cols => [qw(node mpa id comments disable)],
keys => [qw(node)],
},
mpa => {
cols => [qw(mpa username password comments disable)],
keys => [qw(mpa)],
},
mac => {
cols => [qw(node interface mac comments disable)],
keys => [qw(node interface)],
},
chain => {
cols => [qw(node currstate currchain chain ondiscover comments disable)],
keys => [qw(node)],
},
noderes => {
cols => [qw(node servicenode netboot tftpserver nfsserver kernel initrd kcmdline nfsdir serialport installnic primarynic xcatmaster current_osimage next_osimage comments disable)],
keys => [qw(node)],
},
networks => {
cols => [qw(netname net mask gateway dhcpserver tftpserver nameservers dynamicrange comments disable)],
keys => [qw(net mask)]
},
switch => {
cols => [qw(node switch vlan port comments disable)],
keys => [qw(node switch port)]
},
nodelist => {
cols => [qw(node nodetype groups comments disable)],
keys => [qw(node)],
},
site => {
cols => [qw(key value comments disable)],
keys => [qw(key)]
},
passwd => {
cols => [qw(key username password comments disable)],
keys => [qw(key)]
},
ipmi => {
cols => [qw(node bmc username password comments disable )],
keys => [qw(node)]
},
policy => {
cols => [qw(priority name host commands noderange parameters time rule comments disable)],
keys => [qw(priority)]
},
notification => {
cols => [qw(filename tables tableops comments disable)],
keys => [qw(filename)],
required => [qw(tables filename)]
}
);
####################################################
#
# Data abstraction definitions
# For each table entry added to the database schema,
# a corresponding attribute should be added to one of
# the data objects below, or new data objects should
# be created as needed.
#
# Definition format:
# List of data object hashes:
# <dataobject_name> =>
# {attrs =>
# [ {attr_name => '<attribute_name>',
# only_if => '<attr>=<value>',
# # optional, used to define conditional attributes.
# # <attr> is a previously resolved attribute from
# # this data object.
# tabentry => '<table.attr>',
# # where the data is stored in the database
# access_tabentry => '<table.attr>=<value>',
# # how to look up tabentry. For <value>,
# # if "attr:<attrname>", use a previously resolved
# # attribute value from the data object
# # if "str:<value>" use the value directly
# description => '<description of this attribute>',
# },
# {attr_name => <attribute_name>,
# ...
# } ],
# attrhash => {}, # internally generated hash of attrs array
# # to allow code direct access to an attr def
# objkey => 'attribute_name' # key attribute for this data object
# }
#
#
####################################################
%defspec = (
node => { attrs => [], attrhash => {}, objkey => 'node' },
osimage => { attrs => [], attrhash => {}, objkey => 'imagename' },
network => { attrs => [], attrhash => {}, objkey => 'netname' },
site => { attrs => [], attrhash => {}, objkey => 'master' }
);
#############
# TODO: Need to figure out how to map the following to data objects:
# nodetype table (does this get moved to the osimage table?)
# --> do we need an arch attr per node that is stored in nodehm?
# mac table (are we going to have an interface object definition?)
# switch table (each interface on a node can have its own switch
# table entry, part of interface object, too?)
# username/password from password, hmc, ivm, mpa, and ipmi tables
# (do we need special encryption and display masking for passwords?)
# chain table (I think this is internal use only, do not abstract?)
# noderes entries for kernel, initrd, kcmdline
# ppc table (waiting on Scot to add to tabspec)
# policy table - ? do we need a data abstraction for this?
# notification - is this handled by Ling's commands?
# site - need to figure out what entries we will have in the
# site table since they are not listed individually in the
# tabspec
# nodelist.groups
# new group table and object
# new osimage table and object
###############
# TODO: need to fill out all the "description" fields
# These will be used for verbose usage with the def* cmds
##############
@{$defspec{node}->{'attrs'}} = (
{attr_name => 'node',
tabentry => 'nodelist.node',
access_tabentry => 'objkeyvalue'},
############
# TODO: The attr name for nodelist.nodetype is in conflict with the existing
# nodetype table. With the osimage table, the nodetype table should go
# away. Will reuse of this name cause confusion for xcat users?
############
{attr_name => 'nodetype',
tabentry => 'nodelist.nodetype',
access_tabentry => 'nodelist.node=attr:node',
description => 'Type of node: osi,hmc,fsp,mpa,???'},
{attr_name => 'xcatmaster',
tabentry => 'noderes.xcatmaster',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'servicenode',
tabentry => 'noderes.servicenode',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'mgt',
tabentry => 'nodehm.mgt',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'power',
tabentry => 'nodehm.power',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'cons',
tabentry => 'nodehm.cons',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'termserver',
tabentry => 'nodehm.termserver',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'termport',
tabentry => 'nodehm.termport',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'conserver',
tabentry => 'nodehm.conserver',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'getmac',
tabentry => 'nodehm.getmac',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'serialport',
tabentry => 'noderes.serialport',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'serialspeed',
tabentry => 'nodehm.serialspeed',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'serialflow',
tabentry => 'nodehm.serialflow',
access_tabentry => 'nodehm.node=attr:node'},
{attr_name => 'ip',
tabentry => 'hosts.ip',
access_tabentry => 'hosts.node=attr:node'},
{attr_name => 'hostnames',
tabentry => 'hosts.hostnames',
access_tabentry => 'hosts.node=attr:node'},
{attr_name => 'serialnumber',
tabentry => 'vpd.serial',
access_tabentry => 'vpd.node=attr:node'},
{attr_name => 'mtm',
tabentry => 'vpd.mtm',
access_tabentry => 'vpd.node=attr:node'},
{attr_name => 'rackloc',
tabentry => 'nodepos.rack',
access_tabentry => 'nodepos.node=attr:node'},
{attr_name => 'unitloc',
tabentry => 'nodepos.u',
access_tabentry => 'nodepos.node=attr:node'},
{attr_name => 'chassisloc',
tabentry => 'nodepos.chassis',
access_tabentry => 'nodepos.node=attr:node'},
{attr_name => 'slotloc',
tabentry => 'nodepos.slot',
access_tabentry => 'nodepos.node=attr:node'},
{attr_name => 'roomloc',
tabentry => 'nodepos.room',
access_tabentry => 'nodepos.node=attr:node'},
# Conditional attributes:
# OSI node attributes:
{attr_name => 'tftpserver',
only_if => 'nodetype=osi',
tabentry => 'noderes.tftpserver',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'nfsserver',
only_if => 'nodetype=osi',
tabentry => 'noderes.nfsserver',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'nfsdir',
only_if => 'nodetype=osi',
tabentry => 'noderes.nfsdir',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'primarynic',
only_if => 'nodetype=osi',
tabentry => 'noderes.primarynic',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'installnic',
only_if => 'nodetype=osi',
tabentry => 'noderes.installnic',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'netboot',
only_if => 'nodetype=osi',
tabentry => 'noderes.netboot',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'current_osimage',
only_if => 'nodetype=osi',
tabentry => 'noderes.current_osimage',
access_tabentry => 'noderes.node=attr:node'},
{attr_name => 'next_osimage',
only_if => 'nodetype=osi',
tabentry => 'noderes.next_osimage',
access_tabentry => 'noderes.node=attr:node'},
# Hardware Control node attributes:
{attr_name => hdwctrlpoint,
only_if => 'mgtmethod=mp',
tabentry => 'mp.mpa',
access_tabentry => 'mp.node=attr:node'},
# {attr_name => hdwctrlpoint,
# only_if => 'mgtmethod=hmc',
# tabentry => 'ppc.hcp',
# access_tabentry => 'ppc.node=attr:node'},
{attr_name => hdwctrlpoint,
only_if => 'mgtmethod=ipmi',
tabentry => 'ipmi.bmc',
access_tabentry => 'ipmi.node=attr:node'},
{attr_name => hdwctrlnodeid,
only_if => 'mgtmethod=mp',
tabentry => 'mp.id',
access_tabentry => 'mp.node=attr:node'},
# {attr_name => hdwctrlnodeid,
# only_if => 'mgtmethod=hmc',
# tabentry => 'ppc.id',
# access_tabentry => 'ppc.node=attr:node'}
);
@{$defspec{osimage}->{'attrs'}} = (
{attr_name => 'imagename',
tabentry => 'osimage.imagename',
access_tabentry => 'objkeyvalue',
description => 'Name of OS image'},
{attr_name => 'osdistro',
tabentry => 'osimage.osdistro',
access_tabentry => 'osimage.objname=attr:imagename'},
);
@{$defspec{network}->{'attrs'}} = (
{attr_name => 'netname',
tabentry => 'networks.netname',
access_tabentry => 'objkeyvalue',
description => 'Name to identify the network'},
{attr_name => 'net',
tabentry => 'networks.net',
access_tabentry => 'networks.netname=attr:netname'},
{attr_name => 'mask',
tabentry => 'networks.mask',
access_tabentry => 'networks.netname=attr:netname'},
{attr_name => 'gateway',
tabentry => 'networks.gateway',
access_tabentry => 'networks.netname=attr:netname'},
{attr_name => 'dhcpserver',
tabentry => 'networks.dhcpserver',
access_tabentry => 'networks.netname=attr:netname'},
{attr_name => 'tftpserver',
tabentry => 'networks.tftpserver',
access_tabentry => 'networks.netname=attr:netname'},
{attr_name => 'nameservers',
tabentry => 'networks.nameservers',
access_tabentry => 'networks.netname=attr:netname'},
{attr_name => 'dynamicrange',
tabentry => 'networks.dynamicrange',
access_tabentry => 'networks.netname=attr:netname'},
);
##############
# TODO: need to figure out how to handle a key for the site table.
# since this is really implemented differently than all the other
# data objects, it doesn't map as cleanly.
# change format of site table so each column is an attr and there
# is only a single row in the table keyed by xcatmaster name?
#############
@{$defspec{site}->{'attrs'}} = (
{attr_name => 'master',
tabentry => 'site.value',
access_tabentry => 'site.key=str:master',
description => 'The management node'},
{attr_name => 'installdir',
tabentry => 'site.value',
access_tabentry => 'site.key=str:installdir',
description => 'The installation directory'},
{attr_name => 'xcatdport',
tabentry => 'site.value',
access_tabentry => 'site.key=str:xcatdport',
description => 'Port used by xcatd daemon on master'},
);

1470
perl-xCAT-2.0/xCAT/Table.pm Normal file

File diff suppressed because it is too large Load Diff

213
perl-xCAT-2.0/xCAT/Template.pm Executable file
View File

@ -0,0 +1,213 @@
#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::Template;
use strict;
use xCAT::Table;
use File::Basename;
use File::Path;
use Data::Dumper;
use Sys::Syslog;
my $table;
my $key;
my $field;
my $idir;
my $node;
sub subvars {
my $self = shift;
my $inf = shift;
my $outf = shift;
$node = shift;
my $outh;
my $inh;
$idir = dirname($inf);
open($inh,"<",$inf);
unless ($inh) {
return undef;
}
mkpath(dirname($outf));
open($outh,">",$outf);
unless($outh) {
return undef;
}
my $inc;
#First load input into memory..
while (<$inh>) {
$inc.=$_;
}
close($inh);
my $master;
my $sitetab = xCAT::Table->new('site');
my $noderestab = xCAT::Table->new('noderes');
(my $et) = $sitetab->getAttribs({key=>"master"},'value');
if ($et and $et->{value}) {
$master = $et->{value};
}
$et = $noderestab->getNodeAttribs($node,['xcatmaster']);
if ($et and $et->{'xcatmaster'}) {
$master = $et->{'xcatmaster'};
}
unless ($master) {
die "Unable to identify master for $node";
}
$ENV{XCATMASTER}=$master;
#FIRST, do *all* includes, recursive and all
my $doneincludes=0;
while (not $doneincludes) {
$doneincludes=1;
if ($inc =~ /#INCLUDE:[^#]+#/) {
$doneincludes=0;
$inc =~ s/#INCLUDE:([^#]+)#/includefile($1)/eg;
}
}
#ok, now do everything else..
$inc =~ s/#COMMAND:([^#]+)#/command($1)/eg;
$inc =~ s/#TABLE:([^:]+):([^:]+):([^#]+)#/tabdb($1,$2,$3)/eg;
$inc =~ s/#CRYPT:([^:]+):([^:]+):([^#]+)#/crydb($1,$2,$3)/eg;
$inc =~ s/#XCATVAR:([^#]+)#/envvar($1)/eg;
$inc =~ s/#ENV:([^#]+)#/envvar($1)/eg;
print $outh $inc;
close($outh);
return 1;
}
sub includefile
{
my $file = shift;
my $text = "";
unless ($file =~ /^\//) {
$file = $idir."/".$file;
}
open(INCLUDE,$file) || \
return "#INCLUDEBAD:cannot open $file#";
while(<INCLUDE>) {
$text .= "$_";
}
close(INCLUDE);
chomp($text);
return($text);
}
sub command
{
my $command = shift;
my $r;
# if(($r = `$command`) == 0) {
# chomp($r);
# return($r);
# }
# else {
# return("#$command: failed $r#");
# }
$r = `$command`;
chomp($r);
return($r);
}
sub envvar
{
my $envvar = shift;
if($envvar =~ /^\$/) {
$envvar =~ s/^\$//;
}
return($ENV{$envvar});
}
sub genpassword {
#Generate a pseudo-random password of specified length
my $length = shift;
my $password='';
my $characters= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890';
srand; #have to reseed, rand is not rand otherwise
while (length($password) < $length) {
$password .= substr($characters,int(rand 63),1);
}
return $password;
}
sub crydb
{
my $result = tabdb(@_);
unless ($result =~ /^\$1\$/) {
$result = crypt($result,'$1$'.genpassword(8));
}
return $result;
}
sub tabdb
{
my $table = shift;
my $key = shift;
my $field = shift;
my $tabh = xCAT::Table->new($table);
my $ent;
if ($key eq "THISNODE" or $key eq '$NODE') {
$ent = $tabh->getNodeAttribs($node,[$field]);
} else {
my %kp;
foreach (split /,/,$key) {
my $key;
my $val;
($key,$val) = split /=/,$_;
$kp{$key}=$val;
}
($ent) = $tabh->getAttribs(\%kp,$field);
}
$tabh->close;
unless($ent and $ent->{$field}) {
return "#TABLEBAD:$table:field $field not found#";
}
return $ent->{$field};
#if($key =~ /^\$/) {
# $key =~ s/^\$//;
# $key = $ENV{$key};
#}
#if($field =~ /^\$/) {
# $field =~ s/^\$//;
# $field = $ENV{$field};
#}
#if($field == '*') {
# $field = 1;
# $all = 1;
#}
#--$field;
#if($field < 0) {
# return "#TABLE:field not found#"
#}
#open(TAB,$table) || \
# return "#TABLE:cannot open $table#";
#while(<TAB>) {
# if(/^$key(\t|,| )/) {
# m/^$key(\t|,| )+(.*)/;
# if($all == 1) {
# return "$2";
# }
# @fields = split(',',$2);
# if(defined $fields[$field]) {
# return "$fields[$field]";
# }
# else {
# return "#TABLE:field not found#"
# }
# }
#}
#close(TAB);
#return "#TABLE:key not found#"
}
1;

411
perl-xCAT-2.0/xCAT/Utils.pm Normal file
View File

@ -0,0 +1,411 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::Utils;
use xCAT::Table;
use xCAT::Schema;
use Data::Dumper;
use xCAT::NodeRange;
#--------------------------------------------------------------------------------
=head1 xCAT::Utils
=head2 Package Description
This program module file, is a set of utilities used by xCAT commands.
=cut
#--------------------------------------------------------------------------------
=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:
if (defined($$opthashref{'WhereStr'})) {
$where = xCAT::Utils->quote($$opthashref{'WhereStr'});
}
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 isAIX
returns 1 if localHost is AIX
Arguments:
none
Returns:
1 - localHost is AIX
0 - localHost is some other platform
Globals:
none
Error:
none
Example:
if (xCAT::Utils->isAIX()) { blah; }
Comments:
none
=cut
#-------------------------------------------------------------------------------
sub isAIX
{
if ($^O =~ /^aix/i) { return 1; }
else { return 0; }
}
#-------------------------------------------------------------------------------
=head3 isLinux
returns 1 if localHost is Linux
Arguments:
none
Returns:
1 - localHost is Linux
0 - localHost is some other platform
Globals:
none
Error:
none
Example:
if (xCAT::Utils->isLinux()) { blah; }
Comments:
none
=cut
#-------------------------------------------------------------------------------
sub isLinux
{
if ($^O =~ /^linux/i) { return 1; }
else { return 0; }
}
#-------------------------------------------------------------------------------
=head3 make_node_list_file
Makes a node list file.
Arguments:
(\@list_of_nodes) - reference to an arrary of nodes.
Returns:
$file_name and sets the global var: $::NODE_LIST_FILE
Globals:
the ENV vars: DSH_LIST, RPOWER_LIST, RCONSOLE_LIST
Error:
None documented
Example:
xCAT::Utils->make_node_list_file(\@nodelist);
Comments:
IMPORTANT:
Make sure to cleanup afterwards with:
xCAT::Utils->close_delete_file($file_handle, $file_name)
=cut
#--------------------------------------------------------------------------------
sub make_node_list_file
{
my ($class, $ref_node_list) = @_;
my @node_list = @$ref_node_list;
srand(time | $$); #random number generator start
my $file = "/tmp/csm_$$";
while (-e $file)
{
$file = xCAT::Utils->CreateRandomName($file);
}
open($::NODE_LIST_FILE, ">$file")
or MsgUtils->message("E", "Cannot write to file: $file\n");
foreach my $node (@node_list)
{
print $::NODE_LIST_FILE "$node\n";
}
return $file;
}
#--------------------------------------------------------------------------------
=head3 CreateRandomName
Create a randome file name.
Arguments:
Prefix of name
Returns:
Prefix with 8 random letters appended
Error:
none
Example:
$file = xCAT::Utils->CreateRandomName($namePrefix);
Comments:
None
=cut
#-------------------------------------------------------------------------------
sub CreateRandomName
{
my ($class, $name) = @_;
my $nI;
for ($nI = 0 ; $nI < 8 ; $nI++)
{
my $char = ('a' .. 'z', 'A' .. 'Z')[int(rand(52)) + 1];
$name .= $char;
}
$name;
}
#-----------------------------------------------------------------------
=head3
close_delete_file.
Arguments:
file handle,filename
Returns:
none
Globals:
none
Error:
undef
Example:
xCAT::Utils->close_delete_file($file_handle, $file_name);
Comments:
none
=cut
#------------------------------------------------------------------------
sub close_delete_file
{
my ($class, $file_handle, $file_name) = @_;
close $file_handle;
unlink($file_name);
}
#-----------------------------------------------------------------------
=head3
list_all_nodes
Arguments:
Returns:
an array of all define nodes from the nodelist table
Globals:
none
Error:
undef
Example:
@nodes=xCAT::Utils->list_all_nodes;
Comments:
none
=cut
#------------------------------------------------------------------------
sub list_all_nodes
{
my @nodes;
my @nodelist;
my $nodelisttab;
if ($nodelisttab = xCAT::Table->new("nodelist"))
{
my @attribs = ("node");
@nodes = $nodelisttab->getAllAttribs(@attribs);
foreach my $node (@nodes)
{
push @nodelist, $node->{node};
}
}
else
{
xCAT::MsgUtils->message("E", " Could not read the nodelist table\n");
}
return @nodelist;
}
#-----------------------------------------------------------------------
=head3
list_all_nodegroups
Arguments:
Returns:
an array of all define node groups from the nodelist table
Globals:
none
Error:
undef
Example:
@nodegrps=xCAT::Utils->list_all_nodegroups;
Comments:
none
=cut
#------------------------------------------------------------------------
sub list_all_node_groups
{
my @grouplist;
my @grouplist2;
my @distinctgroups;
my $nodelisttab;
if ($nodelisttab = xCAT::Table->new("nodelist"))
{
my @attribs = ("groups");
@grouplist = $nodelisttab->getAllAttribs(@attribs);
# build a distinct list of unique group names
foreach my $group (@grouplist)
{
my $gnames = $group->{groups};
my @groupnames = split ",", $gnames;
foreach my $groupname (@groupnames)
{
if (!grep(/$groupname/, @distinctgroups))
{ # not already in list
push @distinctgroups, $groupname;
}
}
}
}
else
{
xCAT::MsgUtils->message("E", " Could not read the nodelist table\n");
}
return @distinctgroups;
}
#-----------------------------------------------------------------------
=head3
list_nodes_in_nodegroup
Arguments: nodegroup
Returns:
an array of all define nodes in the node group
Globals:
none
Error:
undef
Example:
@nodes=xCAT::Utils->list_nodes_in_nodegroup($group);
Comments:
none
=cut
#------------------------------------------------------------------------
sub list_nodes_in_nodegroups
{
my ($class, $group) = @_;
$req->{noderange}->[0] = $group;
my @nodes = noderange($req->{noderange}->[0]);
return @nodes;
}
#-----------------------------------------------------------------------
=head3
get_site_attribute
Arguments:
Returns:
The value of the attribute requested from the site table
Globals:
none
Error:
undef
Example:
@attr=xCAT::Utils->get_site_attribute($attribute);
Comments:
none
=cut
#------------------------------------------------------------------------
sub get_site_attribute
{
my ($class, $attr) = @_;
my $values;
my $sitetab = xCAT::Table->new('site');
if ($sitetab)
{
(my $ref) = $sitetab->getAttribs({key => $attr}, value);
if ($ref and $ref->{value})
{
$values = $ref->{value};
}
}
else
{
xCAT::MsgUtils->message("E", " Could not read the site table\n");
}
return $values;
}
1;

View File

@ -0,0 +1,89 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#ibmleds,tab, mfg,prod_id,led_id,desc
package xCAT::data::ibmleds;
my %x3755_leds = (
0x0065=>'Dimm 6',
0x0011=>'VRM',
0x00d9=>'Alert',
0x0030=>'CPU1',
0x0032=>'CPU3',
0x00ca=>'Dimm 27',
0x0075=>'PCI 6',
0x00c1=>'Dimm 18',
0x0019=>'NMI',
0x0040=>'UNKNOWN',
0x0067=>'Dimm 8',
0x000f=>'RAID',
0x00c4=>'Dimm 21',
0x0057=>'Fan 8',
0x00d0=>'ServeRAID 8k Batt',
0x0069=>'Dimm 10',
0x000e=>'BOARD',
0x00c3=>'Dimm 20',
0x00cf=>'Dimm 32',
0x006f=>'Dimm 16',
0x0054=>'Fan 5',
0x00cd=>'Dimm 30',
0x0000=>'FAULT',
0x0014=>'FAN',
0x00c8=>'Dimm 25',
0x006c=>'Dimm 13',
0x0061=>'Dimm 2',
0x00c2=>'Dimm 19',
0x0074=>'PCI 5',
0x006a=>'Dimm 11',
0x00b9=>'CPU2_BOARD',
0x0047=>'UNKNOWN',
0x0050=>'Fan 1',
0x0072=>'PCI 3',
0x00c5=>'Dimm 22',
0x00c0=>'Dimm 17',
0x0070=>'PCI 1',
0x00c9=>'Dimm 26',
0x0006=>'CNFG',
0x006b=>'Dimm 12',
0x00d8=>'BK_Blue',
0x0068=>'Dimm 9',
0x00bb=>'CPU4_BOARD',
0x00c6=>'Dimm 23',
0x0031=>'CPU2',
0x0010=>'CPU',
0x00b8=>'CPU1_BOARD',
0x0056=>'Fan 7',
0x0063=>'Dimm 4',
0x00b0=>'HTX',
0x0001=>'LOCATION',
0x000b=>'SEER',
0x0013=>'DASD',
0x00cb=>'Dimm 28',
0x0052=>'Fan 3',
0x0064=>'Dimm 5',
0x001c=>'TEMP',
0x00c7=>'Dimm 24',
0x0060=>'Dimm 1',
0x00d1=>'ServeRAID 8k Err',
0x0073=>'PCI 4',
0x0015=>'MEM',
0x0003=>'INFO',
0x006e=>'Dimm 15',
0x0071=>'PCI 2',
0x00ba=>'CPU3_BOARD',
0x00ce=>'Dimm 31',
0x001b=>'OVERSPEC',
0x0041=>'UNKNOWN',
0x006d=>'Dimm 14',
0x0051=>'Fan 2',
0x001e=>'SP',
0x0066=>'Dimm 7',
0x0053=>'Fan 4',
0x0055=>'Fan 6',
0x0033=>'CPU4',
0x00cc=>'Dimm 29',
0x0020=>'PCI',
0x0062=>'Dimm 3',
);
%leds = (
"2,14" => \%x3755_leds,
);

View File

@ -0,0 +1,66 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#ipmigenericevent.tab",
#DO NOT EDIT",
#",
#<sensor type code>",<sensor offset>,<sensor type>,<event>",
package xCAT::data::ipmigenericevents;
%ipmigenericevents = (
"01h,00h"=>"Threshold,Lower Non-critical - going low",
"01h,01h"=>"Threshold,Lower Non-critical - going high",
"01h,02h"=>"Threshold,Lower Critical - going low",
"01h,03h"=>"Threshold,Lower Critical - going high",
"01h,04h"=>"Threshold,Lower Non-recoverable - going low",
"01h,05h"=>"Threshold,Lower Non-recoverable - going high",
"01h,06h"=>"Threshold,Upper Non-critical - going low",
"01h,07h"=>"Threshold,Upper Non-critical - going high",
"01h,08h"=>"Threshold,Upper Critical - going low",
"01h,09h"=>"Threshold,Upper Critical - going high",
"01h,0Ah"=>"Threshold,Upper Non-recoverable - going low",
"01h,0Bh"=>"Threshold,Upper Non-recoverable - going high",
"02h,00h"=>"Discrete,Transition to Idle",
"02h,01h"=>"Discrete,Transition to Active",
"02h,02h"=>"Discrete,Transition to Busy",
"03h,00h"=>"'digital' Discrete,State Deasserted",
"03h,01h"=>"'digital' Discrete,State Asserted",
"04h,00h"=>"'digital' Discrete,Predictive Failure Deasserted",
"04h,01h"=>"'digital' Discrete,Predictive Failure Asserted",
"05h,00h"=>"'digital' Discrete,Limit Not Exceeded",
"05h,01h"=>"'digital' Discrete,Limit Exceeded",
"06h,00h"=>"'digital' Discrete,Performance Met",
"06h,01h"=>"'digital' Discrete,Performance Lags",
"07h,00h"=>"Discrete,transition to OK",
"07h,01h"=>"Discrete,transition to Non-Critical from OK",
"07h,02h"=>"Discrete,transition to Critical from Less Severe",
"07h,03h"=>"Discrete,transition to Non-recoverable from Less Severe",
"07h,04h"=>"Discrete,transition to Non-Critical from More Severe",
"07h,05h"=>"Discrete,transition to Critical from Non-recoverable",
"07h,06h"=>"Discrete,transition to Non-recoverable",
"07h,07h"=>"Discrete,Monitor",
"07h,08h"=>"Discrete,Informational",
"08h,00h"=>"'digital' Discrete,Device Removed / Device Absent",
"08h,01h"=>"'digital' Discrete,Device Inserted / Device Present",
"09h,00h"=>"'digital' Discrete,Device Disabled",
"09h,01h"=>"'digital' Discrete,Device Enabled",
"0Ah,00h"=>"Discrete,transition to Running",
"0Ah,01h"=>"Discrete,transition to In Test",
"0Ah,02h"=>"Discrete,transition to Power Off",
"0Ah,03h"=>"Discrete,transition to On Line",
"0Ah,04h"=>"Discrete,transition to Off Line",
"0Ah,05h"=>"Discrete,transition to Off Duty",
"0Ah,06h"=>"Discrete,transition to Degraded",
"0Ah,07h"=>"Discrete,transition to Power Save",
"0Ah,08h"=>"Discrete,Install Error",
"0Bh,00h"=>"Discrete,Redundancy Regained",
"0Bh,01h"=>"Discrete,Redundancy Lost",
"0Bh,02h"=>"Discrete,Redundancy Degraded",
"0Bh,03h"=>"Discrete,Non-redundant:Sufficient resources",
"0Bh,04h"=>"Discrete,Non-redundant:Sufficient from insufficient resources",
"0Bh,05h"=>"Discrete,Non-redundant:Insufficient resources",
"0Bh,06h"=>"Discrete,Redundancy Degraded from Fully Reduntant",
"0Bh,06h"=>"Discrete,Redundancy Degraded from Non-Reduntant",
"0Ch,00h"=>"Discrete,D0 Power State",
"0Ch,01h"=>"Discrete,D1 Power State",
"0Ch,02h"=>"Discrete,D2 Power State",
"0Ch,03h"=>"Discrete,D3 Power State",
);

View File

@ -0,0 +1,169 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#ipmisensorevent.tab",
#DO NOT EDIT",
#",
#<sensor type code>",<sensor offset>,<sensor type>,<event>",
package xCAT::data::ipmisensorevents;
%ipmisensorevents = (
"00h,-"=>"reserved,Reserved",
"01h,-"=>"Temperature,Temperature",
"02h,-"=>"Voltage,Voltage",
"03h,-"=>"Current,Current",
"04h,-"=>"Fan,Fan",
"05h,00h"=>"Physical Security,General Chassis Intrusion",
"05h,01h"=>"Physical Security,Drive Bay Intrusion",
"05h,02h"=>"Physical Security,I/O Card area Intrusion",
"05h,03h"=>"Physical Security,Processor area Intrusion",
"05h,04h"=>"Physical Security,LAN Leash Lost (system has been unplugged from LAN)",
"05h,05h"=>"Physical Security,Unauthorized Dock/Undock",
"05h,06h"=>"Physical Security,FAN area intrusion",
"06h,00h"=>"Platform Security Violation Attempt,Secure Mode Violation Attempt",
"06h,01h"=>"Platform Security Violation Attempt,Pre-boot Password Violation - user password",
"06h,02h"=>"Platform Security Violation Attempt,Pre-boot Password Violation Attempt - setup password",
"06h,03h"=>"Platform Security Violation Attempt,Pre-boot Password Violation - network boot password",
"06h,04h"=>"Platform Security Violation Attempt,Other pre-boot Password Violation",
"06h,05h"=>"Platform Security Violation Attempt,Out-of-band Access Password Violation",
"07h,00h"=>"Processor,IERR",
"07h,01h"=>"Processor,Thermal Trip",
"07h,02h"=>"Processor,FRB1/BIST Failure",
"07h,03h"=>"Processor,FRB2/Hang in POST Failure",
"07h,04h"=>"Processor,FRB3/Processor Startup/Initialization failure (CPU didn't start)",
"07h,05h"=>"Processor,Configuration Error (for DMI)",
"07h,06h"=>"Processor,SM BIOS Uncorrectable CPU-complex Error",
"07h,07h"=>"Processor,Processor Presence Detected",
"07h,08h"=>"Processor,Processor Disabled",
"07h,09h"=>"Processor,Terminator Presence Detected",
"08h,00h"=>"Power Supply,Presence Detected",
"08h,01h"=>"Power Supply,Power Supply Failure Detected",
"08h,02h"=>"Power Supply,Predictive Failure Asserted",
"08h,03h"=>"Power Supply,Power Supply AC lost",
"08h,04h"=>"Power Supply,AC lost or out-of-range",
"08h,05h"=>"Power Supply,AC out-of-range, but present",
"09h,00h"=>"Power Unit,Power Off / Power Down",
"09h,01h"=>"Power Unit,Power Cycle",
"09h,02h"=>"Power Unit,240VA Power Down",
"09h,03h"=>"Power Unit,Interlock Power Down",
"09h,04h"=>"Power Unit,A/C Lost",
"09h,05h"=>"Power Unit,Soft Power Control Failure",
"09h,06h"=>"Power Unit,Power Unit Failure Detected",
"09h,07h"=>"Power Unit,Predictive Failure",
"0Ah,-"=>"Cooling Device,-",
"0Bh,-"=>"Other Units-based Sensor,-",
"0Ch,00h"=>"Memory,Correctable ECC",
"0Ch,01h"=>"Memory,Uncorrectable ECC",
"0Ch,02h"=>"Memory,Parity",
"0Ch,03h"=>"Memory,Memory Scrub Failed (stuck bit)",
"0Ch,04h"=>"Memory,Memory Device Disabled",
"0Ch,05h"=>"Memory,Correctable ECC (loggin limit reached)",
"0Dh,-"=>"Drive Slot,-",
"0Eh,-"=>"POST Memory Resize,-",
"0Fh,00h"=>"System Firmware Progress,POST Error",
"0Fh,01h"=>"System Firmware Progress,System Firmware Hung",
"0Fh,02h"=>"System Firmware Progress,System Firmware Progress",
"10h,00h"=>"Event Logging Disabled,Correctable Memory Error Logging Disabled",
"10h,01h"=>"Event Logging Disabled,Event 'Type' Logging Disabled",
"10h,02h"=>"Event Logging Disabled,Log Area Reset/Cleared",
"10h,03h"=>"Event Logging Disabled,All Event Logging Disabled",
"11h,00h"=>"Watchdog 1,BIOS Watchdog Reset",
"11h,01h"=>"Watchdog 1,OS Watchdog Reset",
"11h,02h"=>"Watchdog 1,OS Watchdog Shut Down",
"11h,03h"=>"Watchdog 1,OS Watchdog Power Down",
"11h,04h"=>"Watchdog 1,OS Watchdog Power Cycle",
"11h,05h"=>"Watchdog 1,OS Watchdog NMI",
"11h,06h"=>"Watchdog 1,OS Watchdog Expired, status only",
"11h,07h"=>"Watchdog 1,OS Watchdog Pre-timeout Interrupt, non-NMI",
"12h,00h"=>"System Event,System Reconfigured",
"12h,01h"=>"System Event,Boot",
"12h,02h"=>"System Event,Undetermined system hardware failure",
"12h,03h"=>"System Event,Entry added to Auxiliary Log",
"12h,04h"=>"System Event,PEF Action",
"13h,00h"=>"Critical Interrupt,Front Panel NMI ",
"13h,01h"=>"Critical Interrupt,Bus Timeout",
"13h,02h"=>"Critical Interrupt,I/O Channel Check NMI",
"13h,03h"=>"Critical Interrupt,Software NMI",
"13h,04h"=>"Critical Interrupt,PCI PERR",
"13h,05h"=>"Critical Interrupt,PCI SERR",
"13h,06h"=>"Critical Interrupt,EISA Fail Safe Timeout",
"13h,07h"=>"Critical Interrupt,Bus Correctable Error",
"13h,08h"=>"Critical Interrupt,Bus Uncorrectable Error",
"13h,09h"=>"Critical Interrupt,Fatal NMI (port 61h, bit 7)",
"14h,00h"=>"Button,Power Button pressed",
"14h,01h"=>"Button,Sleep Button pressed",
"14h,02h"=>"Button,Reset Button pressed",
"15h,-"=>"Module / Board,-",
"16h,-"=>"Microcontroller / Coprocessor,-",
"17h,-"=>"Add-in Card,-",
"18h,-"=>"Chassis,-",
"19h,-"=>"Chip Set,-",
"1Ah,-"=>"Other FRU,-",
"1Bh,-"=>"Cable / Interconnect,-",
"1Ch,-"=>"Terminator,-",
"1Dh,00h"=>"System Boot Initiated,Initiated by power up",
"1Dh,01h"=>"System Boot Initiated,Initiated by hard reset",
"1Dh,02h"=>"System Boot Initiated,Initiated by warm reset",
"1Dh,03h"=>"System Boot Initiated,User requested PXE boot",
"1Dh,04h"=>"System Boot Initiated,Automatic boot to diagnostic",
"1Eh,00h"=>"Boot Error,No bootable media",
"1Eh,01h"=>"Boot Error,Non-bootable diskette left in drive",
"1Eh,02h"=>"Boot Error,PXE Server not found",
"1Eh,03h"=>"Boot Error,Invalid boot sector",
"1Eh,04h"=>"Boot Error,Timeout waiting for user selection of boot source",
"1Fh,00h"=>"OS Boot,A: boot completed",
"1Fh,01h"=>"OS Boot,C: boot completed",
"1Fh,02h"=>"OS Boot,PXE boot completed",
"1Fh,03h"=>"OS Boot,Diagnostic boot completed",
"1Fh,04h"=>"OS Boot,CD-ROM boot completed",
"1Fh,05h"=>"OS Boot,ROM boot completed",
"1Fh,06h"=>"OS Boot,Boot completed - boot device not specified",
"20h,00h"=>"OS Critical Stop,Stop during OS load / initialization",
"20h,01h"=>"OS Critical Stop,Run-time Stop",
"21h,00h"=>"Slot / Connector,Fault Status asserted",
"21h,01h"=>"Slot / Connector,Identify Status asserted",
"21h,02h"=>"Slot / Connector,Slot / Connector Device installed/attached",
"21h,03h"=>"Slot / Connector,Slot / Connector Ready for Device Installation",
"21h,04h"=>"Slot / Connector,Slot/Connector Ready for Device Removal",
"21h,05h"=>"Slot / Connector,Slot Power is Off",
"21h,06h"=>"Slot / Connector,Slot / Connector Device Removal Request",
"21h,07h"=>"Slot / Connector,Interlock asserted",
"21h,08h"=>"Slot / Connector,Slot is Disabled",
"22h,00h"=>"System ACPI Power State,S0 / G0 working",
"22h,01h"=>"System ACPI Power State,S1 sleeping with system h/w & processor context maintained",
"22h,02h"=>"System ACPI Power State,S2 sleeping, processor context lost",
"22h,03h"=>"System ACPI Power State,S3 sleeping, processor & h/w context lost, memory retained.",
"22h,04h"=>"System ACPI Power State,S4 non-volatile sleep / suspend-to disk",
"22h,05h"=>"System ACPI Power State,S5 / G2 soft-off",
"22h,06h"=>"System ACPI Power State,S4 / S5 soft-off, particular S4 / S5 state cannot be determined",
"22h,07h"=>"System ACPI Power State,G3 / Mechanical Off",
"22h,08h"=>"System ACPI Power State,Sleeping in an S1, S2, or S3 states",
"22h,09h"=>"System ACPI Power State,G1 sleeping",
"22h,0Ah"=>"System ACPI Power State,S5 entered by override",
"22h,0Bh"=>"System ACPI Power State,Legacy ON state",
"22h,0Ch"=>"System ACPI Power State,Legacy OFF state",
"22h,0Eh"=>"System ACPI Power State,Unknown",
"23h,00h"=>"Watchdog 2,Timer expired, status only",
"23h,01h"=>"Watchdog 2,Hard Reset",
"23h,02h"=>"Watchdog 2,Power Down",
"23h,03h"=>"Watchdog 2,Power Cycle",
"23h,04h"=>"Watchdog 2,reserved",
"23h,05h"=>"Watchdog 2,reserved",
"23h,06h"=>"Watchdog 2,reserved",
"23h,07h"=>"Watchdog 2,reserved",
"23h,08h"=>"Watchdog 2,Timer interrupt",
"24h,00h"=>"Platform Alert,Platform generated page",
"24h,01h"=>"Platform Alert,Platform generated LAN alert",
"24h,02h"=>"Platform Alert,Platform Event Trap generated, formatted per IPMI PET specification",
"24h,03h"=>"Platform Alert,Platform generated SNMP trap, OEM format",
"25h,00h"=>"Entity Presence,Entity Present",
"25h,01h"=>"Entity Presence,Entity Absent",
"25h,02h"=>"Entity Presence,Entity Disabled",
"26h,-"=>"Monitor ASIC / IC,-",
"27h,00h"=>"LAN,LAN Heartbeat Lost",
"27h,01h"=>"LAN,LAN Heartbeat",
"28h,00h"=>"Management Subsystem Health,sensor access degraded or unavailable",
"28h,01h"=>"Management Subsystem Health,controller access degraded or unavailable",
"28h,02h"=>"Management Subsystem Health,management controller off-line",
"28h,03h"=>"Management Subsystem Health,management controller unavailable",
"29h,00h"=>"Battery,battery low (predictive failure)",
"29h,01h"=>"Battery,battery failed",
"29h,02h"=>"Battery,battery presense detected",
);

4
svn-commit.2.tmp Normal file
View File

@ -0,0 +1,4 @@
xCAT 2.0 core import
--This line, and those below, will be ignored--
A .

4
svn-commit.tmp Normal file
View File

@ -0,0 +1,4 @@
Import xCAT 2.0 tree as of 10/26
--This line, and those below, will be ignored--
A .

View File

@ -0,0 +1,326 @@
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=ProgId content=Word.Document>
<meta name=Generator content="Microsoft Word 9">
<meta name=Originator content="Microsoft Word 9">
<title>Eclipse Public License - Version 1.0</title>
<!--[if gte mso 9]><xml>
<o:DocumentProperties>
<o:Revision>2</o:Revision>
<o:TotalTime>3</o:TotalTime>
<o:Created>2004-03-05T23:03:00Z</o:Created>
<o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
<o:Pages>4</o:Pages>
<o:Words>1626</o:Words>
<o:Characters>9270</o:Characters>
<o:Lines>77</o:Lines>
<o:Paragraphs>18</o:Paragraphs>
<o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
<o:Version>9.4402</o:Version>
</o:DocumentProperties>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:TrackRevisions/>
</w:WordDocument>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:553679495 -2147483648 8 0 66047 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p
{margin-right:0in;
mso-margin-top-alt:auto;
mso-margin-bottom-alt:auto;
margin-left:0in;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p.BalloonText, li.BalloonText, div.BalloonText
{mso-style-name:"Balloon Text";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:8.0pt;
font-family:Tahoma;
mso-fareast-font-family:"Times New Roman";}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
</head>
<body lang=EN-US style='tab-interval:.5in'>
<div class=Section1>
<p align=center style='text-align:center'><b>Eclipse Public License - v 1.0</b>
</p>
<p><span style='font-size:10.0pt'>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE,
REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
OF THIS AGREEMENT.</span> </p>
<p><b><span style='font-size:10.0pt'>1. DEFINITIONS</span></b> </p>
<p><span style='font-size:10.0pt'>&quot;Contribution&quot; means:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
in the case of the initial Contributor, the initial code and documentation
distributed under this Agreement, and<br clear=left>
b) in the case of each subsequent Contributor:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
changes to the Program, and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
additions to the Program;</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>where
such changes and/or additions to the Program originate from and are distributed
by that particular Contributor. A Contribution 'originates' from a Contributor
if it was added to the Program by such Contributor itself or anyone acting on
such Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in conjunction
with the Program under their own license agreement, and (ii) are not derivative
works of the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Contributor&quot; means any person or
entity that distributes the Program.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Licensed Patents &quot; mean patent
claims licensable by a Contributor which are necessarily infringed by the use
or sale of its Contribution alone or when combined with the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Program&quot; means the Contributions
distributed in accordance with this Agreement.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Recipient&quot; means anyone who
receives the Program under this Agreement, including all Contributors.</span> </p>
<p><b><span style='font-size:10.0pt'>2. GRANT OF RIGHTS</span></b> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
Subject to the terms of this Agreement, each Contributor hereby grants Recipient
a non-exclusive, worldwide, royalty-free copyright license to<span
style='color:red'> </span>reproduce, prepare derivative works of, publicly
display, publicly perform, distribute and sublicense the Contribution of such
Contributor, if any, and such derivative works, in source code and object code
form.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide,<span style='color:green'> </span>royalty-free
patent license under Licensed Patents to make, use, sell, offer to sell, import
and otherwise transfer the Contribution of such Contributor, if any, in source
code and object code form. This patent license shall apply to the combination
of the Contribution and the Program if, at the time the Contribution is added
by the Contributor, such addition of the Contribution causes such combination
to be covered by the Licensed Patents. The patent license shall not apply to
any other combinations which include the Contribution. No hardware per se is
licensed hereunder. </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>c)
Recipient understands that although each Contributor grants the licenses to its
Contributions set forth herein, no assurances are provided by any Contributor
that the Program does not infringe the patent or other intellectual property
rights of any other entity. Each Contributor disclaims any liability to Recipient
for claims brought by any other entity based on infringement of intellectual
property rights or otherwise. As a condition to exercising the rights and
licenses granted hereunder, each Recipient hereby assumes sole responsibility
to secure any other intellectual property rights needed, if any. For example,
if a third party patent license is required to allow Recipient to distribute
the Program, it is Recipient's responsibility to acquire that license before
distributing the Program.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>d)
Each Contributor represents that to its knowledge it has sufficient copyright
rights in its Contribution, if any, to grant the copyright license set forth in
this Agreement. </span></p>
<p><b><span style='font-size:10.0pt'>3. REQUIREMENTS</span></b> </p>
<p><span style='font-size:10.0pt'>A Contributor may choose to distribute the
Program in object code form under its own license agreement, provided that:</span>
</p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it complies with the terms and conditions of this Agreement; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
its license agreement:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
effectively disclaims on behalf of all Contributors all warranties and
conditions, express and implied, including warranties or conditions of title
and non-infringement, and implied warranties or conditions of merchantability
and fitness for a particular purpose; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
effectively excludes on behalf of all Contributors all liability for damages,
including direct, indirect, special, incidental and consequential damages, such
as lost profits; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iii)
states that any provisions which differ from this Agreement are offered by that
Contributor alone and not by any other party; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iv)
states that source code for the Program is available from such Contributor, and
informs licensees how to obtain it in a reasonable manner on or through a
medium customarily used for software exchange.<span style='color:blue'> </span></span></p>
<p><span style='font-size:10.0pt'>When the Program is made available in source
code form:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it must be made available under this Agreement; and </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b) a
copy of this Agreement must be included with each copy of the Program. </span></p>
<p><span style='font-size:10.0pt'>Contributors may not remove or alter any
copyright notices contained within the Program. </span></p>
<p><span style='font-size:10.0pt'>Each Contributor must identify itself as the
originator of its Contribution, if any, in a manner that reasonably allows
subsequent Recipients to identify the originator of the Contribution. </span></p>
<p><b><span style='font-size:10.0pt'>4. COMMERCIAL DISTRIBUTION</span></b> </p>
<p><span style='font-size:10.0pt'>Commercial distributors of software may
accept certain responsibilities with respect to end users, business partners
and the like. While this license is intended to facilitate the commercial use
of the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create potential
liability for other Contributors. Therefore, if a Contributor includes the
Program in a commercial product offering, such Contributor (&quot;Commercial
Contributor&quot;) hereby agrees to defend and indemnify every other
Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and
costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other
legal actions brought by a third party against the Indemnified Contributor to
the extent caused by the acts or omissions of such Commercial Contributor in
connection with its distribution of the Program in a commercial product
offering. The obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In order
to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
Contributor in writing of such claim, and b) allow the Commercial Contributor
to control, and cooperate with the Commercial Contributor in, the defense and
any related settlement negotiations. The Indemnified Contributor may participate
in any such claim at its own expense.</span> </p>
<p><span style='font-size:10.0pt'>For example, a Contributor might include the
Program in a commercial product offering, Product X. That Contributor is then a
Commercial Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance claims and
warranties are such Commercial Contributor's responsibility alone. Under this
section, the Commercial Contributor would have to defend claims against the
other Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.</span> </p>
<p><b><span style='font-size:10.0pt'>5. NO WARRANTY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
responsible for determining the appropriateness of using and distributing the
Program and assumes all risks associated with its exercise of rights under this
Agreement , including but not limited to the risks and costs of program errors,
compliance with applicable laws, damage to or loss of data, programs or
equipment, and unavailability or interruption of operations. </span></p>
<p><b><span style='font-size:10.0pt'>6. DISCLAIMER OF LIABILITY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
<p><b><span style='font-size:10.0pt'>7. GENERAL</span></b> </p>
<p><span style='font-size:10.0pt'>If any provision of this Agreement is invalid
or unenforceable under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this Agreement, and without
further action by the parties hereto, such provision shall be reformed to the
minimum extent necessary to make such provision valid and enforceable.</span> </p>
<p><span style='font-size:10.0pt'>If Recipient institutes patent litigation
against any entity (including a cross-claim or counterclaim in a lawsuit)
alleging that the Program itself (excluding combinations of the Program with
other software or hardware) infringes such Recipient's patent(s), then such
Recipient's rights granted under Section 2(b) shall terminate as of the date
such litigation is filed. </span></p>
<p><span style='font-size:10.0pt'>All Recipient's rights under this Agreement
shall terminate if it fails to comply with any of the material terms or
conditions of this Agreement and does not cure such failure in a reasonable
period of time after becoming aware of such noncompliance. If all Recipient's
rights under this Agreement terminate, Recipient agrees to cease use and
distribution of the Program as soon as reasonably practicable. However,
Recipient's obligations under this Agreement and any licenses granted by
Recipient relating to the Program shall continue and survive. </span></p>
<p><span style='font-size:10.0pt'>Everyone is permitted to copy and distribute
copies of this Agreement, but in order to avoid inconsistency the Agreement is
copyrighted and may only be modified in the following manner. The Agreement
Steward reserves the right to publish new versions (including revisions) of
this Agreement from time to time. No one other than the Agreement Steward has
the right to modify this Agreement. The Eclipse Foundation is the initial
Agreement Steward. The Eclipse Foundation may assign the responsibility to
serve as the Agreement Steward to a suitable separate entity. Each new version
of the Agreement will be given a distinguishing version number. The Program
(including Contributions) may always be distributed subject to the version of
the Agreement under which it was received. In addition, after a new version of
the Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly stated
in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
the intellectual property of any Contributor under this Agreement, whether
expressly, by implication, estoppel or otherwise. All rights in the Program not
expressly granted under this Agreement are reserved.</span> </p>
<p><span style='font-size:10.0pt'>This Agreement is governed by the laws of the
State of New York and the intellectual property laws of the United States of
America. No party to this Agreement will bring a legal action under this
Agreement more than one year after the cause of action arose. Each party waives
its rights to a jury trial in any resulting litigation.</span> </p>
<p class=MsoNormal><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>
</div>
</body>
</html>

8
xCAT-client-2.0/README Normal file
View File

@ -0,0 +1,8 @@
This is the README for xCAT - Extreme Cluster Administration Toolkit,
Version 2.0 alpha release. xCAT is a toolkit for the deployment and administration of clusters.
xCAT 2.0 is offered OSS under a EPL license.
See http://www.eclipse.org/legal/epl-v10.html for license details.
The xCAT 2.0 code and documentation can be downloaded from http://xcat.org.
For support, go to http://xcat.org for instructions on joining the mailing list.

View File

@ -0,0 +1,67 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use xCAT::Table;
use xCAT::NodeRange;
use IO::Socket::SSL;
use XML::Simple;
use Data::Dumper;
use strict;
my $xcathost='localhost:3001';
if ($ENV{XCATHOST}) {
$xcathost=$ENV{XCATHOST};
}
my $server = IO::Socket::SSL->new(
PeerAddr=>$xcathost,
SSL_key_file=>$ENV{HOME}."/.xcat/client-key.pem",
SSL_cert_file=>$ENV{HOME}."/.xcat/client-cert.pem",
SSL_ca_file => $ENV{HOME}."/.xcat/ca.pem",
SSL_use_cert => 1,
#SSL_verify_mode => 1,
);
die "Connection failure: $!\n" unless ($server);
my $target=shift(@ARGV);
my %request=(); #Start building the hash to XML-ify
$request{command}='getnodeattributes';
$request{noderange}=$target;
for (@ARGV) {
my $temp;
my $table;
my $column;
my $value;
($table,$column) = split('\.',$_,2);
$request{table}=$table; #build/reuse request specific elements
$request{attribute}=$column;
print $server XMLout(\%request,RootName => 'xcatrequest',NoAttr => 1);
alarm(30);
my $response;
while (<$server>) {
alarm(0);
$response .= $_;
if ($response =~ m/<\/xcatresponse>/) {
my $reply=XMLin($response);
$response="";
if ($reply->{error}) {
printf "ERROR: ".$reply->{error}."\n";
}
if ($reply->{warning}) {
printf "Warning: ".$reply->{warning}."\n";
}
if ($reply->{attributes}{$column}) {
printf "$table.$column:".$reply->{attributes}{$column}."\n";
}
if ($reply->{serverdone}) {
last;
}
}
}
}
#my $tab = xCAT::Table->new($table,-create => 1);
#my $rec = $tab->getAttribs($key,$val,$column);
# if ($rec->{$column}) { printf $rec->{$column}."\n"; }
#}

73
xCAT-client-2.0/usr/bin/pping Executable file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#Note, this pping still frontends fping. I think it would be possible to write a perl equivalent, but
#I've not had the time. Net::Ping shows perl code I could see being adapted for a somewhat
#asynchronous ICMP ping (the tcp syn is interesting, but far too limited, and that is currently the only async
#method Net::Ping provides.
use IO::Socket::SSL;
use XML::Simple;
use Data::Dumper;
use IO::Handle;
use IO::Select;
use xCAT::Utils;
use Getopt::Long;
my $interface;
GetOptions("interface=s" => \$interface);
my $xcathost='localhost:3001';
if ($ENV{XCATHOST}) {
$xcathost=$ENV{XCATHOST};
}
unless (@ARGV) {
print "Usage: pping [-i suffix] <noderange>\n";
exit(1);
}
my $noderange = $ARGV[0];
my $client = IO::Socket::SSL->new(
PeerAddr=>$xcathost,
SSL_key_file=>$ENV{HOME}."/.xcat/client-key.pem",
SSL_cert_file=>$ENV{HOME}."/.xcat/client-cert.pem",
SSL_ca_file => $ENV{HOME}."/.xcat/ca.pem",
SSL_use_cert => 1,
#SSL_verify_mode => 1,
);
die "Connection failure: $!\n" unless ($client);
my %cmdref = (command => 'noderange', noderange => $noderange);
$SIG{ALRM} = sub { die "No response getting noderange" };
alarm(15);
print $client XMLout(\%cmdref,RootName=>'xcatrequest', NoAttr=>1, KeyAttr => []);
alarm(15);
my $response="";
my @nodes=();
while (<$client>) {
alarm(0);
$response .= $_;
if ($response =~ m/<\/xcatresponse>/) {
$rsp=XMLin($response, ForceArray => ['node']);
$response='';
if ($rsp->{warning}) {
printf "Warning: ".$rsp->{warning}."\n";
}
if ($rsp->{error}) {
die ("ERROR: ".$rsp->{error}."\n");
} elsif ($rsp->{node}) {
@nodes=@{$rsp->{node}};
}
if ($rsp->{serverdone}) {
last;
}
}
}
close($client);
my $children = 0;
my $inputs = new IO::Select;
$SIG{CHLD} = sub { while (waitpid(-1,WNOHANG) > 0) { $children--; } };
if ($interface) {
foreach (@nodes) {
s/$/-$interface/;
}
}
exec "fping ".join(' ',@nodes). " 2> /dev/null";

108
xCAT-client-2.0/usr/bin/psh Executable file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use IO::Socket::SSL;
use XML::Simple;
use Data::Dumper;
use IO::Handle;
use IO::Select;
use xCAT::Utils;
use Getopt::Long;
use POSIX qw(:signal_h :errno_h :sys_wait_h);
my $interface;
Getopt::Long::Configure("require_order");
GetOptions(
"interface=s" => \$interface,
);
my %nodehdl;
my $xcathost='localhost:3001';
if ($ENV{XCATHOST}) {
$xcathost=$ENV{XCATHOST};
}
my $pshmaxp = 64; #TODO: should this be server dictated or local conf?
unless (@ARGV) {
print "Usage: psh [-i <suffix] <noderange> <command>\n";
}
my $noderange = $ARGV[0];
my $client = IO::Socket::SSL->new(
PeerAddr=>$xcathost,
SSL_key_file=>$ENV{HOME}."/.xcat/client-key.pem",
SSL_cert_file=>$ENV{HOME}."/.xcat/client-cert.pem",
SSL_ca_file => $ENV{HOME}."/.xcat/ca.pem",
SSL_use_cert => 1,
#SSL_verify_mode => 1,
);
die "Connection failure: $!\n" unless ($client);
my %cmdref = (command => 'noderange', noderange => $noderange);
$SIG{ALRM} = sub { die "No response getting noderange" };
alarm(15);
print $client XMLout(\%cmdref,RootName=>'xcatrequest', NoAttr=>1, KeyAttr => []);
alarm(15);
my $response="";
my @nodes=();
while (<$client>) {
alarm(0);
$response .= $_;
if ($response =~ m/<\/xcatresponse>/) {
$rsp=XMLin($response, ForceArray => ['node']);
$response='';
if ($rsp->{warning}) {
printf "Warning: ".$rsp->{warning}."\n";
}
if ($rsp->{error}) {
die ("ERROR: ".$rsp->{error}."\n");
} elsif ($rsp->{node}) {
@nodes=@{$rsp->{node}};
}
if ($rsp->{serverdone}) {
last;
}
}
}
close($client);
my $children = 0;
my $inputs = new IO::Select;
$SIG{CHLD} = sub { while (waitpid(-1,WNOHANG) > 0) { $children--; } };
if ($interface) {
foreach (@nodes) {
s/$/-$interface/;
}
}
foreach (@nodes) {
my $node=$_;
while ($children > $pshmaxp) { processoutput($inputs); }
my $child;
$children++;
sshnode(\$child,$node,@ARGV[1 .. $#ARGV]);
$inputs->add($child);
$nodehdl{$child} = $node;
}
while ($children) {
processoutput($inputs);
}
while (processoutput($inputs)) {};
exit(0);
sub processoutput { #This way, one arbiter handles output, no interrupting
my $inputs = shift;
my @readyins = $inputs->can_read(1);
my $rc = @readyins;
my $readyh;
foreach $readyh (@readyins) {
my $line = <$readyh>;
unless ($line) {
$inputs->remove($readyh);
close($readyh);
next;
}
print $nodehdl{$readyh}.": ".$line;
}
return $rc;
}
sub sshnode {
my $out = shift;
my $node = shift;
my $in;
my $args = join(" ",@_);
open($$out,"ssh -o BatchMode=yes $node " . xCAT::Utils->quote($args) . " 2>&1 |");
}

View File

@ -0,0 +1,241 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use File::Basename;
use xCAT::Client submit_request;
my $bname = basename($0);
#########################################
# Main
#
# xcatDBcmds
#
# Handles xCAT DB object management commands:
# xdefmk, xdefch, xdefls, & xdefrm.
#
# Builds hash and submits request.
#
# Note: The subroutines that implement these commands
# are in /usr/lib/xcat/plugins/DBobjectdefs.pm
# on the xCAT management node.
#
#########################################
my $cmdref;
# set the command name to pass to the plugin
if ($bname =~ /xcatDBcmds/)
{
$cmdref->{command}->[0] = shift @ARGV;
}
elsif ($bname =~ /^(.*$)/)
{
$cmdref->{command}->[0] = $1;
}
else
{
printf("Bad usage\n");
exit 1;
}
print "The command \'$cmdref->{command}->[0]\' is not yet available.\n";
exit 0;
# add all the cmd line args to the hash - to pass to the plugin subroutine
foreach (@ARGV)
{
push(@{$cmdref->{arg}}, $_);
}
if (!($bname =~ /xdefmk/))
{
#
# We need to see if a noderange was provided on the command line
# - the command line could be flags(options) -> noderange -> attr=val pairs
# - the noderange is used by xCAT remote access support infrastructure
# so we need to set it now
#
use Getopt::Long;
# Allows opts to be grouped (e.g. -avx)
Getopt::Long::Configure("bundling");
# parse the options
if (
!GetOptions(
'all|a' => \$::opt_a,
'dynamic|d' => \$::opt_d,
'f=s' => \$::opt_f,
'i=s' => \$::opt_i,
'help|h' => \$::opt_h,
'long|l' => \$::opt_l,
'm|minus' => \$::opt_m,
'o=s' => \$::opt_o,
'r|relace' => \$::opt_r,
't=s' => \$::opt_t,
'verbose|V' => \$::opt_V,
'version|v' => \$::opt_v,
'w=s' => \$::opt_w,
'x=s' => \$::opt_x,
'z=s' => \$::opt_z
)
)
{
return 1;
}
# a node range would be the next arg - but not if it contains an "=" sign
# - then it would be an attr=val operand
my $arg = shift(@ARGV);
if (!($arg =~ /=/))
{
$cmdref->{noderange}->[0] = $arg;
# could check if valid noderange at this point???
}
}
xCAT::Client::submit_request($cmdref, \&handle_response);
print "\n";
exit 0;
# may want to modify handle_response at some point!!!!!!!
##########################################
# handle_response is the callback that is
# invoked to print out the data returned by
# the plugin.
#
# Format of the response hash:
# {data => [ 'data str1', 'data str2', '...' ] }
#
# Results are printed as:
# data str1
# data str2
#
# or:
# {data => [ {desc => [ 'desc1' ],
# contents => [ 'contents1' ] },
# {desc => [ 'desc2 ],
# contents => [ 'contents2' ] }
# :
# ] }
# NOTE: In this format, only the data array can have more than one
# element. All other arrays are assumed to be a single element.
# Results are printed as:
# desc1: contents1
# desc2: contents2
#
# or:
# {node => [ {name => ['node1'],
# data => [ {desc => [ 'node1 desc' ],
# contents => [ 'node1 contents' ] } ] },
# {name => ['node2'],
# data => [ {desc => [ 'node2 desc' ],
# contents => [ 'node2 contents' ] } ] },
# :
# ] }
# NOTE: Only the node array can have more than one element.
# All other arrays are assumed to be a single element.
#
# This was generated from the corresponding HTML:
# <xcatrequest>
# <node>
# <name>node1</name>
# <data>
# <desc>node1 desc</desc>
# <contents>node1 contents</contents>
# </data>
# </node>
# <node>
# <name>node2</name>
# <data>
# <desc>node2 desc</desc>
# <contents>node2 contents</contents>
# </data>
# </node>
# </xcatrequest>
#
# Results are printed as:
# node_name: desc: contents
##########################################
sub handle_response
{
my $rsp = shift;
# Handle {node} structure
if ($rsp->{node})
{
my $nodes = ($rsp->{node});
my $node;
foreach $node (@$nodes)
{
my $desc = $node->{name}->[0];
if ($node->{data})
{
if (ref(\($node->{data}->[0])) eq 'SCALAR')
{
$desc = $desc . ": " . $node->{data}->[0];
}
else
{
if ($node->{data}->[0]->{desc})
{
$desc = $desc . ": " . $node->{data}->[0]->{desc}->[0];
}
if ($node->{data}->[0]->{contents})
{
$desc = "$desc: " . $node->{data}->[0]->{contents}->[0];
}
}
}
if ($desc)
{
print "$desc\n";
}
}
}
# Handle {data} structure with no nodes
if ($rsp->{data})
{
my $data = ($rsp->{data});
my $data_entry;
foreach $data_entry (@$data)
{
my $desc;
if (ref(\($data_entry)) eq 'SCALAR')
{
$desc = $data_entry;
}
else
{
if ($data_entry->{desc})
{
$desc = $data_entry->{desc}->[0];
}
if ($data_entry->{contents})
{
if ($desc)
{
$desc = "$desc: " . $data_entry->{contents}->[0];
}
else
{
$desc = $data_entry->{contents}->[0];
}
}
}
if ($desc)
{
print "$desc\n";
}
}
}
}

View File

@ -0,0 +1,168 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use IO::Socket::SSL;
use IO::Socket::INET;
use File::Basename;
use Data::Dumper;
use xCAT::Client submit_request;
my $bname = basename($0);
#########################################
# Main
# Build hash and submit request
#########################################
my $exitcode = 0; #var to store exit code that results from responses
my $cmdref;
if($bname =~ /xcatclient/) {
$cmdref->{command}->[0]=shift @ARGV;
} elsif ($bname =~/^(.*$)/) {
$cmdref->{command}->[0] = $1;
} else {
printf("Bad usage\n");
exit(1);
}
if (-p STDIN) {
my $data;
while ( <STDIN> ) {
$data.=$_;
}
$cmdref->{stdin}->[0]=$data;
}
my $arg=shift(@ARGV);
while ($arg =~ /^-/) {
push (@{$cmdref->{arg}}, $arg);
$arg=shift(@ARGV);
}
if ($arg ne "NO_NODE_RANGE") {
$cmdref->{noderange}->[0]=$arg;
}
foreach (@ARGV) { push (@{$cmdref->{arg}}, $_ ); }
#$cmdref->{arg}=\@ARGV;
xCAT::Client::submit_request($cmdref,\&handle_response);
exit $exitcode;
##########################################
# handle_response is the callback that is
# invoked to print out the data returned by
# the plugin.
#
# Format of the response hash:
# {data => [ 'data str1', 'data str2', '...' ] }
#
# Results are printed as:
# data str1
# data str2
#
# or:
# {data => [ {desc => [ 'desc1' ],
# contents => [ 'contents1' ] },
# {desc => [ 'desc2 ],
# contents => [ 'contents2' ] }
# :
# ] }
# NOTE: In this format, only the data array can have more than one
# element. All other arrays are assumed to be a single element.
# Results are printed as:
# desc1: contents1
# desc2: contents2
#
# or:
# {node => [ {name => ['node1'],
# data => [ {desc => [ 'node1 desc' ],
# contents => [ 'node1 contents' ] } ] },
# {name => ['node2'],
# data => [ {desc => [ 'node2 desc' ],
# contents => [ 'node2 contents' ] } ] },
# :
# ] }
# NOTE: Only the node array can have more than one element.
# All other arrays are assumed to be a single element.
#
# This was generated from the corresponding HTML:
# <xcatrequest>
# <node>
# <name>node1</name>
# <data>
# <desc>node1 desc</desc>
# <contents>node1 contents</contents>
# </data>
# </node>
# <node>
# <name>node2</name>
# <data>
# <desc>node2 desc</desc>
# <contents>node2 contents</contents>
# </data>
# </node>
# </xcatrequest>
#
# Results are printed as:
# node_name: desc: contents
##########################################
sub handle_response {
my $rsp = shift;
# Handle {node} structure
if ($rsp->{errorcode}) {
foreach my $ecode (@{$rsp->{errorcode}}) {
$exitcode |= $ecode;
}
}
if ($rsp->{node}) {
my $nodes=($rsp->{node});
my $node;
foreach $node (@$nodes) {
my $desc=$node->{name}->[0];
if ($node->{errorcode}) {
foreach my $ecode (@{$node->{errorcode}}) {
$exitcode |= $ecode;
}
}
if ($node->{data}) {
if (ref(\($node->{data}->[0])) eq 'SCALAR') {
$desc=$desc.": ".$node->{data}->[0];
} else {
if ($node->{data}->[0]->{desc}) {
$desc=$desc.": ".$node->{data}->[0]->{desc}->[0];
}
if ($node->{data}->[0]->{contents}) {
$desc="$desc: ".$node->{data}->[0]->{contents}->[0];
}
}
}
if ($desc) {
print "$desc\n";
}
}
}
# Handle {data} structure with no nodes
if ($rsp->{data}) {
my $data=($rsp->{data});
my $data_entry;
foreach $data_entry (@$data) {
my $desc;
if (ref(\($data_entry)) eq 'SCALAR') {
$desc=$data_entry;
} else {
if ($data_entry->{desc}) {
$desc=$data_entry->{desc}->[0];
}
if ($data_entry->{contents}) {
if ($desc) {
$desc="$desc: ".$data_entry->{contents}->[0];
} else {
$desc=$data_entry->{contents}->[0];
}
}
}
if ($desc) {
print "$desc\n";
}
}
}
}

View File

@ -0,0 +1,25 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use File::Basename;
#######################################
# It handles the commands without noderanges.
#######################################
my $bname = basename($0);
my $cmd;
if($bname =~ /xcatclientnnr/) {
$cmd = shift @ARGV;
} elsif ($bname =~/^(.*$)/) {
$cmd = $1;
} else {
printf("Bad usage\n");
exit(1);
}
exec("/usr/bin/xcatclient $cmd NO_NODE_RANGE @ARGV 2>&1");
#if (system("/usr/bin/xcatclient $cmd NO_NODE_RANGE @ARGV 2>&1") != 0) {
# print "$cmd failed: $?\n";
#}
#exit;

27
xCAT-client-2.0/usr/bin/xcoll Executable file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use Data::Dumper;
my %output;
while (<STDIN>) {
my $node;
my $output;
if (/:/) {
($node,$output) = split /:/,$_,2;
} else {
$node= "UNKNOWN";
$output = $_;
}
$output =~ s/^ //;
$output{$node}.=$output;
}
my %collated;
foreach (keys %output) {
$collated{$output{$_}}->{$_}=1;
}
foreach (keys %collated) {
my $nodes = join(',',sort (keys %{$collated{$_}}));
print "====================================\n";
print "$nodes\n";
print "====================================\n";
print $_;
}

View File

@ -0,0 +1,446 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use IO::Socket::SSL;
use IO::Socket::INET;
use File::Basename;
use Data::Dumper;
use Getopt::Long;
use xCAT::MsgUtils;
use xCAT::Client submit_request;
my $bname = basename($0);
#-----------------------------------------------------------------------------
=head1 xdsh/xdcp
This program is the client interface for xdsh/xdcp.
xdsh/xdcp command
This is the client interface for the xdsh/xdcp command
Call parse_args to verify input
Build hash and submit request
Note: xdsh/xdcp (dsh/dcp for xCAT) only supports a subset of the options
supported by dsh/dcp. See help and man page of each command for the
differences.
=cut
#-----------------------------------------------------------------------------
# Main
#$ENV{XCATBYPASS} = "yes"; # set bypass mode
my $rc = 0;
# check for help and Environment Variables
if ($bname eq "xdsh")
{
&parse_args_xdsh;
}
else
{ # xdcp
&parse_args_xdcp;
}
# report unsupported dsh exports
&check_invalid_exports;
my $cmdref;
$cmdref->{command}->[0] = $bname; # save my command name
my $arg = shift(@ARGV);
while ($arg =~ /^-/)
{
push(@{$cmdref->{arg}}, $arg); # save command arguments
$arg = shift(@ARGV);
}
$cmdref->{noderange}->[0] = $arg; # save nodes
#
# add flgs for all the valid dsh/dcp Env Variable set
#
# The first ones are common to dsh/dcp
# if nodes from file and none on the command line
if ($ENV{'DSH_NODE_RSH'})
{
my $value = $ENV{'DSH_NODE_RSH'};
push(@{$cmdref->{arg}}, "-r $value ");
}
if ($ENV{'DSH_NODE_OPTS'})
{
my $value = $ENV{'DSH_NODE_OPTS'};
push(@{$cmdref->{arg}}, "-o $value ");
}
if ($ENV{'DSH_FANOUT'})
{
my $value = $ENV{'DSH_FANOUT'};
push(@{$cmdref->{arg}}, "-f $value ");
}
if ($ENV{'DSH_TIMEOUT'})
{
my $value = $ENV{'DSH_TIMEOUT'};
push(@{$cmdref->{arg}}, "-t $value ");
}
if ($bname eq "xdsh")
{
if ($ENV{'DSH_REPORT'})
{
my $value = $ENV{'DSH_REPORT'};
push(@{$cmdref->{arg}}, "--report $value ");
}
}
## set XCAT Context always ##
push(@{$cmdref->{arg}}, "-C XCAT");
foreach (@ARGV) { push(@{$cmdref->{arg}}, $_); }
xCAT::Client::submit_request($cmdref, \&handle_response);
exit $rc;
#-----------------------------------------------------------------------------
=head3 parse_args_xdsh
Parses for dsh input
Check if the command ask for help and display usage
=cut
#-----------------------------------------------------------------------------
sub parse_args_xdsh
{
my $usagemsg1 =
" xdsh -h \n xdsh -q \n xdsh -v \n xdsh [noderange] [group]\n";
my $usagemsg2 =
" [-C context] [-c] [-e] [-E environment_file] [-f fanout]\n";
my $usagemsg3 =
" [-F output_file] [-i] [-l user_ID] [-L] [--log log_file]\n";
my $usagemsg4 = " [-m] [-o options] [-Q] [-r remote_shell] \n";
my $usagemsg5 =
" [-s] [-S ksh | csh] [-t timeout] [-T] [-X environment variables] [-v] [-z]\n";
my $usagemsg6 =
" [--report report_path] [--report-name report_name]\n";
my $usagemsg7 = " [command_list]\n";
my $usagemsg8 = "Note:Context is always set to XCAT\n";
my $usagemsg .= $usagemsg1 .= $usagemsg2 .= $usagemsg3 .= $usagemsg4 .=
$usagemsg5 .= $usagemsg6 .= $usagemsg7;
Getopt::Long::Configure("posix_default");
Getopt::Long::Configure("no_gnu_compat");
Getopt::Long::Configure("bundling");
if (
!GetOptions(
'e|execute' => \$::EXECUTE,
'f|fanout=i' => \$::FANOUT,
'h|help' => \$::HELP,
'i|notify' => \$::NOTIFY,
'l|user=s' => \$::USER,
'm|monitor' => \$::MONITOR,
'o|node-options=s' => \$::NODEOPTS,
'q|show-config' => \$::SHOWCFG,
'r|node-rsh=s' => \$::NODERSH,
's|stream' => \$::STREAM,
't|timeout=i' => \$::TIMEOUT,
'v|verify' => \$::VERIFY,
'z|exit-status' => \$::EXITSTAT,
'E|environment=s' => \$::ENV,
'F|output-file=s' => \$::OUTPUTFILE,
'I|ignore-sig|ignoresig=s' => \$::IGNORESIG,
'L|no-locale' => \$::NOLOCALE,
'Q|silent' => \$::SILENT,
'S|syntax=s' => \$::SYNTAX,
'T|trace' => \$::TRACE,
'V|version' => \$::VERSION,
'command-name|commandName=s' => \$::COMMANDNAME,
'command-description|commandDescription=s' => \$::COMMANDDES,
'log=s' => \$::LOG,
'report=s' => \$::REPORT,
'R|reports=s' => \$::REPORTS,
'report-name|reportName=s' => \$::REPORTNAME,
'W|noFileWriting' => \$::NOFILEWRITE,
'w|wcoll=s' => \$::WCOLL,
'X:s' => \$::IGNORENV
)
)
{
xCAT::MsgUtils->message("I", "$usagemsg");
exit 1;
}
if ($::HELP)
{
xCAT::MsgUtils->message("I", "$usagemsg");
exit 0;
}
}
#-----------------------------------------------------------------------------
=head3 parse_args_xdcp
Parses for dcp input
Check if the command ask for help and display usage
=cut
#-----------------------------------------------------------------------------
sub parse_args_xdcp
{
my $usagemsg1 =
" xdcp -h \n xdcp -q \n xdcp -v \n xdcp [noderange] [group]\n";
my $usagemsg2 = " [-C context] [-c] [-f fanout] [-l user_ID]\n";
my $usagemsg3 =
" [-o options] [-s] [-p] [-P] [-Q] [-r node_remote_copy]\n";
my $usagemsg4 =
" [-R] [-t timeout] [-T] [-X environment variables] [-v] \n";
my $usagemsg5 = " source_file... target_path\n";
my $usagemsg6 = "Note:Context is always set to XCAT\n";
my $usagemsg .= $usagemsg1 .= $usagemsg2 .= $usagemsg3 .= $usagemsg4 .=
$usagemsg5 .= $usagemsg6;
Getopt::Long::Configure("posix_default");
Getopt::Long::Configure("no_gnu_compat");
Getopt::Long::Configure("bundling");
if (
!GetOptions(
'f|fanout=i' => \$::FANOUT,
'h|help' => \$::HELP,
'l|user=s' => \$::USER,
'o|node-options=s' => \$::NODEOPTS,
'p|preserver' => \$::PRESERVE,
'q|show-config' => \$::SHOWCFG,
'r|c|node-rcp=s' => \$::NODERCP,
's' => \$::RSYNC,
't|timeout=i' => \$::TIMEOUT,
'v|verify' => \$::VERIFY,
'Q|silent' => \$::SILENT,
'P|pull' => \$::PULL,
'R|recursive' => \$::RECURSIVE,
'T|trace' => \$::TRACE,
'V|version' => \$::VERSION,
'w|wcoll=s' => \$::WCOLL,
'X:s' => \$::IGNORENV
)
)
{
xCAT::MsgUtils->message("I", "$usagemsg");
exit 1;
}
if ($::HELP)
{
xCAT::MsgUtils->message("I", "$usagemsg");
exit 0;
}
}
#-----------------------------------------------------------------------------
=head3 check_invalid_exports
Check for unsupported dsh exports and warns
=cut
#-----------------------------------------------------------------------------
sub check_invalid_exports
{
##
# Check for unsupported Environment Variables
# DSH_DEVICE_LIST, DSH_DEVICE_OPTS, DSH_DEVICE_RCP,DSH_DEVICE_RSH,
# DSH_NODEGROUP_PATH
##
if ($ENV{'DSH_NODE_LIST'})
{
xCAT::MsgUtils->message(
"I",
"DSH_NODE_LIST is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_DEVICE_LIST'})
{
xCAT::MsgUtils->message(
"I",
"DSH_DEVICE_LIST is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_DEVICE_OPTS'})
{
xCAT::MsgUtils->message(
"I",
"DSH_DEVICE_OPTS is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_DEVICE_RCP'})
{
xCAT::MsgUtils->message(
"I",
"DSH_DEVICE_RCP is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_DEVICE_RSH'})
{
xCAT::MsgUtils->message(
"I",
"DSH_DEVICE_RSH is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_NODEGROUP_PATH'})
{
xCAT::MsgUtils->message(
"I",
"DSH_NODEGROUP_PATH is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'RSYNC_RSH'})
{
xCAT::MsgUtils->message("I",
" RSYNC_RSH is set but is not supported. It will be ignored.\n");
}
}
#-----------------------------------------------------------------------------
=head3 handle_response
handle_response is the callback that is
invoked to print out the data returned by
the plugin.
Format of the response hash:
{data => [ 'data str1', 'data str2', '...' ] }
Results are printed as:
data str1
data str2
or:
{data => [ {desc => [ 'desc1' ],
contents => [ 'contents1' ] },
{desc => [ 'desc2 ],
contents => [ 'contents2' ] }
:
] }
NOTE: In this format, only the data array can have more than one
element. All other arrays are assumed to be a single element.
Results are printed as:
desc1: contents1
desc2: contents2
or:
{node => [ {name => ['node1'],
data => [ {desc => [ 'node1 desc' ],
contents => [ 'node1 contents' ] } ] },
{name => ['node2'],
data => [ {desc => [ 'node2 desc' ],
contents => [ 'node2 contents' ] } ] },
:
] }
NOTE: Only the node array can have more than one element.
All other arrays are assumed to be a single element.
This was generated from the corresponding HTML:
<xcatrequest>
<node>
<name>node1</name>
<data>
<desc>node1 desc</desc>
<contents>node1 contents</contents>
</data>
</node>
<node>
<name>node2</name>
<data>
<desc>node2 desc</desc>
<contents>node2 contents</contents>
</data>
</node>
</xcatrequest>
Results are printed as:
node_name: desc: contents
=cut
#-----------------------------------------------------------------------------
sub handle_response
{
my $rsp = shift;
# Handle {node} structure
if ($rsp->{node})
{
my $nodes = ($rsp->{node});
my $node;
foreach $node (@$nodes)
{
my $desc = $node->{name}->[0];
if ($node->{data})
{
if (ref(\($node->{data}->[0])) eq 'SCALAR')
{
$desc = $desc . ": " . $node->{data}->[0];
}
else
{
if ($node->{data}->[0]->{desc})
{
$desc = $desc . ": " . $node->{data}->[0]->{desc}->[0];
}
if ($node->{data}->[0]->{contents})
{
$desc = "$desc: " . $node->{data}->[0]->{contents}->[0];
}
}
}
if ($desc)
{
print "$desc\n";
}
}
}
# Handle {data} structure with no nodes
if ($rsp->{data})
{
my $data = ($rsp->{data});
my $data_entry;
foreach $data_entry (@$data)
{
my $desc;
if (ref(\($data_entry)) eq 'SCALAR')
{
$desc = $data_entry;
}
else
{
if ($data_entry->{desc})
{
$desc = $data_entry->{desc}->[0];
}
if ($data_entry->{contents})
{
if ($desc)
{
$desc = "$desc: " . $data_entry->{contents}->[0];
}
else
{
$desc = $data_entry->{contents}->[0];
}
}
}
if ($desc)
{
print "$desc\n";
}
}
}
}

View File

@ -0,0 +1,42 @@
#!/bin/bash
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
function cexit {
if [ -d /tmp/tabedit.$$ ]; then
rm -rf /tmp/tabedit.$$;
fi
exit
}
trap cexit 2 15
TABLE=$1
if [ -z "$EDITOR" ]; then
echo "Define EDITOR environment variable before running this command"
exit 1
fi
if [ -z "$TABLE" ]; then
echo "Usage: tabedit <tablename>";
exit 1
fi
mkdir -p /tmp/tabedit.$$/
xcatclientnnr tabdump $1 > /tmp/tabedit.$$/$1.csv
#use md5sum to check if it actually changes..
SUM=`md5sum /tmp/tabedit.$$/$1.csv`
EXIT=0
while [ $EXIT -eq 0 ]; do
cd /tmp/tabedit.$$
"$EDITOR" $1.csv
cd -
NEWSUM=`md5sum /tmp/tabedit.$$/$1.csv`
if [ "$NEWSUM" == "$SUM" ]; then
echo "No file modifications detected, not restoring."
break;
fi
if `dirname $0`/tabrestore /tmp/tabedit.$$/$1.csv; then
break;
else
echo "Above errors occured, hit enter to edit, or ctrl-c to abort"
read JNK
fi
done
cexit

View File

@ -0,0 +1,161 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#Just like xcatclient, but needs to read a file in and pass it as $request->data
use IO::Socket::SSL;
use IO::Socket::INET;
use File::Basename;
use Data::Dumper;
use xCAT::Client submit_request;
my $bname = basename($0);
#########################################
# Main
# Build hash and submit request
#########################################
my $cmdref;
my $exitcode=0;
$cmdref->{command}->[0] = "tabrestore";
my $arg=shift(@ARGV);
while ($arg =~ /^-/) {
push (@{$cmdref->{arg}}, $arg);
$arg=shift(@ARGV);
}
unless ($arg) {
printf("Usage: tabrestore [tablename].csv\n");
exit(1);
}
my $filename = $arg;
unless (-r $filename) {
printf("Unable to open $arg for reading.\n");
exit(1);
}
my $tabname = basename($filename);
$tabname =~ s/\..*//;
$cmdref->{table}->[0] = $tabname;
my $fh;
open($fh,$filename);
while (<$fh>) {
push @{$cmdref->{data}},$_;
}
foreach (@ARGV) { push (@{$cmdref->{arg}}, $_ ); }
#$cmdref->{arg}=\@ARGV;
xCAT::Client::submit_request($cmdref,\&handle_response);
exit $exitcode;
##########################################
# handle_response is the callback that is
# invoked to print out the data returned by
# the plugin.
#
# Format of the response hash:
# {data => [ 'data str1', 'data str2', '...' ] }
#
# Results are printed as:
# data str1
# data str2
#
# or:
# {data => [ {desc => [ 'desc1' ],
# contents => [ 'contents1' ] },
# {desc => [ 'desc2 ],
# contents => [ 'contents2' ] }
# :
# ] }
# NOTE: In this format, only the data array can have more than one
# element. All other arrays are assumed to be a single element.
# Results are printed as:
# desc1: contents1
# desc2: contents2
#
# or:
# {node => [ {name => ['node1'],
# data => [ {desc => [ 'node1 desc' ],
# contents => [ 'node1 contents' ] } ] },
# {name => ['node2'],
# data => [ {desc => [ 'node2 desc' ],
# contents => [ 'node2 contents' ] } ] },
# :
# ] }
# NOTE: Only the node array can have more than one element.
# All other arrays are assumed to be a single element.
#
# This was generated from the corresponding HTML:
# <xcatrequest>
# <node>
# <name>node1</name>
# <data>
# <desc>node1 desc</desc>
# <contents>node1 contents</contents>
# </data>
# </node>
# <node>
# <name>node2</name>
# <data>
# <desc>node2 desc</desc>
# <contents>node2 contents</contents>
# </data>
# </node>
# </xcatrequest>
#
# Results are printed as:
# node_name: desc: contents
##########################################
sub handle_response {
my $rsp = shift;
# Handle {node} structure
if ($rsp->{node}) {
my $nodes=($rsp->{node});
my $node;
foreach $node (@$nodes) {
my $desc=$node->{name}->[0];
if ($node->{data}) {
if (ref(\($node->{data}->[0])) eq 'SCALAR') {
$desc=$desc.": ".$node->{data}->[0];
} else {
if ($node->{data}->[0]->{desc}) {
$desc=$desc.": ".$node->{data}->[0]->{desc}->[0];
}
if ($node->{data}->[0]->{contents}) {
$desc="$desc: ".$node->{data}->[0]->{contents}->[0];
}
}
}
if ($desc) {
print "$desc\n";
}
}
}
# Handle {data} structure with no nodes
if ($rsp->{error}) {
$exitcode=1;
}
if ($rsp->{data}) {
my $data=($rsp->{data});
my $data_entry;
foreach $data_entry (@$data) {
my $desc;
if (ref(\($data_entry)) eq 'SCALAR') {
$desc=$data_entry;
} else {
if ($data_entry->{desc}) {
$desc=$data_entry->{desc}->[0];
}
if ($data_entry->{contents}) {
if ($desc) {
$desc="$desc: ".$data_entry->{contents}->[0];
} else {
$desc=$data_entry->{contents}->[0];
}
}
}
if ($desc) {
print "$desc\n";
}
}
}
}

View File

@ -0,0 +1,4 @@
Add a basic xcoll, without reverse noderange, reverse noderange will come post alpha
--This line, and those below, will be ignored--
AM bin/xcoll

View File

@ -0,0 +1,89 @@
Summary: Core executables and data of the xCAT management project
Name: xCAT-client
Version: 2.0
Release: snap%(date +"%Y%m%d%H%M")
License: EPL
Group: Applications/System
Source: xCAT-client-2.0.tar.gz
Packager: IBM Corp.
Vendor: IBM Corp.
Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
Prefix: %{_prefix}
BuildRoot: /var/tmp/%{name}-%{version}-%{release}-root
# AIX will build with an arch of "ppc"
%ifos linux
BuildArch: noarch
%endif
Provides: xCAT-client = %{version}
%description
xCAT-client provides the fundamental xCAT commands (chtab, chnode, rpower, etc) helpful in administrating systems at scale, with particular attention paid to large HPC clusters.
%prep
%setup -q
%build
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/bin
mkdir -p $RPM_BUILD_ROOT/usr/sbin
mkdir -p $RPM_BUILD_ROOT/usr/share/xcat/scripts
cp usr/bin/* $RPM_BUILD_ROOT/usr/bin
chmod 755 $RPM_BUILD_ROOT/usr/bin/*
cp usr/sbin/* $RPM_BUILD_ROOT/usr/sbin
chmod 755 $RPM_BUILD_ROOT/usr/sbin/*
#cp usr/share/xcat/scripts/setup-local-client.sh $RPM_BUILD_ROOT/usr/share/xcat/scripts/setup-local-client.sh
#chmod 755 $RPM_BUILD_ROOT/usr/share/xcat/scripts/setup-local-client.sh
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/rpower
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/sbin/makedhcp
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/sbin/makehosts
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/sbin/nodeset
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/sbin/makeconservercf
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/rbeacon
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/rvitals
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/rinv
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/rspreset
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/rsetboot
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/rbootseq
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/reventlog
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/nodels
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/nodech
ln -sf /usr/bin/xcatclient $RPM_BUILD_ROOT/usr/bin/noderm
ln -sf /usr/bin/xcatclientnnr $RPM_BUILD_ROOT/usr/sbin/tabdump
ln -sf /usr/bin/xcatclientnnr $RPM_BUILD_ROOT/usr/sbin/makedns
ln -sf /usr/bin/xcatclientnnr $RPM_BUILD_ROOT/usr/bin/gettab
ln -sf /usr/bin/xcatclientnnr $RPM_BUILD_ROOT/usr/sbin/nodeadd
ln -sf /usr/bin/xcatclientnnr $RPM_BUILD_ROOT/usr/sbin/makenetworks
ln -sf /usr/bin/xcatclientnnr $RPM_BUILD_ROOT/usr/sbin/copycds
ln -sf /usr/bin/xcatclientnnr $RPM_BUILD_ROOT/usr/bin/regnotif
ln -sf /usr/bin/xcatclientnnr $RPM_BUILD_ROOT/usr/bin/unregnotif
ln -sf /usr/bin/xcatDBcmds $RPM_BUILD_ROOT/usr/bin/xdefmk
ln -sf /usr/bin/xcatDBcmds $RPM_BUILD_ROOT/usr/bin/xdefch
ln -sf /usr/bin/xcatDBcmds $RPM_BUILD_ROOT/usr/bin/xdefls
ln -sf /usr/bin/xcatDBcmds $RPM_BUILD_ROOT/usr/bin/xdefrm
ln -sf /usr/bin/xdsh $RPM_BUILD_ROOT/usr/bin/xdcp
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc README
%doc LICENSE.html
/usr/bin/*
/usr/sbin/*
#/usr/share/xcat/scripts/setup-local-client.sh
%changelog
* Wed May 2 2007 - Norm Nott <nott@us.ibm.com>
- Made changes to make this work on AIX
* Tue Feb 20 2007 Jarrod Johnson <jbjohnso@us.ibm.com>
- Start core rpm for 1.3 work

326
xCAT-nbroot/LICENSE.html Normal file
View File

@ -0,0 +1,326 @@
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=ProgId content=Word.Document>
<meta name=Generator content="Microsoft Word 9">
<meta name=Originator content="Microsoft Word 9">
<title>Eclipse Public License - Version 1.0</title>
<!--[if gte mso 9]><xml>
<o:DocumentProperties>
<o:Revision>2</o:Revision>
<o:TotalTime>3</o:TotalTime>
<o:Created>2004-03-05T23:03:00Z</o:Created>
<o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
<o:Pages>4</o:Pages>
<o:Words>1626</o:Words>
<o:Characters>9270</o:Characters>
<o:Lines>77</o:Lines>
<o:Paragraphs>18</o:Paragraphs>
<o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
<o:Version>9.4402</o:Version>
</o:DocumentProperties>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:TrackRevisions/>
</w:WordDocument>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:553679495 -2147483648 8 0 66047 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p
{margin-right:0in;
mso-margin-top-alt:auto;
mso-margin-bottom-alt:auto;
margin-left:0in;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p.BalloonText, li.BalloonText, div.BalloonText
{mso-style-name:"Balloon Text";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:8.0pt;
font-family:Tahoma;
mso-fareast-font-family:"Times New Roman";}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
</head>
<body lang=EN-US style='tab-interval:.5in'>
<div class=Section1>
<p align=center style='text-align:center'><b>Eclipse Public License - v 1.0</b>
</p>
<p><span style='font-size:10.0pt'>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE,
REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
OF THIS AGREEMENT.</span> </p>
<p><b><span style='font-size:10.0pt'>1. DEFINITIONS</span></b> </p>
<p><span style='font-size:10.0pt'>&quot;Contribution&quot; means:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
in the case of the initial Contributor, the initial code and documentation
distributed under this Agreement, and<br clear=left>
b) in the case of each subsequent Contributor:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
changes to the Program, and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
additions to the Program;</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>where
such changes and/or additions to the Program originate from and are distributed
by that particular Contributor. A Contribution 'originates' from a Contributor
if it was added to the Program by such Contributor itself or anyone acting on
such Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in conjunction
with the Program under their own license agreement, and (ii) are not derivative
works of the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Contributor&quot; means any person or
entity that distributes the Program.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Licensed Patents &quot; mean patent
claims licensable by a Contributor which are necessarily infringed by the use
or sale of its Contribution alone or when combined with the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Program&quot; means the Contributions
distributed in accordance with this Agreement.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Recipient&quot; means anyone who
receives the Program under this Agreement, including all Contributors.</span> </p>
<p><b><span style='font-size:10.0pt'>2. GRANT OF RIGHTS</span></b> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
Subject to the terms of this Agreement, each Contributor hereby grants Recipient
a non-exclusive, worldwide, royalty-free copyright license to<span
style='color:red'> </span>reproduce, prepare derivative works of, publicly
display, publicly perform, distribute and sublicense the Contribution of such
Contributor, if any, and such derivative works, in source code and object code
form.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide,<span style='color:green'> </span>royalty-free
patent license under Licensed Patents to make, use, sell, offer to sell, import
and otherwise transfer the Contribution of such Contributor, if any, in source
code and object code form. This patent license shall apply to the combination
of the Contribution and the Program if, at the time the Contribution is added
by the Contributor, such addition of the Contribution causes such combination
to be covered by the Licensed Patents. The patent license shall not apply to
any other combinations which include the Contribution. No hardware per se is
licensed hereunder. </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>c)
Recipient understands that although each Contributor grants the licenses to its
Contributions set forth herein, no assurances are provided by any Contributor
that the Program does not infringe the patent or other intellectual property
rights of any other entity. Each Contributor disclaims any liability to Recipient
for claims brought by any other entity based on infringement of intellectual
property rights or otherwise. As a condition to exercising the rights and
licenses granted hereunder, each Recipient hereby assumes sole responsibility
to secure any other intellectual property rights needed, if any. For example,
if a third party patent license is required to allow Recipient to distribute
the Program, it is Recipient's responsibility to acquire that license before
distributing the Program.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>d)
Each Contributor represents that to its knowledge it has sufficient copyright
rights in its Contribution, if any, to grant the copyright license set forth in
this Agreement. </span></p>
<p><b><span style='font-size:10.0pt'>3. REQUIREMENTS</span></b> </p>
<p><span style='font-size:10.0pt'>A Contributor may choose to distribute the
Program in object code form under its own license agreement, provided that:</span>
</p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it complies with the terms and conditions of this Agreement; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
its license agreement:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
effectively disclaims on behalf of all Contributors all warranties and
conditions, express and implied, including warranties or conditions of title
and non-infringement, and implied warranties or conditions of merchantability
and fitness for a particular purpose; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
effectively excludes on behalf of all Contributors all liability for damages,
including direct, indirect, special, incidental and consequential damages, such
as lost profits; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iii)
states that any provisions which differ from this Agreement are offered by that
Contributor alone and not by any other party; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iv)
states that source code for the Program is available from such Contributor, and
informs licensees how to obtain it in a reasonable manner on or through a
medium customarily used for software exchange.<span style='color:blue'> </span></span></p>
<p><span style='font-size:10.0pt'>When the Program is made available in source
code form:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it must be made available under this Agreement; and </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b) a
copy of this Agreement must be included with each copy of the Program. </span></p>
<p><span style='font-size:10.0pt'>Contributors may not remove or alter any
copyright notices contained within the Program. </span></p>
<p><span style='font-size:10.0pt'>Each Contributor must identify itself as the
originator of its Contribution, if any, in a manner that reasonably allows
subsequent Recipients to identify the originator of the Contribution. </span></p>
<p><b><span style='font-size:10.0pt'>4. COMMERCIAL DISTRIBUTION</span></b> </p>
<p><span style='font-size:10.0pt'>Commercial distributors of software may
accept certain responsibilities with respect to end users, business partners
and the like. While this license is intended to facilitate the commercial use
of the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create potential
liability for other Contributors. Therefore, if a Contributor includes the
Program in a commercial product offering, such Contributor (&quot;Commercial
Contributor&quot;) hereby agrees to defend and indemnify every other
Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and
costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other
legal actions brought by a third party against the Indemnified Contributor to
the extent caused by the acts or omissions of such Commercial Contributor in
connection with its distribution of the Program in a commercial product
offering. The obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In order
to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
Contributor in writing of such claim, and b) allow the Commercial Contributor
to control, and cooperate with the Commercial Contributor in, the defense and
any related settlement negotiations. The Indemnified Contributor may participate
in any such claim at its own expense.</span> </p>
<p><span style='font-size:10.0pt'>For example, a Contributor might include the
Program in a commercial product offering, Product X. That Contributor is then a
Commercial Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance claims and
warranties are such Commercial Contributor's responsibility alone. Under this
section, the Commercial Contributor would have to defend claims against the
other Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.</span> </p>
<p><b><span style='font-size:10.0pt'>5. NO WARRANTY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
responsible for determining the appropriateness of using and distributing the
Program and assumes all risks associated with its exercise of rights under this
Agreement , including but not limited to the risks and costs of program errors,
compliance with applicable laws, damage to or loss of data, programs or
equipment, and unavailability or interruption of operations. </span></p>
<p><b><span style='font-size:10.0pt'>6. DISCLAIMER OF LIABILITY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
<p><b><span style='font-size:10.0pt'>7. GENERAL</span></b> </p>
<p><span style='font-size:10.0pt'>If any provision of this Agreement is invalid
or unenforceable under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this Agreement, and without
further action by the parties hereto, such provision shall be reformed to the
minimum extent necessary to make such provision valid and enforceable.</span> </p>
<p><span style='font-size:10.0pt'>If Recipient institutes patent litigation
against any entity (including a cross-claim or counterclaim in a lawsuit)
alleging that the Program itself (excluding combinations of the Program with
other software or hardware) infringes such Recipient's patent(s), then such
Recipient's rights granted under Section 2(b) shall terminate as of the date
such litigation is filed. </span></p>
<p><span style='font-size:10.0pt'>All Recipient's rights under this Agreement
shall terminate if it fails to comply with any of the material terms or
conditions of this Agreement and does not cure such failure in a reasonable
period of time after becoming aware of such noncompliance. If all Recipient's
rights under this Agreement terminate, Recipient agrees to cease use and
distribution of the Program as soon as reasonably practicable. However,
Recipient's obligations under this Agreement and any licenses granted by
Recipient relating to the Program shall continue and survive. </span></p>
<p><span style='font-size:10.0pt'>Everyone is permitted to copy and distribute
copies of this Agreement, but in order to avoid inconsistency the Agreement is
copyrighted and may only be modified in the following manner. The Agreement
Steward reserves the right to publish new versions (including revisions) of
this Agreement from time to time. No one other than the Agreement Steward has
the right to modify this Agreement. The Eclipse Foundation is the initial
Agreement Steward. The Eclipse Foundation may assign the responsibility to
serve as the Agreement Steward to a suitable separate entity. Each new version
of the Agreement will be given a distinguishing version number. The Program
(including Contributions) may always be distributed subject to the version of
the Agreement under which it was received. In addition, after a new version of
the Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly stated
in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
the intellectual property of any Contributor under this Agreement, whether
expressly, by implication, estoppel or otherwise. All rights in the Program not
expressly granted under this Agreement are reserved.</span> </p>
<p><span style='font-size:10.0pt'>This Agreement is governed by the laws of the
State of New York and the intellectual property laws of the United States of
America. No party to this Agreement will bring a legal action under this
Agreement more than one year after the cause of action arose. Each party waives
its rights to a jury trial in any resulting litigation.</span> </p>
<p class=MsoNormal><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>
</div>
</body>
</html>

8
xCAT-nbroot/mkrpm Executable file
View File

@ -0,0 +1,8 @@
cd `dirname $0`
tar --exclude .svn -czvf xcat-nbrootoverlay.tar.gz -C overlay/ .
cp *.gz /usr/src/redhat/SOURCES
cp xcat-core-nbroot.spec /usr/src/redhat/SPECS
rm xcat-nbrootoverlay.tar.gz
rpmbuild -ba /usr/src/redhat/SPECS/xcat-core-nbroot.spec --target $1
cd -

View File

@ -0,0 +1,28 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
modprobe ipmi_si
modprobe ipmi_devintf
while ! getipmi.awk
do
echo "Retrying retrieval of IPMI settings from server"
done
BMCIP=`grep bmcip /tmp/ipmi.data |awk -F\> '{print $2}'|awk -F\< '{print $1}'`
BMCGW=`grep gateway /tmp/ipmi.data |awk -F\> '{print $2}'|awk -F\< '{print $1}'`
BMCNM=`grep netmask /tmp/ipmi.data |awk -F\> '{print $2}'|awk -F\< '{print $1}'`
BMCUS=`grep username /tmp/ipmi.data |awk -F\> '{print $2}'|awk -F\< '{print $1}'`
BMCPW=`grep password /tmp/ipmi.data |awk -F\> '{print $2}'|awk -F\< '{print $1}'`
ipmitool lan set 1 ipsrc static
ipmitool lan set 1 ipaddr $BMCIP
ipmitool lan set 1 netmask $BMCNM
if [ ! -z "$BMCGW" ]; then
ipmitool lan set 1 defgw ipaddr $BMCGW
fi
ipmitool user disable 1
ipmitool user disable 3
ipmitool user disable 4
ipmitool user enable 2
ipmitool user priv 2 4 1
ipmitool user set name 2 $BMCUS
ipmitool user set password 2 $BMCPW
echo "Set up following user table: "
ipmitool user list 1

113
xCAT-nbroot/overlay/bin/dodestiny Executable file
View File

@ -0,0 +1,113 @@
#!/bin/sh
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
for parm in `cat /proc/cmdline`; do
key=`echo $parm|awk -F= '{print $1}'`
if [ "$key" == "xcatd" ]; then
XCATDEST=`echo $parm|awk -F= '{print $2}'`
fi
done
export XCATMASTER=`echo $XCATDEST | awk -F: '{print $1}'`
export XCATPORT=`echo $XCATDEST | awk -F: '{print $2}'`
while :; do
DESTINY=`grep destiny /tmp/destiny | awk -F'>' '{print $2}'|awk -F'<' '{print $1}'`
DEST=`echo $DESTINY|awk -F= '{print $1}'` #No bash, no tricks
TARG=`echo $DESTINY|awk -F= '{print $2}'` #No bash, no tricks
DESTINY=`echo $DESTINY|awk '{print $1}'` #No bash, no tricks
if [ $DESTINY == "standby" ]; then
echo "Server notified us of standby condition, please check chain table".
echo "Retrying destiny in 15 seconds"
usleep 15000000 # something may be transiently wrong, check back in 15 seconds
while ! getdestiny.awk; do
echo "Retrying destiny retrieval"
done
exec $0
fi
if [ $DESTINY == "shell" ]; then
echo "Server notified us to stay in shell state, stopping destiny requests"
exit
fi
if [ $DESTINY == "discover" ]; then
echo "MAC discovery begins"
minixcatd.awk &
while [ ! -r /restart ]; do
ifconfig -a|grep HWaddr|grep -v sit|awk '{print $1 "|" $5}'
MTM="unknown"
SERIAL="unknown"
if [ -x /bin/vpddecode ]; then
MTM=`(/bin/vpddecode|grep Type || echo "unknown unknown: unknown")|awk '{print $3}'`
SERIAL=`(/bin/vpddecode|grep "Box Serial" || echo "unknown unknown unknown: unknown")|awk '{print $4}'`
fi
if [ "$MTM" == "unknown" -a -x /bin/dmidecode ]; then #This gets a bit hackish... iDataplex
MTM=`dmidecode |grep -A4 "^System Information"|grep "Product Name"|awk -F'[' '{print $2}'|awk -F']' '{print $1}'`
SERIAL=`dmidecode |grep -A4 "^System Information"|grep "Serial Number"|awk -F: '{print $2}'`
fi
if [ -r /proc/device-tree/model ]; then
MTM=`cat /proc/device-tree/model |awk -F, '{print $2}'`
fi
(
echo "<xcatrequest>"
echo "<command>findme</command>"
echo "<arch>"`uname -m`"</arch>"
for i in `ifconfig -a|grep HWaddr|grep -v sit|awk '{print $1 "|" $5}'`; do
IFACE=`echo $i|awk -F'|' '{print $1}'`
DRIVER=`ethtool -i $IFACE|grep ^driver|awk '{print $2}'`
echo "<mac>$DRIVER|$i</mac>"
done
modprobe ipmi_devintf
if modprobe ipmi_si; then
echo "<mac>bmc|bmc|"`ipmitool lan print 1|grep ^MAC|awk '{print $4}'`"</mac>"
fi
rmmod ipmi_si
rmmod ipmi_devintf
if [ "$MTM" != "unknown" ]; then
echo "<mtm>$MTM</mtm>"
fi
if [ "$SERIAL" != "unknown" ]; then
echo "<serial>$SERIAL</serial>"
fi
echo "</xcatrequest>" )| udpcat.awk $XCATMASTER $XCATPORT
usleep 30000000
done
#Discovery complete, restart requested.
exec /bin/restart
fi
if [ $DESTINY == "reboot" ]; then
while ! nextdestiny.awk ; do
echo "Retrying next destiny..."
done
reboot -f
fi
if [ $DEST == "runcmd" ]; then
while ! nextdestiny.awk ; do
echo "Retrying next destiny..."
done
$TARG
fi
if [ $DESTINY == "install" -o $DESTINY == "netboot" ]; then
IMGSERVER=`grep imgserver /tmp/destiny | awk -F'>' '{print $2}'|awk -F'<' '{print $1}'`
INITRD=`grep initrd /tmp/destiny | awk -F'>' '{print $2}'|awk -F'<' '{print $1}'`
KERNEL=`grep kernel /tmp/destiny | awk -F'>' '{print $2}'|awk -F'<' '{print $1}'`
KCMD=`grep kcmdline /tmp/destiny | awk -F'>' '{print $2}'|awk -F'<' '{print $1}'`
wget http://$IMGSERVER/tftpboot/$KERNEL -O /tmp/kernel
wget http://$IMGSERVER/tftpboot/$INITRD -O /tmp/initrd
#START getting ready for kexec
for mod in `lsmod|awk '{print $1}'|grep -v Module`; do
rmmod $mod
done
kexec -f --append="$KCMD" --initrd=/tmp/initrd /tmp/kernel
reboot -f #If script is here, kexec failed, reboot in case it wasn't a linux kernel and let the boot loader handle it instead
fi
if [ $DEST == "runimage" ]; then
mkdir /tmp/$TARG
cd /tmp/$TARG
wget $TARG
while ! nextdestiny.awk ; do
echo "Retrying next destiny..."
done
tar zxvf $TARG
/tmp/$TARG/runme.sh
cd -
fi
done

View File

@ -0,0 +1,22 @@
#!/usr/bin/awk -f
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
BEGIN {
ns = "/inet/tcp/0/127.0.0.1/301"
print "<xcatrequest>" |& ns
print "<command>getdestiny</command>" |& ns
print "</xcatrequest>" |& ns
while (1) {
if ((ns |& getline) > 0) {
print $0 > "/tmp/destiny"
if ($0 == "</xcatresponse>")
break
} else { #Timeout
close(ns)
exit 1
}
}
close(ns)
exit 0
}

View File

@ -0,0 +1,22 @@
#!/usr/bin/awk -f
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
BEGIN {
ns = "/inet/tcp/0/127.0.0.1/301"
print "<xcatrequest>" |& ns
print "<command>getbmcconfig</command>" |& ns
print "</xcatrequest>" |& ns
while (1) {
if ((ns |& getline) > 0) {
print $0 > "/tmp/ipmi.data"
if ($0 == "</xcatresponse>")
break
} else {
close(ns)
exit 1
}
}
close(ns)
exit 0
}

View File

@ -0,0 +1,20 @@
#!/usr/bin/awk -f
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
BEGIN {
port = 3001
listener = "/inet/tcp/" port "/0/0"
quit = "no"
while (match(quit,"no")) {
print quit;
while (match(quit,"no") && (listener |& getline) > 0) {
if (match($0,"restart")) {
print "restarting bootstrap process" |& listener
quit="yes"
system("touch /restart")
system("killall usleep")
close(listener)
}
}
close(listener)
}
}

View File

@ -0,0 +1,22 @@
#!/usr/bin/awk -f
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
BEGIN {
ns = "/inet/tcp/0/127.0.0.1/301"
print "<xcatrequest>" |& ns
print "<command>nextdestiny</command>" |& ns
print "</xcatrequest>" |& ns
while (1) {
if ((ns |& getline) > 0) {
print $0 > "/tmp/destiny"
if ($0 == "</xcatresponse>")
break
} else {
close(ns)
exit 1
}
}
close(ns)
exit 0
}

View File

@ -0,0 +1,6 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#Redhcp, do the xcat part again
rm /restart
killall -12 udhcpc;killall -10 udhcpc
sleep 5
/etc/init.d/S99xcat

View File

@ -0,0 +1,12 @@
#!/usr/bin/awk -f
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
BEGIN {
xcatdport = ARGV[2]
xcatdhost = ARGV[1]
delete ARGV[1]
delete ARGV[2]
RS=""
}
END {
print $0 |& "/inet/udp/301/"xcatdhost"/"xcatdport
}

View File

@ -0,0 +1,66 @@
#!/bin/sh
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
nic=0
hba=0
MOD=""
#Load common usb drivers
modprobe ohci-hcd
modprobe uhci-hcd
modprobe ehci-hcd
for i in $(lspci -n | awk '{print $1 "%" $3}')
do
PCI=$(echo $i | awk -F% '{print $1}')
VID="0x0000$(echo $i | awk -F% '{print $2}' |awk -F: '{print $1}')"
DID="0x0000$(echo $i | awk -F% '{print $2}' |awk -F: '{print $2}')"
if egrep "^[^ ]*[ ]*$VID[ ]*$DID" /lib/modules/*/modules.pcimap >/dev/null
then
TYPE=$(
lspci | \
grep "^$PCI " | \
awk '{print $2}' | \
tr '[A-Z]' '[a-z]'
)
DESC=$(
lspci | \
grep "^$PCI " | \
awk -F: '{print $3}' | \
sed 's/^ *//'
)
MOD=$(
egrep "^[^ ]*[ ]*$VID[ ]*$DID" /lib/modules/*/modules.pcimap | \
head -1 | \
awk '{print $1}' | \
tr -d '"'
)
case "$TYPE" in
ethernet|network)
echo "Found ($MOD) $DESC"
GOTNIC=1
if [ "$MOD" = "gm" ]
then
echo "alias myri0 $MOD"
echo "alias myri0 $MOD" >>/etc/modules.conf
echo "alias myri0 $MOD" >>/etc/modprobe.conf
else
modprobe $MOD
udhcpc -i eth$nic -b
nic=$(($nic + 1))
fi
;;
scsi|raid)
echo "Found ($MOD) $DESC"
GOTHBA=1
modprobe $MOD
modprobe sd_mod
modprobe scsi_mod
hba=$(($hba + 1))
;;
*)
continue
;;
esac
fi
done

View File

@ -0,0 +1,19 @@
#!/bin/sh
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#Stunnel init for xcat:
XCATDEST=""
for parm in `cat /proc/cmdline`; do
key=`echo $parm|awk -F= '{print $1}'`
if [ "$key" == "xcatd" ]; then
XCATDEST=`echo $parm|awk -F= '{print $2}'`
fi
done
mkdir -p /etc/stunnel
echo 'client=yes' > /etc/stunnel/stunnel.conf
echo 'foreground=yes' >> /etc/stunnel/stunnel.conf
echo 'verify=0' >> /etc/stunnel/stunnel.conf
echo '[xcatds]' >> /etc/stunnel/stunnel.conf
echo 'accept=301' >> /etc/stunnel/stunnel.conf
echo 'connect='$XCATDEST >> /etc/stunnel/stunnel.conf
mkdir -p /usr/var/run/stunnel
stunnel &

View File

@ -0,0 +1,2 @@
#!/bin/sh
exit

View File

@ -0,0 +1,9 @@
#!/bin/sh
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
(
while ! /bin/getdestiny.awk
do
echo "Retrying destiny retrieval"
done
/bin/dodestiny
) &

View File

@ -0,0 +1,54 @@
# /etc/inittab
#
# Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
#
# Note: BusyBox init doesn't support runlevels. The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use
# sysvinit.
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console
# runlevels == ignored
# action == one of sysinit, respawn, askfirst, wait, and once
# process == program to run
# Startup the system
::sysinit:/bin/mount -t proc none /proc
::sysinit:/bin/mount -t sysfs none /sys
::sysinit:/bin/mount -t tmpfs -o size=64k,mode=0755 none /dev
::sysinit:/bin/mkdir /dev/pts
::sysinit:/bin/mount -t devpts devpts /dev/pts
::sysinit:/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
::sysinit:/sbin/mdev -s
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mount -a
::sysinit:/bin/hostname -F /etc/hostname
::sysinit:/sbin/ifconfig lo 127.0.0.1 up
::sysinit:/sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Set up a couple of getty's
#console::respawn:/sbin/getty 19200 console
tty1::respawn:/sbin/getty 38400 tty1
tty2::respawn:/sbin/getty 38400 tty2
# Put a getty on the serial port
#ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100
# Logging junk
null::sysinit:/bin/touch /var/log/messages
#null::respawn:/sbin/syslogd -n
#null::respawn:/sbin/klogd -n
#tty3::respawn:/usr/bin/tail -f /var/log/messages
# Stuff to do for the 3-finger salute
::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
null::shutdown:/usr/bin/killall klogd
null::shutdown:/usr/bin/killall syslogd
null::shutdown:/bin/umount -a -r
null::shutdown:/sbin/swapoff -a

View File

View File

@ -0,0 +1,26 @@
#!/bin/sh
case $1 in
deconfig)
/sbin/ifconfig $interface up
/sbin/ifconfig $interface 0.0.0.0
;;
bound|renew)
/sbin/ifconfig $interface $ip netmask $subnet
if [ -n "$router" ] ; then
echo "deleting routers"
while route del default gw 0.0.0.0 dev $interface ; do
:
done
for i in $router ; do
route add default gw $i dev $interface
done
fi
echo -n > /etc/resolv.conf
[ -n "$domain" ] && echo search $domain >> /etc/resolv.conf
for i in $dns ; do
echo adding dns $i
echo nameserver $i >> /etc/resolv.conf
done
;;
esac

View File

@ -0,0 +1,56 @@
%define epoch 0
%define version 2.0
%ifarch i386 i586 i686
%define tarch x86
%endif
%ifarch x86_64
%define tarch x86_64
%endif
%ifarch ppc ppc64
%define tarch ppc64
%endif
BuildArch: noarch
%define name xCAT-nbroot-core-%{tarch}
Release: snap%(date +"%Y%m%d%H%M")
AutoReq: false
AutoProv: false
Name: %{name}
#Epoch: %{epoch}
Version: %{version}
Group: System/Utilities
License: EPL
Vendor: IBM Corp.
Summary: xCAT-nbroot-coreprovides opensource components of the netboot image
URL: http://xcat.org
Source1: xcat-nbrootoverlay.tar.gz
Buildroot: %{_localstatedir}/tmp/xCAT-nbroot-core
Packager: IBM Corp.
%Description
xcat-nbroot-core provides the xCAT scripts for the mini-root environment
All files included are as they were downloadable on 4/7/2007
%Prep
%Build
%Install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/share/xcat/netboot/%{tarch}/nbroot
cd $RPM_BUILD_ROOT/usr/share/xcat/netboot/%{tarch}/nbroot
tar zxvf %{SOURCE1}
cd -
%Files
%defattr(-,root,root)
%doc LICENSE.html
/

View File

@ -0,0 +1,326 @@
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=ProgId content=Word.Document>
<meta name=Generator content="Microsoft Word 9">
<meta name=Originator content="Microsoft Word 9">
<title>Eclipse Public License - Version 1.0</title>
<!--[if gte mso 9]><xml>
<o:DocumentProperties>
<o:Revision>2</o:Revision>
<o:TotalTime>3</o:TotalTime>
<o:Created>2004-03-05T23:03:00Z</o:Created>
<o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
<o:Pages>4</o:Pages>
<o:Words>1626</o:Words>
<o:Characters>9270</o:Characters>
<o:Lines>77</o:Lines>
<o:Paragraphs>18</o:Paragraphs>
<o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
<o:Version>9.4402</o:Version>
</o:DocumentProperties>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:WordDocument>
<w:TrackRevisions/>
</w:WordDocument>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:553679495 -2147483648 8 0 66047 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p
{margin-right:0in;
mso-margin-top-alt:auto;
mso-margin-bottom-alt:auto;
margin-left:0in;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";}
p.BalloonText, li.BalloonText, div.BalloonText
{mso-style-name:"Balloon Text";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:8.0pt;
font-family:Tahoma;
mso-fareast-font-family:"Times New Roman";}
@page Section1
{size:8.5in 11.0in;
margin:1.0in 1.25in 1.0in 1.25in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
</head>
<body lang=EN-US style='tab-interval:.5in'>
<div class=Section1>
<p align=center style='text-align:center'><b>Eclipse Public License - v 1.0</b>
</p>
<p><span style='font-size:10.0pt'>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE,
REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
OF THIS AGREEMENT.</span> </p>
<p><b><span style='font-size:10.0pt'>1. DEFINITIONS</span></b> </p>
<p><span style='font-size:10.0pt'>&quot;Contribution&quot; means:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
in the case of the initial Contributor, the initial code and documentation
distributed under this Agreement, and<br clear=left>
b) in the case of each subsequent Contributor:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
changes to the Program, and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
additions to the Program;</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>where
such changes and/or additions to the Program originate from and are distributed
by that particular Contributor. A Contribution 'originates' from a Contributor
if it was added to the Program by such Contributor itself or anyone acting on
such Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in conjunction
with the Program under their own license agreement, and (ii) are not derivative
works of the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Contributor&quot; means any person or
entity that distributes the Program.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Licensed Patents &quot; mean patent
claims licensable by a Contributor which are necessarily infringed by the use
or sale of its Contribution alone or when combined with the Program. </span></p>
<p><span style='font-size:10.0pt'>&quot;Program&quot; means the Contributions
distributed in accordance with this Agreement.</span> </p>
<p><span style='font-size:10.0pt'>&quot;Recipient&quot; means anyone who
receives the Program under this Agreement, including all Contributors.</span> </p>
<p><b><span style='font-size:10.0pt'>2. GRANT OF RIGHTS</span></b> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
Subject to the terms of this Agreement, each Contributor hereby grants Recipient
a non-exclusive, worldwide, royalty-free copyright license to<span
style='color:red'> </span>reproduce, prepare derivative works of, publicly
display, publicly perform, distribute and sublicense the Contribution of such
Contributor, if any, and such derivative works, in source code and object code
form.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide,<span style='color:green'> </span>royalty-free
patent license under Licensed Patents to make, use, sell, offer to sell, import
and otherwise transfer the Contribution of such Contributor, if any, in source
code and object code form. This patent license shall apply to the combination
of the Contribution and the Program if, at the time the Contribution is added
by the Contributor, such addition of the Contribution causes such combination
to be covered by the Licensed Patents. The patent license shall not apply to
any other combinations which include the Contribution. No hardware per se is
licensed hereunder. </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>c)
Recipient understands that although each Contributor grants the licenses to its
Contributions set forth herein, no assurances are provided by any Contributor
that the Program does not infringe the patent or other intellectual property
rights of any other entity. Each Contributor disclaims any liability to Recipient
for claims brought by any other entity based on infringement of intellectual
property rights or otherwise. As a condition to exercising the rights and
licenses granted hereunder, each Recipient hereby assumes sole responsibility
to secure any other intellectual property rights needed, if any. For example,
if a third party patent license is required to allow Recipient to distribute
the Program, it is Recipient's responsibility to acquire that license before
distributing the Program.</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>d)
Each Contributor represents that to its knowledge it has sufficient copyright
rights in its Contribution, if any, to grant the copyright license set forth in
this Agreement. </span></p>
<p><b><span style='font-size:10.0pt'>3. REQUIREMENTS</span></b> </p>
<p><span style='font-size:10.0pt'>A Contributor may choose to distribute the
Program in object code form under its own license agreement, provided that:</span>
</p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it complies with the terms and conditions of this Agreement; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
its license agreement:</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
effectively disclaims on behalf of all Contributors all warranties and
conditions, express and implied, including warranties or conditions of title
and non-infringement, and implied warranties or conditions of merchantability
and fitness for a particular purpose; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
effectively excludes on behalf of all Contributors all liability for damages,
including direct, indirect, special, incidental and consequential damages, such
as lost profits; </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iii)
states that any provisions which differ from this Agreement are offered by that
Contributor alone and not by any other party; and</span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iv)
states that source code for the Program is available from such Contributor, and
informs licensees how to obtain it in a reasonable manner on or through a
medium customarily used for software exchange.<span style='color:blue'> </span></span></p>
<p><span style='font-size:10.0pt'>When the Program is made available in source
code form:</span> </p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
it must be made available under this Agreement; and </span></p>
<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b) a
copy of this Agreement must be included with each copy of the Program. </span></p>
<p><span style='font-size:10.0pt'>Contributors may not remove or alter any
copyright notices contained within the Program. </span></p>
<p><span style='font-size:10.0pt'>Each Contributor must identify itself as the
originator of its Contribution, if any, in a manner that reasonably allows
subsequent Recipients to identify the originator of the Contribution. </span></p>
<p><b><span style='font-size:10.0pt'>4. COMMERCIAL DISTRIBUTION</span></b> </p>
<p><span style='font-size:10.0pt'>Commercial distributors of software may
accept certain responsibilities with respect to end users, business partners
and the like. While this license is intended to facilitate the commercial use
of the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create potential
liability for other Contributors. Therefore, if a Contributor includes the
Program in a commercial product offering, such Contributor (&quot;Commercial
Contributor&quot;) hereby agrees to defend and indemnify every other
Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and
costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other
legal actions brought by a third party against the Indemnified Contributor to
the extent caused by the acts or omissions of such Commercial Contributor in
connection with its distribution of the Program in a commercial product
offering. The obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In order
to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
Contributor in writing of such claim, and b) allow the Commercial Contributor
to control, and cooperate with the Commercial Contributor in, the defense and
any related settlement negotiations. The Indemnified Contributor may participate
in any such claim at its own expense.</span> </p>
<p><span style='font-size:10.0pt'>For example, a Contributor might include the
Program in a commercial product offering, Product X. That Contributor is then a
Commercial Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance claims and
warranties are such Commercial Contributor's responsibility alone. Under this
section, the Commercial Contributor would have to defend claims against the
other Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.</span> </p>
<p><b><span style='font-size:10.0pt'>5. NO WARRANTY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
responsible for determining the appropriateness of using and distributing the
Program and assumes all risks associated with its exercise of rights under this
Agreement , including but not limited to the risks and costs of program errors,
compliance with applicable laws, damage to or loss of data, programs or
equipment, and unavailability or interruption of operations. </span></p>
<p><b><span style='font-size:10.0pt'>6. DISCLAIMER OF LIABILITY</span></b> </p>
<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
<p><b><span style='font-size:10.0pt'>7. GENERAL</span></b> </p>
<p><span style='font-size:10.0pt'>If any provision of this Agreement is invalid
or unenforceable under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this Agreement, and without
further action by the parties hereto, such provision shall be reformed to the
minimum extent necessary to make such provision valid and enforceable.</span> </p>
<p><span style='font-size:10.0pt'>If Recipient institutes patent litigation
against any entity (including a cross-claim or counterclaim in a lawsuit)
alleging that the Program itself (excluding combinations of the Program with
other software or hardware) infringes such Recipient's patent(s), then such
Recipient's rights granted under Section 2(b) shall terminate as of the date
such litigation is filed. </span></p>
<p><span style='font-size:10.0pt'>All Recipient's rights under this Agreement
shall terminate if it fails to comply with any of the material terms or
conditions of this Agreement and does not cure such failure in a reasonable
period of time after becoming aware of such noncompliance. If all Recipient's
rights under this Agreement terminate, Recipient agrees to cease use and
distribution of the Program as soon as reasonably practicable. However,
Recipient's obligations under this Agreement and any licenses granted by
Recipient relating to the Program shall continue and survive. </span></p>
<p><span style='font-size:10.0pt'>Everyone is permitted to copy and distribute
copies of this Agreement, but in order to avoid inconsistency the Agreement is
copyrighted and may only be modified in the following manner. The Agreement
Steward reserves the right to publish new versions (including revisions) of
this Agreement from time to time. No one other than the Agreement Steward has
the right to modify this Agreement. The Eclipse Foundation is the initial
Agreement Steward. The Eclipse Foundation may assign the responsibility to
serve as the Agreement Steward to a suitable separate entity. Each new version
of the Agreement will be given a distinguishing version number. The Program
(including Contributions) may always be distributed subject to the version of
the Agreement under which it was received. In addition, after a new version of
the Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly stated
in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
the intellectual property of any Contributor under this Agreement, whether
expressly, by implication, estoppel or otherwise. All rights in the Program not
expressly granted under this Agreement are reserved.</span> </p>
<p><span style='font-size:10.0pt'>This Agreement is governed by the laws of the
State of New York and the intellectual property laws of the United States of
America. No party to this Agreement will bring a legal action under this
Agreement more than one year after the cause of action arose. Each party waives
its rights to a jury trial in any resulting litigation.</span> </p>
<p class=MsoNormal><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>
</div>
</body>
</html>

8
xCAT-server-2.0/README Normal file
View File

@ -0,0 +1,8 @@
This is the README for xCAT - Extreme Cluster Administration Toolkit,
Version 2.0 alpha release. xCAT is a toolkit for the deployment and administration of clusters.
xCAT 2.0 is offered OSS under a EPL license.
See http://www.eclipse.org/legal/epl-v10.html for license details.
The xCAT 2.0 code and documentation can be downloaded from http://xcat.org.
For support, go to http://xcat.org for instructions on joining the mailing list.

View File

@ -0,0 +1,98 @@
#!/bin/bash
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
# chkconfig: 345 85 60
# description: xCAT management service
# processname: xcatd
### BEGIN INIT INFO
# Provides: xcatd
# Default-Start: 3 4 5
# Default-stop: 0 1 2 6
# Short-Description: xCATd
# Description: xCAT management service
### END INIT INFO
MStatus()
{
ps ax|grep -v grep|grep xcatd: >& /dev/null
if [ "$?" = "0" ]; then
RVAL=0
echo "xCAT service is running"
else
RVAL=3
echo "xCAT service is not running"
fi
return $RVAL
}
if [ -f /lib/lsb/init-functions ]; then
. /lib/lsb/init-functions
START_DAEMON=start_daemon
STATUS=MStatus
LOG_SUCCESS=log_success_msg
LOG_FAILURE=log_failure_msg
LOG_WARNING=log_warning_message
elif [ -f /etc/init.d/functions ]; then
echo RH
. /etc/init.d/functions
START_DAEMON=daemon
STATUS=status
LOG_SUCCESS=success
LOG_FAILURE=failure
LOG_WARNING=passed
else
echo "Error, don't know how to start on this platform"
exit 1
fi
case $1 in
restart)
$0 stop
$0 start
;;
status)
$STATUS
;;
stop)
echo -n "Stopping xCATd "
$STATUS >& /dev/null
if [ "$?" != "0" ]; then
echo -n "xCATd not running, not stopping "
$LOG_WARNING
exit 1
fi
kill -TERM -`cat /var/run/xcatd.pid`
let i=0;
while $STATUS >& /dev/null && [ $i -lt 15 ]; do
usleep 100000
let i=i+1
done
$STATUS >& /dev/null
if [ "$?" == "0" ]; then
kill -KILL -`cat /var/run/xcatd.pid`
fi
usleep 100000
$STATUS >& /dev/null
if [ "$?" == "0" ]; then
$LOG_FAILURE
exit 1
fi
$LOG_SUCCESS
rm /var/run/xcatd.pid
;;
start)
$STATUS >& /dev/null
if [ "$?" == "0" ]; then
echo -n "xCATd already running "
$LOG_WARNING
exit
fi
echo -n "Starting xCATd "
xcatd -p /var/run/xcatd.pid && $LOG_SUCCESS || $LOG_FAILURE
;;
esac

View File

@ -0,0 +1,202 @@
# Post Install Scripts
#
# The Post Install Scripts table is a rules-based system for determining
# which install scripts and in what order to execute them.
#
# Rules and actions are formatted:
#
# RULE {
# script [args]
# script [args]
# script [args]
# ...
# }
#
# Rules are defined as VAR=REGEX. Where VAR may be any exported
# environmental variable, ALL, or NODERANGE (special, see below).
#
# Regular expressions (REGEX or regex) are a powerful way to define a match.
# The perl regex engine is used to parse the rules. Please do not confuse
# regex with shell expansion characters.
#
# e.g. compute* does NOT match anything starting with 'compute' as bash
# would. compute.* is the correct regex for a that match. man perlre for
# regex docs. (BTW, regex compute* matches 'comput' with 0 or more 'e's at
# the end.)
#
# There is no need to place beginning and end markers (^$) in your regex.
# They are added automatically.
#
# Actions are defined as: script [optional args]
#
# A special action/script "STOP" will stop processing all rules and exit.
#
# Scripts are run top-down multiples rules can match.
#
# Nesting with () and operators and, or, and not are supported.
#
# The following VARs are exported by xCAT:
#
# OSVER=(rh62|rh70|rh71|rh72|rh73|rh80|suse81|sles8)
# OSVER is the OS that has just been installed. OSVER may be defined by
# regex. (e.g. rh.* is "anything starting with rh")
#
# ARCH=(x86|ia64)
# ARCH is the hardware architecture (uname -m). ARCH may be defined by
# regex.
#
# NODERANGE=(e.g. node1-node10)
# NODERANGE follows the xCAT noderange format as defined by noderange.5
# (man noderange). Regex is supported as part of noderange, however it
# must be prefixed with a '@', e.g. (@node.* is "anything starting with
# node").
#
# ALL (Apply to all)
#
# TABLE:TABLENAME:KEY:FIELD=
#
# The last rule is special and is determined at runtime.
#
# TABLENAME is the name of an xCAT table located in $XCATROOT/etc. You
# may create your own tables.
#
# KEY is the first field of any xCAT table. $NODE is a
# special value for key, usually the key is a fixed name, however many xCAT
# tables start with a node or resource group name.
#
# FIELD is a numeric value for fields associated with KEY. The first field
# is 1. Special names are available (e.g. $nodehm_eth0) and are defined in
# $XCATROOT/lib/functions. Any environmental variable can be used.
#
# e.g.:
#
# TABLE:nodehm.tab:$NODENAME:$nodehm_eth0=e1000
#
# Would only execute scripts where eth0 was defined as e1000 in nodehm.tab
# for any node.
#
# The script $XCATROOT/bin/postage is the master post installation script
# that parses this table and runs the scripts. You can use the script
# $XCATROOT/bin/postrules NODENAME ARCH OSVER to parse this table to test
# your rules.
#
# e.g. postrules node1 x86 rh73
#
# Setup syslog
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
syslog
}
# update/add packages
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
updaterpms nodeps
otherrpms
forcerpms
}
# setup NFS mounts
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
nfsmounts
}
# sync clock
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
syncclock
setupntp
}
# Setup PAM
TABLE:noderes:$NODE:access=Y and
(OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.*) {
setuppam
}
# Setup PBS
TABLE:noderes:$NODE:pbs=Y and
(OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.*) {
openpbs
}
# Setup paths
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
setuppaths
}
# Setup services
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
setupservices
}
# Setup rsh/ssh.
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
remoteshell
}
# Enable sysctl
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
enablesysreq
}
# Enable debug
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
enabledebug
}
# Setup Myrinet MX
TABLE:noderes:$NODE:install_roll=Y {
setupstage
}
# Re setup syslog, RPM updates may have hosed it.
OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
resyslog
}
ALL {
serialconsole
}
#
# Start custom section
#
# Here is a good place to put custom code
#
#
# End custom section
#
# Sync dirs
OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
syncdirs
}
# Unmount /post.
ALL {
umountpost
}
# Update remote boot flag. rsh/ssh must be setup first
# unless xcatd is used. To use rsh or ssh, pass as
# option to updateflag else pass xcatd
#
#2nd arg can be Master IP for multiple master IP support.
#
ALL {
updateflag.awk $MASTER
}
# hardcode networking
#OSVER=sl[34].* or OSVER=centos.* or OSVER=rh.* or OSVER=sles.* or OSVER=suse.* {
# hardnis
# hardmodopts options e1000 RxIntDelay=0,0 TxIntDelay=0,0 RxAbsIntDelay=0,0 TxAbsIntDelay=0,0 InterruptThrottleRate=0,0
#}
# SuSE needs an extra reboot.
OSVER=sles.* or OSVER=suse.* {
reboot
}

View File

@ -0,0 +1,458 @@
#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package XCAT;
use base DSHContext;
use Socket;
use xCAT::Utils;
use xCAT::MsgUtils;
# Define remote shell globals from xCAT
our $XCAT_RSH_CMD;
our $XCAT_RCP_CMD;
#
# get the remote command settings
#
XCAT->get_xcat_remote_cmds;
# Global Data structures for xCAT context
our @xcat_node_list = ();
our %xcat_nodegroup_table = ();
#-------------------------------------------------------------------------------
=head3
context_defaults
Assign default properties for the xCAT context. A default
property for a context will be used if the property is
not user configured in any other way.
Arguments:
None
Returns:
A reference to a hash table with the configured
default properties for the xCAT context
Globals:
$XCAT_RSH_CMD
Error:
None
Example:
$default_properties = XCAT->config_defaults;
Comments:
$defaults hash table contents:
$defaults{'NodeRemoteShell'} - default remote shell to use for node targets
=cut
#-------------------------------------------------------------------------------
sub context_defaults
{
my %defaults = ();
$defaults{'NodeRemoteShell'} = $XCAT_RSH_CMD;
return \%defaults;
}
#-------------------------------------------------------------------------------
=head3
context_properties
Configure the user specified context properties for the xCAT context.
These properties are configured by the user through environment
variables or external configuration files.
Arguments:
None
Returns:
A reference to a hash table of user-configured properties for
the xCAT context.
Globals:
None
Error:
None
Example:
$properties = XCAT->config_properties
Comments:
=cut
#-------------------------------------------------------------------------------
sub context_properties
{
my %properties = ();
$properties{'RemoteShell'} = $XCAT_RSH_CMD;
$properties{'RemoteCopyCmd'} = $XCAT_RCP_CMD;
return \%properties;
}
#-------------------------------------------------------------------------------
=head3
all_devices
Comments: devices are nodes in the XCAT context. Use node flags
and not device flags.
=cut
#-------------------------------------------------------------------------------
sub all_devices
{
my ($class, $resolved_targets) = @_;
xCAT::MsgUtils->message(
"E",
" Nodes and Devices are considered nodes in xCAT.\n The -A flag is not supported. Use the all group in XCAT to dsh to all node/devices.\n"
);
return;
}
#-------------------------------------------------------------------------------
=head3
all_nodes
Returns an array of all node names in the xCAT context
Note in xCAT everything is a node including devices
Arguments:
None
Returns:
An array of node/device names
Globals:
@xcat_node_list
Error:
None
Example:
@nodes = XCAT->get_xcat_node_list;
Comments:
=cut
#-------------------------------------------------------------------------------
sub all_nodes
{
scalar(@xcat_node_list) || XCAT->get_xcat_node_list;
return @xcat_node_list;
}
#-------------------------------------------------------------------------------
=head3
all_nodegroups
Returns an array of all node group names in the xCAT context
Note in xCAT everything is a node including devices
Arguments:
None
Returns:
An array of node/device group names
Globals:
%xcat_nodegroup_table
Error:
None
Example:
@nodegroups = XCAT->all_nodegroups;
Comments:
=cut
#-------------------------------------------------------------------------------
sub all_nodegroups
{
scalar(%xcat_nodegroup_table) || XCAT->get_xcat_nodegroup_table;
return keys(%xcat_nodegroup_table);
}
#-------------------------------------------------------------------------------
=head3
nodegroup_members
Given a node/device group in the xCAT context, this routine expands the
membership of the group and returns a list of its members.
Arguments:
$nodegroup - node group name
Returns:
An array of node group members
Globals:
$nodegroup_path
Error:
None
Example:
$members = XCAT->nodegroup_members('MyGroup1');
Comments:
=cut
#-------------------------------------------------------------------------------
sub nodegroup_members
{
my ($class, $nodegroup) = @_;
my %node_list = ();
scalar(%xcat_nodegroup_table) || XCAT->get_xcat_nodegroup_table;
!defined($xcat_nodegroup_table{$nodegroup}) && return undef;
my @nodes = split /,/, $xcat_nodegroup_table{$nodegroup};
foreach my $node (@nodes)
{
$node_list{$node}++;
}
my @members = keys(%node_list);
return \@members;
}
#-------------------------------------------------------------------------------
=head3
resolve_node
Within the xCAT context, resolve the name of a given node and
augment the supplied property hash table with xCAT node information.
Arguments:
$target_properties - basic properties hash table reference for a node
Returns:
1 if resolution was successful
undef otherwise
Globals:
$XCAT_RSH_CMD
$XCAT_RCP_CMD
Error:
None
Example:
XCAT->resolve_node($target_properties);
Comments:
=cut
#-------------------------------------------------------------------------------
sub resolve_node
{
my ($class, $target_properties) = @_;
$$target_properties{'remote-shell'} = $XCAT_RSH_CMD;
$$target_properties{'remote-copy'} = $XCAT_RCP_CMD;
return 1;
}
#-------------------------------------------------------------------------------
=head3
get_xcat_remote_cmds
Using xCAT native commands, store the remote command settings for
the remote shell and remote copy commands as defined in xCAT
site.tab file.
Arguments:
None
Returns:
None
Globals:
$XCAT_RSH_CMD
$XCAT_RCP_CMD
Error:
None
Example:
XCAT->get_xcat_remote_cmds
Comments:
Internal routine only
=cut
#-------------------------------------------------------------------------------
sub get_xcat_remote_cmds
{
$XCAT_RSH_CMD = "/usr/bin/ssh"; # default
$XCAT_RCP_CMD = "/usr/bin/scp"; #default
my @remote_shell = xCAT::Utils->get_site_attribute("rsh");
if ($remote_shell[0])
{
$XCAT_RSH_CMD = $remote_shell[0];
}
my @remote_copy = xCAT::Utils->get_site_attribute("rcp");
if ($remote_copy[0])
{
$XCAT_RCP_CMD = $remote_copy[0];
}
}
#-------------------------------------------------------------------------------
=head3
get_xcat_node_list
Using xCAT native commands, this routine builds a cached list of
node/device names defined in the xCAT context
Arguments:
None
Returns:
None
Globals:
%xcat_node_list
Error:
None
Example:
XCAT->get_xcat_node_list
Comments:
Internal routine only
=cut
#-------------------------------------------------------------------------------
sub get_xcat_node_list
{
@xcat_node_list = xCAT::Utils->get_node_list;
chomp(@xcat_node_list);
}
#-------------------------------------------------------------------------------
=head3
get_xcat_nodegroup_table
Using xCAT native commands, this routine builds a cached list of
node groups and their members defined in the xCAT context
Arguments:
None
Returns:
None
Globals:
%xcat_nodegroup_table
Error:
None
Example:
XCAT->get_xcat_nodegroup_table
Comments:
Internal routine only
=cut
#-------------------------------------------------------------------------------
sub get_xcat_nodegroup_table
{
$node_list = "";
my @nodegroups = xCAT::Utils->list_all_node_groups;
for my $group (@nodegroups)
{
chomp($group);
my @nodes = `nodels $group`;
while (@nodes)
{
my $nodename = shift @nodes;
chomp($nodename);
$node_list .= $nodename;
$node_list .= ",";
}
chop($node_list);
$xcat_nodegroup_table{$group} = $node_list;
$node_list = "";
}
}
sub query_node
{
my ($class, $node, $flag) = @_;
my @xcat_nodes = all_nodes();
$~ = "NODES";
if ($flag)
{
if (grep(/^$node$/, @xcat_nodes))
{
print("$node : Valid\n");
}
else
{
print("$node : Invalid\n");
}
}
else
{
print("$node : Invalid\n");
}
}
sub query_group
{
my ($class, $group) = @_;
my @xcat_groups = all_nodegroups();
$~ = "GROUPS";
if (grep(/^$group$/, @xcat_groups))
{
print("$group : Valid\n");
}
else
{
print("$group : Invalid\n");
}
}
1; #end

View File

@ -0,0 +1,49 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_monitoring::mycode;
1;
# This subroutine get called when new nodes are added into the cluster
# or nodes are removed from the cluster.
#
sub processTableChanges {
my $action=shift;
if ($action =~ /xCAT_monitoring::mycode/){
$action=shift;
}
my $tablename=shift;
my $old_data=shift;
my $new_data=shift;
my @nodenames=();
if ($action eq "a") { #nodes added in the cluster
if ($new_data) {
push(@nodenames, $new_data->{node});
$noderange=join(',', @nodenames);
open(FILE, ">>/var/log/mycode.log") or dir ("cannot open the file\n");
print (FILE "new nodes in the cluster are: $noderange\n");
close(FILE);
}
}
elsif ($action eq "d") { #nodes removed from the cluster
#find out the index of "node" column
if ($old_data->[0]) {
$colnames=$old_data->[0];
my $i;
for ($i=0; $i<@$colnames; ++$i) {
if ($colnames->[$i] eq "node") {last;}
}
for (my $j=1; $j<@$old_data; ++$j) {
push(@nodenames, $old_data->[$j]->[$i]);
}
if (@nodenames > 0) {
$noderange=join(',', @nodenames);
open(FILE, ">>/var/log/mycode.log") or dir ("cannot open the file\n");
print (FILE "nodes leaving the cluster are: $noderange\n");
close(FILE);
}
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,757 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::blade;
#use Net::SNMP qw(:snmp INTEGER);
use xCAT::Table;
use IO::Socket;
use SNMP;
use strict;
use XML::Simple;
use Data::Dumper;
use POSIX "WNOHANG";
use Storable qw(freeze thaw);
use IO::Select;
use IO::Handle;
sub handled_commands {
return {
findme => 'blade',
rpower => 'nodehm:power,mgt',
rvitals => 'nodehm:vitals,mgt',
rinv => 'nodehm:inv,mgt',
rbeacon => 'nodehm:beacon,mgt',
rbootseq => 'nodehm:bootseq,mgt',
reventlog => 'nodehm:eventlog,mgt',
};
}
my %usage = (
"rpower" => "Usage: rpower <noderange> [on|off|reset|stat|boot]",
"rbeacon" => "Usage: rbeacon <noderange> [on|off|stat]",
"rvitals" => "Usage: rvitals <noderange> [all|temp|voltage|fanspeed|power|leds]",
"reventlog" => "Usage: reventlog <noderange> [all|clear|<number of entries to retrieve>]",
"rinv" => "Usage: rinv <noderange> [all|model|serial|vpd|mprom|deviceid|uuid]",
"rbootseq" => "Usage: rbootseq <noderange> [hd0|hd1|hd2|hd3|net|iscsi|usbflash|floppy|none],...",
);
my %macmap; #Store responses from rinv for discovery
my $mmprimoid = '1.3.6.1.4.1.2.3.51.2.22.5.1.1.4';#mmPrimary
my $beaconoid = '1.3.6.1.4.1.2.3.51.2.2.8.2.1.1.11'; #ledBladeIdentity
my $powerstatoid = '1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.4';#bladePowerState
my $powerchangeoid = '1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7';#powerOnOffBlade
my $powerresetoid = '1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.8';#restartBlade
my $mpresetoid = '1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.9'; #restartBladeSMP
my $bladexistsoid = '1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.3'; #bladeExists
my $bladeserialoid = '1.3.6.1.4.1.2.3.51.2.2.21.4.1.1.6'; #bladeHardwareVpdSerialNumber
my $blademtmoid = '1.3.6.1.4.1.2.3.51.2.2.21.4.1.1.7'; #bladeHardwareVpdMachineType
my $bladempveroid = '1.3.6.1.4.1.2.3.51.2.2.21.5.3.1.7'; #bladeSysMgmtProcVpdRevision
my $bladempaveroid = '1.3.6.1.4.1.2.3.51.2.2.21.3.1.1.4';#mmMainApplVpdRevisonNumber
my $bladempabuildidoid = '1.3.6.1.4.1.2.3.51.2.2.21.3.1.1.3';#mmMainApplVpdBuildId
my $bladempadateoid = '1.3.6.1.4.1.2.3.51.2.2.21.3.1.1.6';#mmMainApplVpdBuildDate
my $bladempbuildidoid = '1.3.6.1.4.1.2.3.51.2.2.21.5.3.1.6'; #bladeSysMgmtProcVpdBuildId
my $bladebiosveroid = '1.3.6.1.4.1.2.3.51.2.2.21.5.1.1.7'; #bladeBiosVpdRevision
my $bladebiosbuildidoid = '1.3.6.1.4.1.2.3.51.2.2.21.5.1.1.6'; #bladeBiosVpdBuildId
my $bladebiosdateoid = '1.3.6.1.4.1.2.3.51.2.2.21.5.1.1.8'; #bladeBiosVpdDate
my $bladediagveroid = '1.3.6.1.4.1.2.3.51.2.2.21.5.2.1.7'; #bladeDiagsVpdRevision
my $bladediagbuildidoid = '1.3.6.1.4.1.2.3.51.2.2.21.5.2.1.6'; #bladeDiagsVpdBuildId
my $bladediagdateoid = '1.3.6.1.4.1.2.3.51.2.2.21.5.2.1.8';#bladeDiagsVpdDate
my $eventlogoid = '1.3.6.1.4.1.2.3.51.2.3.4.2.1.2';#readEventLogString
my $clearlogoid = '.1.3.6.1.4.1.2.3.51.2.3.4.3';#clearEventLog
my @macoids = (
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.2', #bladeMACAddress1Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.3', #bladeMACAddress2Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.4', #bladeMACAddress3Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.5', #bladeMACAddress4Vpd
);
my @dcmacoids = (
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.10', #bladeDaughterCard1MACAddress1Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.11', #bladeDaughterCard1MACAddress2Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.12', #bladeDaughterCard1MACAddress3Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.13', #bladeDaughterCard1MACAddress4Vpd
);
my @hsdcmacoids = (
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.100', #bladeHSDaughterCard1MACAddress1Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.101', #bladeHSDaughterCard1MACAddress2Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.102', #bladeHSDaughterCard1MACAddress3Vpd
'1.3.6.1.4.1.2.3.51.2.2.21.4.2.1.103', #bladeHSDaughterCard1MACAddress4Vpd
);
my @bootseqoids = (
'1.3.6.1.4.1.2.3.51.2.22.1.3.1.7', #bootSequence1
'1.3.6.1.4.1.2.3.51.2.22.1.3.1.8', #bootSequence2
'1.3.6.1.4.1.2.3.51.2.22.1.3.1.9', #bootSequence3
'1.3.6.1.4.1.2.3.51.2.22.1.3.1.10', #bootSequence4
);
my %bootdevices = (
0 => 'none',
1 => 'floppy',
2 => 'cdrom',
3 => 'hd0',
4 => 'hd1',
5 => 'hd2',
6 => 'hd3',
7 => 'net',
8 => 'iscsi',
9 => 'iscsicrit',
10 => 'hd4',
11 => 'usbflash'
);
my %bootnumbers = (
'none' => 0,
'f' => 1,
'floppy' => 1,
'c' => 2,
'cd' => 2,
'dvd' => 2,
'cdrom' => 2,
'dvdrom' => 2,
'h' => 3, #in absence of an index, presuming hd0 intended
'hd' => 3,
'hardisk' => 3,
'hd0' => 3,
'harddisk0' => 3,
'hd1' => 4,
'harddisk1' => 4,
'hd2' => 5,
'harddisk2' => 5,
'hd3' => 6,
'harddisk3' => 6,
'n' => 7,
'network' => 7,
'net' => 7,
'iscsi' => 8,
'iscsicrit' => 9,
'hd4' => 10,
'harddisk4' => 10,
'usbflash' => 11,
'flash' => 11,
'usb' => 11
);
my $session;
my $slot;
my $didchassis = 0;
my @eventlog_array = ();
my $activemm;
my %mpahash;
my $mpa;
my $allinchassis=0;
sub fillresps {
my $response = shift;
my $mac = $response->{node}->[0]->{data}->[0]->{contents}->[0];
my $node = $response->{node}->[0]->{name}->[0];
$macmap{$mac} = $node;
#$macmap{$response->{node}->[0]->{data}->{contents}->[0]}=$response->{node}->[0]->{name};
}
sub isallchassis {
my $bladesinchassis = 0;
if ($allinchassis) {
return 1;
}
foreach (1..14) {
my $tmp = $session->get([$bladexistsoid.".$_"]);
if ($tmp eq 1) { $bladesinchassis++ }
}
my $count = keys %{$mpahash{$mpa}->{nodes}};
if ($count >= $bladesinchassis) { $allinchassis++; return 1 }; #commands that affect entire are okayed, i.e eventlog clear
return 0;
}
sub resetmp {
my $data;
my $stat;
my $rc;
$data = $session->set($mpresetoid.".$slot", 1);
#if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
if ($data->{$mpresetoid.".$slot"} == 1) {
return (0, "mpreset");
} else {
return (1,"error");
}
}
sub walkelog {
my $session = shift;
my $oid = shift;
unless ($oid =~ /^\./) {
$oid = '.'.$oid;
}
my $retmap = undef;
my $current = 1;
my @bindlist;
my $varbind;
do {
foreach ($current..$current+31) { #Attempt to retrive 32 ents at a time, seems to be working...
push @bindlist,[$oid,$_];
}
$current+=32;
$varbind = new SNMP::VarList(
@bindlist
);
$session->get($varbind);
foreach(@$varbind) {
unless (${_}->[2]) {last;}
if( ${_}->[2] =~ /NOSUCHINSTANCE/) {last;}
$retmap->{$_->[1]}=$_->[2];
}
} while ($varbind->[31] and $varbind->[31]->[2] != 'NOSUCHINSTANCE' and ($current < 600));
return $retmap;
print "Count was $current\n";
#print Dumper($varbind->[60]->[2]);
print "\n\n";
return undef;
my $count=0;
while ($varbind->[0] =~ /^$oid\.?(.*)/) {
$count++;
if ($1) {
$retmap->{$1.".".$varbind->[1]}=$varbind->[2]; #If $1 is set, means key should
} else {
$retmap->{$varbind->[1]}=$varbind->[2]; #If $1 is set, means key should
}
$session->getnext($varbind);
}
return $retmap;
}
sub eventlog { #Tried various optimizations, but MM seems not to do bulk-request
#TODO: retrieval of non blade events, what should be syntax?
#TODO: try retrieving 5 at a time, then 1 at a time when that stops working
my $cmd=shift;
my $data;
my @output;
my $oid = $eventlogoid;
if ($cmd eq 'all') {
$cmd=65535; #no MM has this many logs possible, should be a good number
}
if ($cmd =~ /^(\d+)$/) {
my $requestednumber=$1;
unless (@eventlog_array) {
#my $varbind=new SNMP::Varbind([$oid,0]);
#while ($data=$session->getnext($varbind)) {
# print Dumper($data);
# if ($session->{ErrorStr}) { printf $session->{ErrorStr}."\n"; }
# foreach (keys %$data) {
# $oid=$_;
# }
# unless (oid_base_match($eventlogoid,$oid)) {
# last;
# }
my $logents = walkelog($session,$oid);
foreach (sort {$a <=> $b} (keys %$logents)) {
push @eventlog_array,$logents->{$_}."\n";
}
#push @eventlog_array,$data->{$oid}; #TODO: filter against slot number, check for $allchassis for non-blade
#}
}
my $numentries=0;
#my $allchassis = isallchassis;
foreach (@eventlog_array) {
m/Severity:(\S+)\s+Source:(\S+)\s+Name:\S*\s+Date:(\S+)\s+Time:(\S+)\s+Text:(.+)/;
my $sev=$1;
my $source=$2;
my $date=$3;
my $time=$4;
my $text=$5;
my $matchstring;
if ($slot > 0) {
$matchstring=sprintf("BLADE_%02d",$slot);
} else {
$matchstring="^(?!BLADE).*";
}
if ($source =~ m/$matchstring$/i) { #MM guys changed their minds on capitalization
$numentries++;
unshift @output,"$sev:$date $time $text"; #unshift to get it in a sane order
}
if ($numentries >= $requestednumber) {
last;
}
}
return (0,@output);
}
my $data;
if ($cmd eq "clear") {
unless (isallchassis) {
return (1,"Cannot clear eventlogs except for entire chassis");
}
if ($didchassis) { return 0, "eventlog cleared" }
my $varbind = new SNMP::Varbind([$clearlogoid,0,1,'INTEGER']);
$data = $session->set($varbind);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$didchassis=1;
if ($varbind->[2] eq 1) {
return 0, "eventlog cleared";
}
}
}
sub bootseq {
my @args=@_;
my $data;
my @order=();
if ($args[0] eq "list" or $args[0] eq "stat") {
foreach my $oid (@bootseqoids) {
$data=$session->get([$oid,$slot]);
if ($session->{ErrorStr}) { return (1, $session->{ErrorStr}); }
push @order,$bootdevices{$data};
}
return (0,join(',',@order));
} else {
foreach (@args) {
my @neworder=(split /,/,$_);
push @order,@neworder;
}
my $number=@order;
if ($number > 4) {
return (1,"Only four boot sequence entries allowed");
}
my $nonespecified=0;
foreach (@order) {
unless (defined($bootnumbers{$_})) { return (1,"Unsupported device $_"); }
unless ($bootnumbers{$_}) { $nonespecified = 1; }
if ($nonespecified and $bootnumbers{$_}) { return (1,"Error: cannot specify 'none' before a device"); }
}
unless ($bootnumbers{$order[0]}) {
return (1,"Error: cannot specify 'none' as first device");
}
foreach (3,2,1,0) {
my $param = $bootnumbers{$order[$_]};
unless ($param) {
$param = 0;
my $varbind = new SNMP::Varbind([$bootseqoids[$_],$slot,$param,'INTEGER']);
$data = $session->set($varbind);
#$session->set($bootseqoids[$_].".$slot",$param);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
}
}
foreach (0,1,2,3) {
my $param = $bootnumbers{$order[$_]};
if ($param) {
my $varbind = new SNMP::Varbind([$bootseqoids[$_],$slot,$param,'INTEGER']);
$data = $session->set($varbind);
#$session->set($bootseqoids[$_].".$slot",$param);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
}
}
return bootseq('list');
}
}
sub inv {
my @invitems;
my $data;
my @output;
foreach (@_) {
push @invitems,split( /,/,$_);
}
my $item;
while (my $item = shift @invitems) {
if ($item =~ /^all/) {
push @invitems,(qw(mtm serial mac firm));
next;
}
if ($item =~ /^firm/) {
push @invitems,(qw(bios diag mprom mparom));
next;
}
if ($item =~ /^bios/) {
my $biosver;
my $biosbuild;
my $biosdate;
$biosver=$session->get([$bladebiosveroid.".$slot"]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$biosbuild=$session->get([$bladebiosbuildidoid.".$slot"]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$biosdate=$session->get([$bladebiosdateoid.".$slot"]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
push @output,"BIOS: $biosver ($biosbuild $biosdate)";
}
if ($item =~ /^diag/) {
my $diagver;
my $diagdate;
my $diagbuild;
$data=$session->get([$bladediagveroid,$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$diagver = $data;
$data=$session->get([$bladediagbuildidoid,$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$diagbuild = $data;
$data=$session->get([$bladediagdateoid,$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$diagdate = $data;
push @output,"Diagnostics: $diagver ($diagbuild $diagdate)";
}
if ($item =~ /^[sm]prom/) {
my $spver;
my $spbuild;
$data=$session->get([$bladempveroid,$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$spver=$data;
$data=$session->get([$bladempbuildidoid,$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$spbuild=$data;
push @output,"BMC/Mgt processor: $spver ($spbuild)";
}
if ($item =~ /^mparom/) {
my $mpabuild;
my $mpaver;
my $mpadate;
$data=$session->get([$bladempaveroid,$activemm]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$mpaver=$data;
$data=$session->get([$bladempabuildidoid,$activemm]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$mpabuild=$data;
$data=$session->get([$bladempadateoid,$activemm]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
$mpadate=$data;
push @output,"Management Module firmware: $mpaver ($mpabuild $mpadate)";
}
if ($item =~ /^model/ or $item =~ /^mtm/) {
$data=$session->get([$blademtmoid,$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
push @output,"Machine Type/Model: ".$data;
}
if ($item =~ /^serial/) {
$data=$session->get([$bladeserialoid,$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
push @output,"Serial Number: ".$data;
}
if ($item =~ /^mac/) {
foreach (0..3) {
$data=$session->get([$macoids[$_],$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
if ($data =~ /:/) {
push @output,"MAC Address ".($_+1).": ".$data;
}
}
foreach (0..3) {
my $oid=$hsdcmacoids[$_].".$slot";
$data=$session->get([$hsdcmacoids[$_],$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
if ($data =~ /:/) {
push @output,"HS Daughter card MAC Address ".($_+1).": ".$data;
}
}
foreach (0..3) {
$data=$session->get([$dcmacoids[$_],$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
if ($data =~ /:/) {
push @output,"Daughter card 1 MAC Address ".($_+1).": ".$data;
}
}
}
}
return (0,@output);
}
sub power {
my $subcommand = shift;
my $data;
my $stat;
if ($subcommand eq "stat") {
$data = $session->get([$powerstatoid.".".$slot]);
if ($data == 1) {
$stat = "on";
} elsif ( $data == 0) {
$stat = "off";
} else {
$stat= "error";
}
} elsif ($subcommand eq "off") {
$data = $session->set(new SNMP::Varbind([".".$powerchangeoid,$slot,0,'INTEGER']));
unless ($data) { return (1,$session->{ErrorStr}); }
$stat = "off";
} elsif ($subcommand eq "on") {
$data = $session->set(new SNMP::Varbind([".".$powerchangeoid,$slot,1,'INTEGER']));
unless ($data) { return (1,$session->{ErrorStr}); }
$stat = ($data ? "on" : "off");
} elsif ($subcommand eq "reset") {
$data = $session->set(new SNMP::Varbind([".".$powerresetoid,$slot ,1,'INTEGER']));
unless ($data) { return (1,$session->{ErrorStr}); }
$stat = "reset";
}
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
if ($stat) { return (0,$stat); }
}
sub beacon {
my $subcommand = shift;
my $data;
if ($subcommand eq "stat") {
} elsif ($subcommand eq "on") {
$data = $session->set(new SNMP::Varbind([$beaconoid,$slot , 1,'INTEGER']));
} elsif ($subcommand eq "off") {
$data = $session->set(new SNMP::Varbind([$beaconoid,$slot , 0,'INTEGER']));
} elsif ($subcommand eq "blink") {
$data = $session->set(new SNMP::Varbind([$beaconoid,$slot , 2,'INTEGER']));
} else {
return (1,"$subcommand unsupported");
}
my $stat = $session->get([$beaconoid.".".$slot]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
if ($stat==0) {
return (0,"off");
} elsif ($stat==1) {
return (0,"on");
} elsif ($stat==2) {
return (0,"blink");
} elsif ($stat==3) {
return (0,"unsupported");
}
}
sub bladecmd {
$mpa = shift;
$slot = shift;
#my $user = shift;
#my $pass = shift;
my $command = shift;
my @args = @_;
my $error;
if ($slot > 0) {
my $tmp = $session->get([$bladexistsoid.".$slot"]);
if ($session->{ErrorStr}) { return (1,$session->{ErrorStr}); }
unless ($tmp eq 1) { return (1,"Target bay empty"); }
}
if ($command eq "rbeacon") {
return beacon(@args);
} elsif ($command eq "rpower") {
return power(@args);
} elsif ($command =~ /r[ms]preset/) {
return resetmp(@args);
} elsif ($command eq "rbootseq") {
return bootseq(@args);
} elsif ($command eq "rinv") {
return inv(@args);
} elsif ($command eq "reventlog") {
return eventlog(@args);
}
return (1,"$command not a supported command by blade method");
}
sub process_request {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my $noderange = $request->{node};
my $command = $request->{command}->[0];
my @exargs;
unless ($noderange or $command eq "findme") {
if ($usage{$command}) {
$callback->({data=>$usage{$command}});
$request = {};
}
return;
}
if (ref($request->{arg})) {
@exargs = @{$request->{arg}};
} else {
@exargs = ($request->{arg});
}
my $bladeuser = 'USERID';
my $bladepass = 'PASSW0RD';
my $blademaxp = 64;
my $sitetab = xCAT::Table->new('site');
my $mpatab = xCAT::Table->new('mpa');
my $mptab = xCAT::Table->new('mp');
my $tmp;
if ($sitetab) {
($tmp)=$sitetab->getAttribs({'key'=>'blademaxp'},'value');
if (defined($tmp)) { $blademaxp=$tmp->{value}; }
}
my $passtab = xCAT::Table->new('passwd');
if ($passtab) {
($tmp)=$passtab->getAttribs({'key'=>'blade'},'username','password');
if (defined($tmp)) {
$bladeuser = $tmp->{username};
$bladepass = $tmp->{password};
}
}
if ($request->{command}->[0] eq "findme") {
my $mptab = xCAT::Table->new("mp");
unless ($mptab) { return 2; }
my @bladents = $mptab->getAllNodeAttribs([qw(node)]);
my @blades;
foreach (@bladents) {
push @blades,$_->{node};
}
my %invreq;
$invreq{node} = \@blades;
$invreq{arg} = ['mac'];
$invreq{command} = ['rinv'];
my $mac;
my $ip = $request->{'!xcat_clientip'};
my $arptable = `/sbin/arp -n`;
my @arpents = split /\n/,$arptable;
foreach (@arpents) {
if (m/^($ip)\s+\S+\s+(\S+)\s/) {
$mac=$2;
last;
}
}
unless ($mac) { return };
unless ($macmap{$mac}) {
process_request(\%invreq,\&fillresps);
}
unless ($macmap{$mac}) {
return 1; #failure
}
my $mactab = xCAT::Table->new('mac',-create=>1);
$mactab->setNodeAttribs($macmap{$mac},{mac=>$mac});
$mactab->close();
my %request = (
command => ['makedhcp'],
node => [$macmap{$mac}]
);
$doreq->(\%request);
$request->{command}=['discovered'];
$request->{noderange} = [$macmap{$mac}];
$doreq->($request);
%{$request}=(); #Clear request. it is done
undef $mactab;
return 0;
}
my $children = 0;
$SIG{CHLD} = sub { while (waitpid(-1, WNOHANG) > 0) { $children--; } };
my $inputs = new IO::Select;;
foreach (@$noderange) {
my $node=$_;
my $user=$bladeuser;
my $pass=$bladepass;
my $nodeid;
my $mpa;
my $ent;
if (defined($mptab)) {
$ent=$mptab->getNodeAttribs($node,['mpa','id']);
if (defined($ent->{mpa})) { $mpa=$ent->{mpa}; }
if (defined($ent->{id})) { $nodeid = $ent->{id}; }
}
if (defined($mpatab)) {
($ent)=$mpatab->getAttribs({'mpa'=>$mpa},'username','password');
if (defined($ent->{password})) { $pass = $ent->{password}; }
if (defined($ent->{username})) { $user = $ent->{username}; }
}
$mpahash{$mpa}->{nodes}->{$node}=$nodeid;
$mpahash{$mpa}->{username} = $user;
$mpahash{$mpa}->{password} = $pass;
}
my $sub_fds = new IO::Select;
foreach $mpa (sort (keys %mpahash)) {
while ($children > $blademaxp) { sleep (0.1); }
$children++;
my $cfd;
my $pfd;
pipe $cfd, $pfd;
$cfd->autoflush(1);
$pfd->autoflush(1);
my $cpid = fork;
unless (defined($cpid)) { die "Fork error"; }
unless ($cpid) {
close($cfd);
dompa($pfd,$mpa,\%mpahash,$command,-args=>@exargs);
exit(0);
}
close ($pfd);
$sub_fds->add($cfd);
}
while ($children > 0) {
forward_data($callback,$sub_fds);
}
while (forward_data($callback,$sub_fds)) {}
}
sub forward_data {
my $callback = shift;
my $fds = shift;
my @ready_fds = $fds->can_read(1);
my $rfh;
my $rc = @ready_fds;
foreach $rfh (@ready_fds) {
my $data;
if ($data = <$rfh>) {
while ($data !~ /ENDOFFREEZE6sK4ci/) {
$data .= <$rfh>;
}
my $responses=thaw($data);
foreach (@$responses) {
$callback->($_);
}
} else {
$fds->remove($rfh);
close($rfh);
}
}
return $rc;
}
sub dompa {
my $out = shift;
$mpa = shift;
my $mpahash = shift;
my $command=shift;
my %namedargs=@_;
my @exargs=$namedargs{-args};
my $node;
$session = new SNMP::Session(
DestHost => $mpa,
Version => '3',
SecName => $mpahash->{$mpa}->{username},
AuthProto => 'SHA',
AuthPass => $mpahash->{$mpa}->{password},
PrivProto => 'DES',
SecLevel => 'authPriv',
UseNumeric => 1,
Retries => 2, # Give up sooner to make commands go smoother
Timeout=>1200000, #Beacon, for one, takes a bit over a second to return
PrivPass => $mpahash->{$mpa}->{password});
if ($session->{ErrorStr}) { return 1,$session->{ErrorStr}; }
my $tmp = $session->get([$mmprimoid.".1"]);
if ($session->{ErrorStr}) { print $session->{ErrorStr}; }
$activemm = ($tmp ? 1 : 2);
my @outhashes;
if ($command eq "reventlog" and isallchassis) {
#Add a dummy node for eventlog to get non-blade events
$mpahash{$mpa}->{nodes}->{$mpa}=-1;
}
foreach $node (sort (keys %{$mpahash->{$mpa}->{nodes}})) {
my ($rc,@output) = bladecmd($mpa,$mpahash->{$mpa}->{nodes}->{$node},$command,@exargs);
my @output_hashes;
foreach(@output) {
my %output;
(my $desc,my $text) = split (/:/,$_,2);
unless ($text) {
$text=$desc;
} else {
$desc =~ s/^\s+//;
$desc =~ s/\s+$//;
if ($desc) {
$output{node}->[0]->{data}->[0]->{desc}->[0]=$desc;
}
}
$text =~ s/^\s+//;
$text =~ s/\s+$//;
$output{node}->[0]->{name}->[0]=$node;
$output{node}->[0]->{data}->[0]->{contents}->[0]=$text;
print $out freeze([\%output]);
print $out "\nENDOFFREEZE6sK4ci\n";
}
}
#my $msgtoparent=freeze(\@outhashes); # = XMLout(\%output,RootName => 'xcatresponse');
#print $out $msgtoparent; #$node.": $_\n";
}
1;

View File

@ -0,0 +1,102 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::bmcconfig;
use Data::Dumper;
use xCAT::Table;
sub handled_commands {
return {
getbmcconfig => 'bmcconfig',
};
}
sub genpassword {
my $length = shift;
my $password='';
my $characters= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890';
srand; #have to reseed, rand is not rand otherwise
while (length($password) < $length) {
$password .= substr($characters,int(rand 63),1);
}
return $password;
}
sub net_parms {
my $ip = shift;
if ($ip =~ /[A-Za-z]/) {
my $addr = (gethostbyname($ip))[4];
my @bytes = unpack("C4",$addr);
$ip = join(".",@bytes);
}
my $nettab = xCAT::Table->new('networks');
unless ($nettab) { return undef };
my @nets = $nettab->getAllAttribs('net','mask','gateway');
foreach (@nets) {
my $net = $_->{'net'};
my $mask =$_->{'mask'};
my $gw = $_->{'gateway'};
$ip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
my $ipnum = ($1<<24)+($2<<16)+($3<<8)+$4;
$mask =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
my $masknum = ($1<<24)+($2<<16)+($3<<8)+$4;
$net =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/;
my $netnum = ($1<<24)+($2<<16)+($3<<8)+$4;
if (($ipnum & $masknum)==$netnum) {
return ($ip,$mask,$gw);
}
}
}
sub process_request {
my $request = shift;
my $callback = shift;
my $node = $request->{'!xcat_clienthost'}->[0];
my $sitetable = xCAT::Table->new('site');
my $ipmitable = xCAT::Table->new('ipmi');
my $passtable = xCAT::Table->new('passwd');
my $tmphash;
my $username = 'USERID';
my $gennedpassword=0;
my $bmc;
my $password = 'PASSW0RD';
if ($passtable) { $tmphash=$passtable->getAttribs({key=>'ipmi'},'username','password'); }
#Check for generics, can grab for both user and pass with a query
#since they cannot be in disparate records in passwd tab
if ($tmphash->{username}) {
$username=$tmphash->{username};
}
if ($tmphash->{password}) { #It came for free with the last query
$password=$tmphash->{password};
}
$tmphash=($sitetable->getAttribs({key=>'genpasswords'},'value'))[0];
if ($tmphash->{value} eq "1" or $tmphash->{value} =~ /y(es)?/i) {
$password = genpassword(8);
$gennedpassword=1;
} else {
$tmphash=$ipmitable->getNodeAttribs($node,['password']);
if ($tmphash->{password}) {
$password = $tmphash->{password};
}
}
$tmphash=$ipmitable->getNodeAttribs($node,['bmc','username']);
if ($tmphash->{bmc} ) {
$bmc=$tmphash->{bmc};
}
if ($tmphash->{username}) {
$username = $tmphash->{username};
}
(my $ip,my $mask,my $gw) = net_parms($bmc);
my $response={bmcip=>$ip,netmask=>$mask,gateway=>$gw,username=>$username,password=>$password};
$callback->($response);
if ($gennedpassword) { # save generated password
$ipmitable->setNodeAttribs($node,{password=>$password});
}
return 1;
}
1;

View File

@ -0,0 +1,207 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::centos;
use Storable qw(dclone);
use Sys::Syslog;
use xCAT::Table;
use xCAT::Template;
use xCAT::Postage;
use Data::Dumper;
use Getopt::Long;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
use File::Path;
use File::Copy;
my %distnames = (
"1176234647.982657" => "centos5",
"1156364963.862322" => "centos4.4",
"1178480581.024704" => "centos4.5"
);
my %numdiscs = (
"1156364963.862322" => 4,
"1178480581.024704" => 3
);
sub handled_commands {
return {
copycd => "centos",
mkinstall => "nodetype:os=centos.*"
}
}
sub process_request {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my $distname = undef;
my $arch = undef;
my $path = undef;
if ($request->{command}->[0] eq 'copycd') {
return copycd($request,$callback,$doreq);
} elsif ($request->{command}->[0] eq 'mkinstall') {
return mkinstall($request,$callback,$doreq);
}
}
sub mkinstall {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my @nodes = @{$request->{node}};
my $node;
my $ostab = xCAT::Table->new('nodetype');
my %doneimgs;
foreach $node (@nodes) {
my $osinst;
my $ent = $ostab->getNodeAttribs($node,['profile','os','arch']);
unless ($ent->{os} and $ent->{arch} and $ent->{profile}) {
$callback->({error=>["No profile defined in nodetype for $node"],errorcode=>[1]});
next; #No profile
}
my $os = $ent->{os};
my $arch = $ent->{arch};
my $profile = $ent->{profile};
unless (-r "/usr/share/xcat/install/centos/".$ent->{profile}.".tmpl") {
$callback->({error=>["No kickstart template exists for ".$ent->{profile}],errorcode=>[1]});
next;
}
#Call the Template class to do substitution to produce a kickstart file in the autoinst dir
xCAT::Template->subvars("/usr/share/xcat/install/centos/".$ent->{profile}.".tmpl","/install/autoinst/".$node,$node);
mkpath "/install/postscripts/";
xCAT::Postage->writescript($node,"/install/postscripts/".$node);
if (-r "/install/$os/$arch/images/pxeboot/vmlinuz"
and -r "/install/$os/$arch/images/pxeboot/initrd.img") {
#TODO: driver slipstream, targetted for network.
unless ($doneimgs{"$os|$arch"}) {
mkpath("/tftpboot/xcat/$os/$arch");
copy("/install/$os/$arch/images/pxeboot/vmlinuz","/tftpboot/xcat/$os/$arch/");
copy("/install/$os/$arch/images/pxeboot/initrd.img","/tftpboot/xcat/$os/$arch/");
$doneimgs{"$os|$arch"}=1;
}
#We have a shot...
my $restab = xCAT::Table->new('noderes');
my $hmtab = xCAT::Table->new('nodehm');
my $ent = $restab->getNodeAttribs($node,['nfsserver','serialport','primarynic','installnic']);
my $sent = $hmtab->getNodeAttribs($node,['serialspeed','serialflow']);
unless ($ent and $ent->{nfsserver}) {
$callback->({error=>["No noderes.nfsserver defined for ".$ent->{profile}],errorcode=>[1]});
next;
}
my $kcmdline="nofb utf8 ks=http://".$ent->{nfsserver}."/install/autoinst/".$node;
if ($ent->{installnic}) {
$kcmdline.=" ksdevice=".$ent->{installnic};
} elsif ($ent->{primarynic}) {
$kcmdline.=" ksdevice=".$ent->{primarynic};
} else {
$kcmdline .= " ksdevice=eth0";
}
#TODO: dd=<url> for driver disks
if (defined($ent->{serialport})) {
unless ($sent->{serialspeed}) {
$callback->({error=>["serialport defined, but no serialspeed for $node in nodehm table"],errorcode=>[1]});
next;
}
$kcmdline.=" console=ttyS".$ent->{serialport}.",".$sent->{serialspeed};
if ($sent->{serialflow} =~ /(hard|cts|ctsrts)/) {
$kcmdline .= "n8r";
}
}
$kcmdline .= " noipv6";
$restab->setNodeAttribs($node,{
kernel=>"xcat/$os/$arch/vmlinuz",
initrd=>"xcat/$os/$arch/initrd.img",
kcmdline=>$kcmdline
});
} else {
$callback->({error=>["Unable to find kernel and initrd for $os and $arch in install source /install/$os/$arch"],errorcode=>[1]});
}
}
}
sub copycd {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my $installroot;
my $sitetab = xCAT::Table->new('site');
if ($sitetab) {
(my $ref) = $sitetab->getAttribs({key=>installdir},value);
print Dumper($ref);
if ($ref and $ref->{value}) {
$installroot = $ref->{value};
}
}
@ARGV= @{$request->{arg}};
GetOptions(
'n=s' => \$distname,
'a=s' => \$arch,
'p=s' => \$path
);
unless ($path) {
#this plugin needs $path...
return;
}
if ($distname and $distname !~ /^centos/) {
#If they say to call it something other than CentOS, give up?
return;
}
unless (-r $path."/.discinfo") {
return;
}
my $dinfo;
open($dinfo,$path."/.discinfo");
my $did = <$dinfo>;
chomp($did);
my $desc = <$dinfo>;
chomp($desc);
my $darch = <$dinfo>;
chomp($darch);
if ($darch and $darch =~ /i.86/) {
$darch = "x86";
}
close($dinfo);
if ($distnames{$did}) {
unless ($distname) {
$distname = $distnames{$did};
}
} elsif ($desc =~ /^Final$/) {
unless ($distname) {
$distname = "centos5";
}
} elsif ($desc =~ /^CentOS-4 .*/) {
unless ($distname) {
$distname = "centos4";
}
}
unless ($distname) {
return; #Do nothing, not ours..
}
if ($darch) {
unless ($arch) {
$arch = $darch;
}
if ($arch and $arch ne $darch) {
$callback->({error=>"Requested CentOS architecture $arch, but media is $darch"});
return;
}
}
%{$request} = (); #clear request we've got it.
$callback->({data=>"Copying media to $installroot/$distname/$arch/"});
my $omask=umask 0022;
mkpath("$installroot/$distname/$arch");
umask $omask;
my $rc = system("cd $path; find . | nice -n 20 cpio -dump $installroot/$distname/$arch");
chmod 0755,"$installroot/$distname/$arch";
if ($rc != 0) {
$callback->({error=>"Media copy operation failed, status $rc"});
} else {
$callback->({data=>"Media copy operation successful"});
}
}
1;

View File

@ -0,0 +1,206 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#TODO: delete entries not being refreshed if no noderange
package xCAT_plugin::conserver;
use xCAT::Table;
use strict;
use Data::Dumper;
my @cservers = qw(mrv cyclades);
my %termservers; #list of noted termservers
sub handled_commands {
return {
makeconservercf => "conserver"
}
}
sub process_request {
my $req = shift;
my $cb = shift;
if ($req->{command}->[0] eq "makeconservercf") {
makeconservercf($req,$cb);
}
}
sub docfheaders {
# Put in standard headers common to all conserver.cf files
my $content = shift;
my $numlines = @$content;
my @meat = grep(!/^#/,@$content);
unless (grep(/^default full/,@meat)) {
push @$content,"default full { rw *; }\n";
}
unless (grep(/^default cyclades/,@meat)) {
push @$content,"default cyclades { type host; portbase 7000; portinc 1; }\n"
}
unless (grep(/^default mrv/,@meat)) {
push @$content,"default mrv { type host; portbase 2000; portinc 100; }\n"
}
unless (grep(/^access \*/,@meat)) {
#TODO: something intelligent, allowing other hosts in
#push @$content,"#xCAT BEGIN ACCESS\n";
push @$content,"access * {\n";
push @$content," trusted 127.0.0.1;\n";
push @$content,"}\n";
#push @$content,"#xCAT END ACCESS\n";
}
unless (grep(/^default \*/,@meat)) {
push @$content,"default * {\n";
push @$content," logfile /var/log/consoles/&;\n";
push @$content," timestamp 1hab;\n";
push @$content," include full;\n";
push @$content," master localhost;\n";
push @$content,"}\n";
}
}
sub makeconservercf {
my $req = shift;
%termservers = (); #clear hash of existing entries
my $cb = shift;
my $nodes = $req->{node};
my $cfile;
my @filecontent;
open $cfile,'/etc/conserver.cf';
while (<$cfile>) {
push @filecontent,$_;
}
close $cfile;
docfheaders(\@filecontent);
my $hmtab = xCAT::Table->new('nodehm');
my @cfgents = $hmtab->getAllNodeAttribs(['mgt','cons']);
#cfgents should now have all the nodes, so we can fill in our hashes one at a time.
foreach (@cfgents) {
unless ($_->{cons}) {$_->{cons} = $_->{mgt};} #populate with fallback
my $cmeth=$_->{cons};
if (grep(/^$cmeth$/,@cservers)) { #terminal server, more attribs needed
my $node = $_->{node};
my $tent = $hmtab->getNodeAttribs($node,["termserver","termport"]);
$_->{termserver} = $tent->{termserver};
$termservers{$tent->{termserver}} = 1;
$_->{termport}= $tent->{termport};
}
}
if (($nodes and @$nodes > 0) or $req->{noderange}->[0]) {
foreach (@$nodes) {
my $node = $_;
foreach (@cfgents) {
if ($_->{node} eq $node) {
if ($_->{termserver} and $termservers{$_->{termserver}}) {
dotsent($_,\@filecontent);
delete $termservers{$_->{termserver}}; #prevent needless cycles being burned
}
donodeent($_,\@filecontent);
}
}
}
} else { #no nodes specified, do em all up
zapcfg(\@filecontent); # strip all xCAT configured stuff from config
foreach (@cfgents) {
if ($_->{termserver} and $termservers{$_->{termserver}}) {
dotsent($_,\@filecontent);
delete $termservers{$_->{termserver}}; #prevent needless cycles being burned
}
donodeent($_,\@filecontent);
}
}
open $cfile,'>','/etc/conserver.cf';
foreach (@filecontent) {
print $cfile $_;
}
close $cfile;
}
sub dotsent {
my $cfgent = shift;
my $tserv = $cfgent->{termserver};
my $content = shift;
my $idx = 0;
my $toidx = -1;
my $skip = 0;
my $skipnext = 0;
while ($idx < $#$content) { # Go through and delete that which would match my entry
if ($content->[$idx] =~ /^#xCAT BEGIN $tserv TS/) {
$toidx=$idx; #TODO put it back right where I found it
$skip = 1;
$skipnext=1;
} elsif ($content->[$idx] =~ /^#xCAT END $tserv TS/) {
$skipnext = 0;
}
if ($skip) {
splice (@$content,$idx,1);
} else {
$idx++;
}
$skip = $skipnext;
}
push @$content,"#xCAT BEGIN $tserv TS\n";
push @$content,"default $tserv {\n";
push @$content," include ".$cfgent->{cons}.";\n";
push @$content," host $tserv;\n";
push @$content,"}\n";
push @$content,"#xCAT END $tserv TS\n";
}
sub donodeent {
my $cfgent = shift;
my $node = $cfgent->{node};
my $content = shift;
my $idx=0;
my $toidx=-1;
my $skip = 0;
my $skipnext = 0;
while ($idx < $#$content) { # Go through and delete that which would match my entry
if ($content->[$idx] =~ /^#xCAT BEGIN $node CONS/) {
$toidx=$idx; #TODO put it back right where I found it
$skip = 1;
$skipnext=1;
} elsif ($content->[$idx] =~ /^#xCAT END $node CONS/) {
$skipnext = 0;
}
if ($skip) {
splice (@$content,$idx,1);
} else {
$idx++;
}
$skip = $skipnext;
}
push @$content,"#xCAT BEGIN $node CONS\n";
push @$content,"console $node {\n";
#if ($cfgent->{cons}
my $cmeth=$cfgent->{cons};
print $cmeth."\n";
if (grep(/^$cmeth$/,@cservers)) {
push @$content," include ".$cfgent->{termserver}.";\n";
push @$content," port ".$cfgent->{termport}.";\n";
} else { #a script method...
push @$content," type exec;\n";
push @$content," exec /usr/share/xcat/cons/".$cmeth." ".$node.";\n"
}
push @$content,"}\n";
push @$content,"#xCAT END $node CONS\n";
}
sub zapcfg {
my $content = shift;
my $idx=0;
my $toidx=-1;
my $skip = 0;
my $skipnext = 0;
while ($idx <= $#$content) { # Go through and delete that which would match my entry
if ($content->[$idx] =~ /^#xCAT BEGIN/) {
$toidx=$idx; #TODO put it back right where I found it
$skip = 1;
$skipnext=1;
} elsif ($content->[$idx] =~ /^#xCAT END/) {
$skipnext = 0;
}
if ($skip) {
splice (@$content,$idx,1);
} else {
$idx++;
}
$skip = $skipnext;
}
}
1;

View File

@ -0,0 +1,70 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::copycds;
use Storable qw(dclone);
use xCAT::Table;
use Data::Dumper;
use Getopt::Long;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
my $processed = 0;
my $callback;
sub handled_commands {
return {
copycds => "copycds",
}
}
sub take_answer {
#TODO: Intelligently filter and decide things
my $resp = shift;
$callback->($resp);
}
sub process_request {
my $request = shift;
$callback = shift;
my $doreq = shift;
my $distname = undef;
my $arch = undef;
@ARGV = @{$request->{arg}};
GetOptions(
'n|name|osver=s' => \$distname,
'a|arch=s' => \$arch
);
if ($arch and $arch =~ /i.86/) {
$arch = x86;
}
my @args = @ARGV; #copy ARGV
unless ($#args >= 0) {
$callback->({error=>"copycds needs at least one full path to ISO currently."});
return;
}
foreach (@args) {
unless (-r $_ and -f $_) {
$callback->({error=>"copycds currently only understands FULL path to iso files, $_ not processed"});
return;
}
mkdir "/mnt/xcat";
if (system("mount -o loop $_ /mnt/xcat")) {
$callback->({error=>"copycds was unable to examine $_ as an install image"});
return;
}
my $newreq = dclone($request);
$newreq->{command}= [ 'copycd' ]; #Note the singular, it's different
$newreq->{arg} = ["-p","/mnt/xcat"];
if ($distname) {
push @{$newreq->{arg}},("-n",$distname);
}
if ($arch) {
push @{$newreq->{arg}},("-a",$arch);
}
$doreq->($newreq,\&take_answer);
system("umount /mnt/xcat");
}
}
1;

View File

@ -0,0 +1,239 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::destiny;
use xCAT::NodeRange;
use Data::Dumper;
use Sys::Syslog;
use strict;
my $request;
my $callback;
my $subreq;
my $errored = 0;
sub handled_commands {
return {
setdestiny => "destiny",
getdestiny => "destiny",
nextdestiny => "destiny"
}
}
sub process_request {
$request = shift;
$callback = shift;
$subreq = shift;
if ($request->{command}->[0] eq 'getdestiny') {
getdestiny();
}
if ($request->{command}->[0] eq 'nextdestiny') {
nextdestiny($request);
}
if ($request->{command}->[0] eq 'setdestiny') {
setdestiny($request);
}
}
sub relay_response {
my $resp = shift;
$callback->($resp);
if ($resp and $resp->{errorcode} and $resp->{errorcode}->[0]) {
$errored = 1;
}
}
sub setdestiny {
my $req=shift;
my $chaintab = xCAT::Table->new('chain');
my @nodes=@{$req->{node}};
my $state = $req->{arg}->[0];
if ($state eq "next") {
return nextdestiny();
} elsif ($state =~ /^install$/ or $state eq "install") {
my $nodetype = xCAT::Table->new('nodetype');
foreach (@{$req->{node}}) {
my $ntent = $nodetype->getNodeAttribs($_,[qw(os arch profile)]);
if ($ntent and $ntent->{os}) {
$state = "install ".$ntent->{os};
}
if ($ntent and $ntent->{arch}) {
$state .= "-".$ntent->{arch};
}
if ($ntent and $ntent->{profile}) {
$state .= "-".$ntent->{profile};
}
$chaintab->setNodeAttribs($_,{currchain=>"boot"});
}
$subreq->({command=>["mkinstall"],
node=>$req->{node}}, \&relay_response);
if ($errored) { return; }
} elsif ($state eq "shell" or $state eq "standby" or $state =~ /^runcmd/) {
my $noderes=xCAT::Table->new('noderes');
my $nodetype = xCAT::Table->new('nodetype');
my $sitetab = xCAT::Table->new('site');
(my $portent) = $sitetab->getAttribs({key=>'xcatdport'},'value');
(my $mastent) = $sitetab->getAttribs({key=>'master'},'value');
foreach (@nodes) {
my $ent = $nodetype->getNodeAttribs($_,[qw(arch)]);
unless ($ent and $ent->{arch}) {
$callback->({error=>["No archictecture defined in nodetype table for $_"],errorcode=>[1]});
return;
}
my $arch = $ent->{arch};
my $ent = $noderes->getNodeAttribs($_,[qw(xcatmaster)]);
my $master;
if ($mastent and $mastent->{value}) {
$master = $mastent->{value};
}
if ($ent and $ent->{xcatmaster}) {
$master = $ent->{xcatmaster};
}
unless ($master) {
$callback->({error=>["No master in site table nor noderes table for $_"],errorcode=>[1]});
return;
}
my $xcatdport="3001";
if ($portent and $portent->{value}) {
$xcatdport = $portent->{value};
}
$noderes->setNodeAttribs($_,{kernel => "xcat/nbk.$arch",
initrd => "xcat/nbfs.$arch.gz",
kcmdline => "xcatd=$master:$xcatdport"});
}
$nodetype->close;
} elsif (!($state eq "boot")) {
$callback->({error=>["Unknown state $state requested"],errorcode=>[1]});
return;
}
foreach (@nodes) {
$chaintab->setNodeAttribs($_,{currstate=>$state});
}
return getdestiny();
}
sub nextdestiny {
my @nodes;
if ($request and $request->{node}) {
if (ref($request->{node})) {
@nodes = @{$request->{node}};
} else {
@nodes = ($request->{node});
}
#TODO: service third party getdestiny..
} else { #client asking to move along its own chain
#TODO: SECURITY with this, any one on a node could advance the chain, for node, need to think of some strategy to deal with...
unless ($request->{'!xcat_clienthost'}->[0]) {
#ERROR? malformed request
return; #nothing to do here...
}
my $node = $request->{'!xcat_clienthost'}->[0];
($node) = noderange($node);
unless ($node) {
#not a node, don't trust it
return;
}
@nodes=($node);
}
my $node;
foreach $node (@nodes) {
my $chaintab = xCAT::Table->new('chain');
unless($chaintab) {
syslog("local1|err","ERROR: $node requested destiny update, no chain table");
return; #nothing to do...
}
my $ref = $chaintab->getNodeAttribs($node,[qw(currstate currchain chain)]);
unless ($ref->{chain}) {
syslog ("currchain local1|err","ERROR: node requested destiny update, no path in chain.currchain");
$chaintab->close;
return; #Can't possibly do anything intelligent..
}
unless ($ref->{currchain}) { #If no current chain, copy the default
$ref->{currchain} = $ref->{chain};
}
my @chain = split /[,:;]/,$ref->{currchain};
$ref->{currstate} = shift @chain;
$ref->{currchain}=join(',',@chain);
unless ($ref->{currchain}) { #If we've gone off the end of the chain, have currchain stick
$ref->{currchain} = $ref->{currstate};
}
$chaintab->setNodeAttribs($node,$ref); #$ref is in a state to commit back to db
$chaintab->close;
my %requ;
$requ{node}=[$node];
$requ{arg}=[$ref->{currstate}];
setdestiny(\%requ);
getdestiny();
}
}
sub getdestiny {
my @args;
my @nodes;
if ($request->{node}) {
if (ref($request->{node})) {
@nodes = @{$request->{node}};
} else {
@nodes = ($request->{node});
}
} else { # a client asking for it's own destiny.
unless ($request->{'!xcat_clienthost'}->[0]) {
$callback->({destiny=>[ 'discover' ]});
return;
}
my ($node) = noderange($request->{'!xcat_clienthost'}->[0]);
unless ($node) { # it had a valid hostname, but isn't a node
$callback->({destiny=>[ 'discover' ]});
return;
}
@nodes=($node);
}
my $node;
foreach $node (@nodes) {
my $chaintab = xCAT::Table->new('chain');
unless ($chaintab) { #Without destiny, have the node wait with ssh hopefully open at least
$callback->({node=>[{name=>[$node],data=>['standby'],destiny=>[ 'standby' ]}]});
return;
}
my $ref = $chaintab->getNodeAttribs($node,[qw(currstate chain)]);
unless ($ref) {
$callback->({node=>[{name=>[$node],data=>['standby'],destiny=>[ 'standby' ]}]});
return;
}
unless ($ref->{currstate}) { #Has a record, but not yet in a state...
my @chain = split /,/,$ref->{chain};
$ref->{currstate} = shift @chain;
$chaintab->setNodeAttribs($node,{currstate=>$ref->{currstate}});
}
my $noderestab = xCAT::Table->new('noderes'); #In case client decides to download images, get data out to it
my %response;
$response{name}=[$node];
$response{data}=[$ref->{currstate}];
$response{destiny}=[$ref->{currstate}];
my $sitetab= xCAT::Table->new('site');
my $nrent = $noderestab->getNodeAttribs($node,[qw(tftpserver kernel initrd kcmdline xcatmaster)]);
(my $sent) = $sitetab->getAttribs({key=>'master'},'value');
if (defined $nrent->{kernel}) {
$response{kernel}=$nrent->{kernel};
}
if (defined $nrent->{initrd}) {
$response{initrd}=$nrent->{initrd};
}
if (defined $nrent->{kcmdline}) {
$response{kcmdline}=$nrent->{kcmdline};
}
if (defined $nrent->{tftpserver}) {
$response{imgserver}=$nrent->{tftpserver};
} elsif (defined $nrent->{xcatmaster}) {
$response{imgserver}=$nrent->{xcatmaster};
} elsif (defined($sent->{value})) {
$response{imgserver}=$sent->{value};
}
$callback->({node=>[\%response]});
}
}
1;

View File

@ -0,0 +1,333 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::dhcp;
use xCAT::Table;
use Data::Dumper;
use MIME::Base64;
use Socket;
use Sys::Syslog;
use IPC::Open2;
my @dhcpconf; #Hold DHCP config file contents to be written back.
my @nrn; # To hold output of netstat -rn to be consulted throughout process
my $domain;
my $omshell;
sub handled_commands {
return {
makedhcp => "dhcp",
}
}
sub delnode {
my $node = shift;
my $inetn = inet_aton($node);
print $omshell "new host\n";
print $omshell "set name = \"$node\"\n"; #Find and destroy conflict name
print $omshell "open\n";
print $omshell "remove\n";
print $omshell "close\n";
if ($inetn) {
my $ip = inet_ntoa(inet_aton($node));;
unless ($ip) { return; }
print $omshell "new host\n";
print $omshell "set ip-address = $ip\n"; #find and destroy ip conflict
print $omshell "open\n";
print $omshell "remove\n";
print $omshell "close\n";
}
}
sub addnode {
#Use omshell to add the node.
#the process used is blind typing commands that should work
#it tries to delet any conflicting entries matched by name and
#hardware address and ip address before creating a brand now one
#unfortunate side effect: dhcpd.leases can look ugly over time, when
#doing updates would keep it cleaner, good news, dhcpd restart cleans
#up the lease file the way we would want anyway.
my $node = shift;
my $ent;
my $mactab = xCAT::Table->new('mac');
unless ($mactab) { return; } #TODO: report error sanely
$ent = $mactab->getNodeAttribs($node,[qw(mac interface)]);
unless ($ent and $ent->{mac}) {
return; #TODO: sane error
}
my $inetn = inet_aton($node);
unless ($inetn) {
syslog("local1|err","xCAT DHCP plugin unable to resolve IP for $node");
return;
}
my $ip = inet_ntoa(inet_aton($node));;
print "Setting $node ($ip) to ".$ent->{mac}."\n";
print $omshell "new host\n";
print $omshell "set name = \"$node\"\n"; #Find and destroy conflict name
print $omshell "open\n";
print $omshell "remove\n";
print $omshell "close\n";
print $omshell "new host\n";
print $omshell "set ip-address = $ip\n"; #find and destroy ip conflict
print $omshell "open\n";
print $omshell "remove\n";
print $omshell "close\n";
print $omshell "new host\n";
print $omshell "set hardware-address = ".$ent->{mac}."\n"; #find and destroy mac conflict
print $omshell "open\n";
print $omshell "remove\n";
print $omshell "close\n";
print $omshell "new host\n";
print $omshell "set name = \"$node\"\n";
print $omshell "set hardware-address = ".$ent->{mac}."\n";
print $omshell "set hardware-type = 1\n";
print $omshell "set ip-address = $ip\n";
print $omshell "create\n";
unless (grep /#definition for host $node/,@dhcpconf) {
push @dhcpconf,"#definition for host $node can be found in the dhcpd.leases file\n";
}
}
sub process_request {
my $req = shift;
my $callback = shift;
my $sitetab = xCAT::Table->new('site');
my %activenics;
my $querynics=1;
if ($sitetab) {
my $href;
($href) = $sitetab->getAttribs({key=>'dhcpinterfaces'},'value');
unless ($href and $href->{value}) { #LEGACY: singular keyname for old style site value
($href) = $sitetab->getAttribs({key=>'dhcpinterface'},'value');
}
if ($href and $href->{value}) {
foreach (split /[,\s]+/,$href->{value}) {
$activenics{$_} = 1;
$querynics=0;
}
}
($href) = $sitetab->getAttribs({key=>'domain'},'value');
unless ($href and $href->{value}) {
$callback->({error=>["No domain defined in site tabe"],errorcode=>[1]});
return;
}
$domain = $href->{value};
}
@dhcpconf = ();
unless ($req->{arg} or $req->{node}) {
$callback->({data=>["Usage: makedhcp <-n> <noderange>"]});
return;
}
if (grep /-n/,@{$req->{arg}}) {
if (-e "/etc/dhcpd.conf") {
my $bakname = "/etc/dhcpd.conf.xcatbak";
while (-e $bakname) { #look for unused backup name..
$bakname .= "~";
}
rename("/etc/dhcpd.conf",$bakname);
}
} else {
open($rconf,"/etc/dhcpd.conf"); # Read file into memory
if ($rconf) {
while (<$rconf>) {
push @dhcpconf,$_;
}
close($rconf);
}
unless ($dhcpconf[0] =~ /^#xCAT/) { #Discard file if not xCAT originated, like 1.x did
@dhcpconf = ();
}
}
@nrn = split /\n/,`/bin/netstat -rn`;
splice @nrn,0,2; #get rid of header
if ($querynics) { #Use netstat to determine activenics only when no site ent.
foreach (@nrn) {
my @ent = split /\s+/;
if ($ent[7] =~ m/(ipoib|ib|vlan|bond|eth|myri|man|wlan)/) { #Mask out many types of interfaces, like xCAT 1.x
$activenics{$ent[7]} = 1;
}
}
}
unless ($dhcpconf[0]) { #populate an empty config with some starter data...
newconfig();
}
foreach (keys %activenics) {
addnic($_);
}
if ($req->{node}) {
my $passtab = xCAT::Table->new('passwd');
my $ent;
($ent) = $passtab->getAttribs({key=>"omapi"},qw(username password));
unless ($ent->{username} and $ent->{password}) { return; } # TODO sane err
#Have nodes to update
#open2($omshellout,$omshell,"/usr/bin/omshell");
open($omshell,"|/usr/bin/omshell > /dev/null");
print $omshell "key ".$ent->{username}." \"".$ent->{password}."\"\n";
print $omshell "connect\n";
foreach(@{$req->{node}}) {
if (grep /^-d$/,@{$req->{arg}}) {
delnode $_;
} else {
addnode $_;
}
}
close($omshell);
}
foreach (@nrn) {
my @line = split /\s+/;
if ($activenics{$line[7]}) {
addnet($line[0],$line[2]);
}
}
writeout();
}
sub addnet {
my $net = shift;
my $mask = shift;
my $nic;
unless (grep /\} # $net\/$mask subnet_end/,@dhcpconf) {
foreach (@nrn) { # search for relevant NIC
my @ent = split /\s+/;
if ($ent[0] eq $net and $ent[2] eq $mask) {
$nic=$ent[7];
}
}
print "Need to add $net $mask under $nic\n";
my $idx=0;
while ($idx <= $#dhcpconf) {
if ($dhcpconf[$idx] =~ /\} # $nic nic_end\n/) {
last;
}
$idx++;
}
unless ($dhcpconf[$idx] =~ /\} # $nic nic_end\n/) {
return 1; #TODO: this is an error condition
}
# if here, means we found the idx before which to insert
my $nettab = xCAT::Table->new("networks");
my $nameservers;
my $gateway;
my $tftp;
my $range;
if ($nettab) {
my ($ent) = $nettab->getAttribs({net=>$net,mask=>$mask},qw(tftpserver nameservers gateway dynamicrange));
if ($ent and $ent->{nameservers}) {
$nameservers = $ent->{nameservers};
}
if ($ent and $ent->{tftpserver}) {
$tftp = $ent->{tftpserver};
}
if ($ent and $ent->{gateway}) {
$gateway = $ent->{gateway};
}
if ($ent and $ent->{dynamicrange}) {
$range = $ent->{dynamicrange};
$range =~ s/[,-]/ /g;
}
}
my @netent;
@netent = (
" subnet $net netmask $mask {\n",
" max-lease-time 43200;\n",
" min-lease-time 43200;\n",
" default-lease-time 43200;\n"
);
if ($gateway) {
push @netent," option routers $gateway;\n";
}
if ($tftp) {
push @netent," next-server $tftp;\n";
}
push @netent," option domain-name \"$domain\";\n";
if ($nameservers) {
push @netent," option domain-name-servers $nameservers;\n";
}
push @netent," if option client-architecture = 00:00 { #x86\n";
push @netent," filename \"pxelinux.0\";\n";
push @netent," } else if option client-architecture = 00:02 { #ia64\n ";
push @netent," filename \"elilo.efi\";\n";
push @netent," } else if substring(filename,0,1) = null { #otherwise, provide yaboot if the client isn't specific\n ";
push @netent," filename \"yaboot\";\n";
push @netent," }\n";
if ($range) { push @netent," range dynamic-bootp $range;\n" };
push @netent," } # $net\/$mask subnet_end\n";
splice(@dhcpconf,$idx,0,@netent);
}
}
sub addnic {
my $nic = shift;
my $firstindex=0;
my $lastindex=0;
unless (grep /} # $nic nic_end/,@dhcpconf) { #add a section if not there
print "Adding NIC $nic\n";
push @dhcpconf,"shared-network $nic {\n";
push @dhcpconf,"\} # $nic nic_end\n";
}
#return; #Don't touch it, it should already be fine..
#my $idx=0;
#while ($idx <= $#dhcpconf) {
# if ($dhcpconf[$idx] =~ /^shared-network $nic {/) {
# $firstindex = $idx; # found the first place to chop...
# } elsif ($dhcpconf[$idx] =~ /} # $nic network_end/) {
# $lastindex=$idx;
# }
# $idx++;
#}
#print Dumper(\@dhcpconf);
#if ($firstindex and $lastindex) {
# splice @dhcpconf,$firstindex,($lastindex-$firstindex+1);
#}
#print Dumper(\@dhcpconf);
}
sub writeout {
my $targ;
open($targ,'>',"/etc/dhcpd.conf");
foreach (@dhcpconf) {
print $targ $_;
}
close($targ)
}
sub newconfig {
# This function puts a standard header in and enough to make omapi work.
my $passtab = xCAT::Table->new('passwd',-create=>1);
push @dhcpconf,"#xCAT generated dhcp configuration\n";
push @dhcpconf,"\n";
push @dhcpconf,"authoritative;\n";
push @dhcpconf,"ddns-update-style none;\n";
push @dhcpconf,"option client-architecture code 93 = unsigned integer 16;\n";
push @dhcpconf,"\n";
push @dhcpconf,"omapi-port 7911;\n"; #Enable omapi...
push @dhcpconf,"key xcat_key {\n";
push @dhcpconf," algorithm hmac-md5;\n";
my $secret = encode_base64(genpassword(32)); #Random from set of 62^32
chomp $secret;
$passtab->setAttribs({key=>omapi},{username=>'xcat_key',password=>$secret});
push @dhcpconf," secret \"".$secret."\";\n";
push @dhcpconf,"};\n";
push @dhcpconf,"omapi-key xcat_key;\n";
}
sub genpassword {
#Generate a pseudo-random password of specified length
my $length = shift;
my $password='';
my $characters= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890';
srand; #have to reseed, rand is not rand otherwise
while (length($password) < $length) {
$password .= substr($characters,int(rand 63),1);
}
return $password;
}
1;

View File

@ -0,0 +1,88 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::hosts;
use xCAT::Table;
use Data::Dumper;
my @hosts; #Hold /etc/hosts data to be written back
my %usage=(
makehosts => "Usage: makehosts [-n] <noderange>",
);
sub handled_commands {
return {
makehosts => "hosts",
}
}
sub addnode {
my $node = shift;
my $ip = shift;
my $othernames = shift;
my $idx=0;
my $foundone=0;
while ($idx <= $#hosts) {
if ($hosts[$idx] =~ /^${ip}\s/ or $hosts[$idx] =~ /^\d+\.\d+\.\d+\.\d+\s+${node}\s/) {
#TODO: if foundone, delete a dupe
$hosts[$idx] = "$ip $node $othernames\n";
$foundone=1;
}
$idx++;
}
if ($foundone) { return;}
push @hosts,"$ip $node $othernames\n";
}
sub process_request {
my $req = shift;
my $callback = shift;
my $hoststab = xCAT::Table->new('hosts');
@hosts = ();
if (grep /-h/,@{$req->{arg}}) {
$callback->({data=>$usage{makehosts}});
return;
}
if (grep /-n/,@{$req->{arg}}) {
if (-e "/etc/hosts") {
my $bakname = "/etc/hosts.xcatbak";
while (-e $bakname) { #look for unused backup name..
$bakname .= "~";
}
rename("/etc/hosts",$bakname);
}
} else {
open($rconf,"/etc/hosts"); # Read file into memory
if ($rconf) {
while (<$rconf>) {
push @hosts,$_;
}
close($rconf);
}
}
if ($req->{node}) {
foreach(@{$req->{node}}) {
my $ref = $hoststab->getNodeAttribs($_,[qw(ip node hostnames)]);
addnode $ref->{node},$ref->{ip},$ref->{hostnames};
}
} else {
my @hostents = $hoststab->getAllNodeAttribs(['ip','node','hostnames']);
foreach (@hostents) {
addnode $_->{node},$_->{ip},$_->{hostnames};
}
}
writeout();
}
sub writeout {
my $targ;
open($targ,'>',"/etc/hosts");
foreach (@hosts) {
print $targ $_;
}
close($targ)
}
1;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::networks;
use xCAT::Table;
use Data::Dumper;
use Sys::Syslog;
sub handled_commands {
return {
makenetworks => "networks",
}
}
sub process_request {
my $nettab = xCAT::Table->new('networks',-create=>1,-autocommit=>0);
my @rtable = split /\n/,`/bin/netstat -rn`;
open($rconf,"/etc/resolv.conf");
my @nameservers;
if ($rconf) {
my @rcont;
while (<$rconf>) {
push @rcont,$_;
}
close($rconf);
foreach (grep /nameserver/,@rcont) {
my $line = $_;
my @pair;
$line =~ s/#.*//;
@pair = split(/\s+/,$line);
push @nameservers,$pair[1];
}
}
splice @rtable,0,2;
foreach (@rtable) { #should be the lines to think about, do something with U, and something else with UG
my $net;
my $mask;
my $gw;
my @ent = split /\s+/,$_;
if ($ent[3] eq 'U') {
$net = $ent[0];
$mask = $ent[2];
$nettab->setAttribs({'net'=>$net},{'mask'=>$mask});
my $tent = $nettab->getAttribs({'net'=>$net},nameservers);
unless ($tent and $tent->{nameservers}) {
my $text = join ',',@nameservers;
$nettab->setAttribs({'net'=>$net},{nameservers=>$text});
}
unless ($tent and $tent->{tftpserver}) {
my $netdev=$ent[7];
my @netlines = split/\n/,`/sbin/ip addr show dev $netdev`;
foreach (grep /\s*inet\b/,@netlines) {
my @row = split(/\s+/,$_);
my $ipaddr = $row[2];
$ipaddr =~ s/\/.*//;
my @maska=split(/\./,$mask);
my @ipa=split(/\./,$ipaddr);
my @neta=split(/\./,$net);
my $isme=1;
foreach (0..3) {
my $oct = (0+$maska[$_]) & ($ipa[$_]+0);
unless ($oct == $neta[$_]) {
$isme=0;
last;
}
}
if ($isme) {
$nettab->setAttribs({'net'=>$net},{tftpserver=>$ipaddr});
last;
}
}
}
$nettab->commit;
#Nothing much sane to do for the other fields at the moment?
} elsif ($ent[3] eq 'UG') {
#TODO: networks through gateway. and how we might care..
} else {
#TODO: anything to do with such entries?
}
}
}
1;

View File

@ -0,0 +1,65 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::nodediscover;
#use Net::SNMP qw(:snmp INTEGER);
use xCAT::Table;
use IO::Socket;
use SNMP;
use strict;
use XML::Simple;
use Data::Dumper;
use POSIX "WNOHANG";
use Storable qw(freeze thaw);
use IO::Select;
use IO::Handle;
use Sys::Syslog;
sub handled_commands {
return {
discovered => 'chain:ondiscover',
};
}
sub process_request {
my $request = shift;
my $callback = shift;
my $node = $request->{node}->[0];
my $ip = $request->{'!xcat_clientip'};
openlog("xCAT node discovery",'','local0');
#First, fill in tables with data fields..
if (defined($request->{mtm}) or defined($request->{serial})) {
my $vpdtab = xCAT::Table->new("vpd",-create=>1);
if ($request->{mtm}->[0]) {
$vpdtab->setNodeAttribs($node,{mtm=>$request->{mtm}->[0]});
}
if ($request->{serial}) {
$vpdtab->setNodeAttribs($node,{serial=>$request->{serial}->[0]});
}
}
if (defined($request->{arch})) {
my $typetab=xCAT::Table->new("nodetype",-create=>1);
$typetab->setNodeAttribs($node,{arch=>$request->{arch}->[0]});
}
#TODO: mac table? on the one hand, 'the' definitive interface was determined earlier...
#Delete the state it was in to make it traverse destiny once agoin
my $chaintab = xCAT::Table->new('chain');
if ($chaintab) {
$chaintab->setNodeAttribs($node,{currstate=>'',currchain=>''});
$chaintab->close();
}
#now, notify the node to continue life
my $sock = new IO::Socket::INET (
PeerAddr => $ip,
PeerPort => '3001',
Proto => 'tcp'
);
unless ($sock) { syslog("err","Failed to notify $ip that it's actually $node."); return; } #Give up if the node won't hear of it.
print $sock "restart";
close($sock);
syslog("info","$node has been discovered");
}
1;

View File

@ -0,0 +1,285 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::notification;
use xCAT::Table;
use xCAT::NotifHandler;
1;
#-------------------------------------------------------------------------------
=head1 xCAT_plugin:notification
=head2 Package Description
xCAT notification plugini module. This mondule allows users to register and
unregister for the xCAT database table changes.
=cut
#-------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
=head3 handled_commands
It returns a list of commands handled by this plugin.
Arguments:
none
Returns:
a list of commands.
=cut
#-------------------------------------------------------------------------------
sub handled_commands {
return {
regnotif => "notification",
unregnotif => "notification",
refnotif => "notification",
lsnotif => "notification",
enablenotif => "notification",
disablenotif => "notification",
}
}
#--------------------------------------------------------------------------------
=head3 process_request
It processes the monitoring control commands.
Arguments:
request -- a hash table which contains the command name.
callback -- a callback pointer to return the response to.
args -- a list of arguments that come with the command.
Returns:
0 for success. The output is returned through the callback pointer.
1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#-------------------------------------------------------------------------------
sub process_request {
use Getopt::Long;
# options can be bundled up like -vV
Getopt::Long::Configure("bundling") ;
$Getopt::Long::ignorecase=0;
my $request = shift;
my $callback = shift;
my $command = $request->{command}->[0];
my $args=$request->{arg};
if ($command eq "regnotif") {
my ($ret, $msg) = regNotification($args, $callback);
if ($msg) {
my %rsp=();
$rsp->{dara}->[0]= $msg;
$callback->($rsp);
}
return $ret;
}
elsif ($command eq "unregnotif") {
my ($ret, $msg) = unregNotification($args, $callback);
if ($msg) {
my %rsp=();
$rsp->{data}->[0]= $msg;
$callback->($rsp);
}
return $ret;
}
else {
my %rsp=();
$rsp->{data}->[0]= "unsupported command: $command.";
$callback->($rsp);
return 1;
}
}
#--------------------------------------------------------------------------------
=head3 regNotification
It registers a notification routine or a command which
will be called when there are changes in the data base tables
that the routine/command is interested in.
Arguments:
args - The format of the args is:
[-h|--help|-v|--version] or
filename tablename[,tablename]... [-o|--operation tableop[,tableop][,tableop]]]
where
tablename - string. a list of comma seperated names of the tables whose changes
will be watched.
filename - string. The name of the module (e.g. /usr/lib/xxx.pm) or
command (e.g. /usr/bin/xxx) that handles the notification.
If it is a perl module, the module must implement the following routine:
processTableChanges(action, table_name, old_data, new_data)
Refer to notify() subroutine for the meaning of the parameters.
If it is a command, the command format should be:
command [-d|-a|-u] tablename {[colnames][rowvalues][rowvalues]...} {[colnames][rowvalues]}
tableop - it can be 'a' for add, 'd' for delete and 'u' for update.
callback - the pointer to the callback function.
Returns:
none
Comments:
If the module or the command already exists in the notification table, this subroutine
will replace it.
=cut
#-------------------------------------------------------------------------------
sub regNotification {
my $args=shift;
my $callback=shift;
my $VERSION;
my $HELP;
my $tableops;
# subroutine to display the usage
sub regnotif_usage
{
my $callbk=shift;
if (! $callbk) { return;}
my %rsp;
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " regnotif filename tablename[,tablename]... [-o|--operation tableop[,tableop][,tableop]]]";
$rsp->{data}->[2]= " where tableop can be 'a' for add, 'd' for delete and 'u' for update";
$rsp->{data}->[3]= " regnotif [-h|--help|-v|--version]";
$callbk->($rsp);
}
@ARGV=@{$args};
# parse the options
if(!GetOptions(
'o|operation=s' => \$tableops,
'h|help' => \$::HELP,
'v|version' => \$::VERSION,))
{
&regnotif_usage($callback);
return;
}
# display the usage if -h or --help is specified
if ($::HELP) {
&regnotif_usage($callback);
return;
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my %rsp;
$rsp->{data}->[0]= "regnotif version 1.0";
if ($callback) {
$callback->($rsp);
}
return;
}
# must specify the file name and table names
if (@ARGV < 2)
{
&regnotif_usage($callback);
return;
}
#table operations must be a,d or u seperated by ','
if ($tableops)
{
if ($tableops !~ m/^(a|d|u)(,(a|d|u)){0,2}$/) {
my %rsp;
$rsp->{data}->[0]= "Invalid table operations: $tableops";
if ($callback) {
$callback->($rsp);
}
return;
}
}
else
{
$tableops="a,d,u";
}
my $fname=shift(@ARGV);
my $table_names=shift(@ARGV);
my $table=xCAT::Table->new("notification", -create => 1,-autocommit => 0);
if ($table) {
my %key_col = (filename=>$fname);
my %tb_cols=(tables=>$table_names, tableops=>$tableops);
$table->setAttribs(\%key_col, \%tb_cols);
$table->commit;
}
#update notification cache
xCAT::NotifHandler::sendNotifSignal();
return;
}
#--------------------------------------------------------------------------------
=head3 unregNotification
It unregisters a notification routine or a command.
Arguments:
args - the format of the ares is:
[-h|--help|-v|--version] or
filename
where
filename - string. The name of the module or command that handles the notification.
callback - the pointer to the callback funtion.
Returns:
none
=cut
#-------------------------------------------------------------------------------
sub unregNotification {
my $args=shift;
my $callback=shift;
my $VERSION;
my $HELP;
# subroutine to display the usage
sub unregnotif_usage
{
my $callbk=shift;
if (! $callbk) { return;}
my %rsp;
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " unregnotif filename";
$rsp->{data}->[2]= " unregnotif [-h|--help|-v|--version]";
$callbk->($rsp);
}
@ARGV=@{$args};
# parse the options
if(!GetOptions(
'h|help' => \$::HELP,
'v|version' => \$::VERSION,))
{
&unregnotif_usage($callback);
return;
}
# display the usage if -h or --help is specified
if ($::HELP) {
&unregnotif_usage($callback);
return;
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my %rsp;
$rsp->{data}->[0]= "unregnotif version 1.0";
if ($callback) {
$callback->($rsp);
}
return;
}
# must specify the node range
if (@ARGV < 1) {
&unregnotif_usage($callback);
return;
}
my $fname=shift(@ARGV);
my $table=xCAT::Table->new("notification", -create => 1,-autocommit => 0);
if ($table) {
my %key_col = (filename=>$fname);
$table->delEntries(\%key_col);
$table->commit;
}
#update notification cache
xCAT::NotifHandler::sendNotifSignal();
return;
}

View File

@ -0,0 +1,172 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::pxe;
use Data::Dumper;
use Sys::Syslog;
use Socket;
my $request;
my $callback;
my $dhcpconf = "/etc/dhcpd.conf";
my $tftpdir = "/tftpboot";
#my $dhcpver = 3;
my %usage = (
"nodeset" => "Usage: nodeset <noderange> [install|shell|boot|runcmd=bmcsetup]",
);
sub handled_commands {
return {
nodeset => "noderes:netboot"
}
}
sub check_dhcp {
#TODO: omapi magic to do things right
my $node = shift;
my $dhcpfile;
open ($dhcpfile,$dhcpconf);
while (<$dhcpfile>) {
if (/host $node\b/) {
close $dhcpfile;
return 1;
}
}
close $dhcpfile;
return 0;
}
sub getstate {
my $node = shift;
if (check_dhcp($node)) {
if (-r $tftpdir . "/pxelinux.cfg/".$node) {
my $fhand;
open ($fhand,$tftpdir . "/pxelinux.cfg/".$node);
my $headline = <$fhand>;
close $fhand;
$headline =~ s/^#//;
chomp($headline);
return $headline;
} else {
return "boot";
}
} else {
return "discover";
}
}
sub setstate {
=pod
This function will manipulate the pxelinux.cfg structure to match what the noderes/chain tables indicate the node should be booting.
=cut
my $node = shift;
my $restab = xCAT::Table->new('noderes');
my $kern = $restab->getNodeAttribs($node,['kernel','initrd','kcmdline']);
my $pcfg;
open($pcfg,'>',$tftpdir."/pxelinux.cfg/".$node);
my $chaintab = xCAT::Table->new('chain');
my $cref=$chaintab->getNodeAttribs($node,['currstate']);
if ($cref->{currstate}) {
print $pcfg "#".$cref->{currstate}."\n";
}
print $pcfg "DEFAULT xCAT\n";
print $pcfg "LABEL xCAT\n";
my $chaintab = xCAT::Table->new('chain');
my $stref = $chaintab->getNodeAttribs($node,['currstate']);
if ($stref and $stref->{currstate} eq "boot") {
print $pcfg "LOCALBOOT 0\n";
close($pcfg);
} elsif ($kern and $kern->{kernel}) {
#It's time to set pxelinux for this node to boot the kernel..
print $pcfg " KERNEL ".$kern->{kernel}."\n";
if ($kern->{initrd} or $kern->{kcmdline}) {
print $pcfg " APPEND ";
}
if ($kern and $kern->{initrd}) {
print $pcfg "initrd=".$kern->{initrd}." ";
}
if ($kern and $kern->{kcmdline}) {
print $pcfg $kern->{kcmdline}."\n";
} else {
print $pcfg "\n";
}
close($pcfg);
my $inetn = inet_aton($node);
unless ($inetn) {
syslog("local1|err","xCAT unable to resolve IP for $node in pxe plugin");
return;
}
} else { #TODO: actually, should possibly default to xCAT image?
print $pcfg "LOCALBOOT 0\n";
close($pcfg);
}
my $ip = inet_ntoa(inet_aton($node));;
unless ($ip) {
syslog("local1|err","xCAT unable to resolve IP in pxe plugin");
return;
}
my @ipa=split(/\./,$ip);
my $pname = sprintf("%02X%02X%02X%02X",@ipa);
link($tftpdir."/pxelinux.cfg/".$node,$tftpdir."/pxelinux.cfg/".$pname);
}
my $errored = 0;
sub pass_along {
my $resp = shift;
$callback->($resp);
if ($resp and $resp->{errorcode} and $resp->{errorcode}->[0]) {
$errored=1;
}
}
sub process_request {
$request = shift;
$callback = shift;
my $sub_req = shift;
my @args;
my @nodes;
if (ref($request->{node})) {
@nodes = @{$request->{node}};
} else {
if ($request->{node}) { @nodes = ($request->{node}); }
}
unless (@nodes) {
if ($usage{$request->{command}->[0]}) {
$callback->({data=>$usage{$request->{command}->[0]}});
}
return;
}
if (ref($request->{arg})) {
@args=@{$request->{arg}};
} else {
@args=($request->{arg});
}
unless ($args[0] eq 'stat' or $args[0] eq 'enact') {
$sub_req->({command=>['setdestiny'],
node=>\@nodes,
arg=>[$args[0]]},\&pass_along);
}
if ($errored) { return; }
foreach (@nodes) {
my %response;
$response{node}->[0]->{name}->[0]=$_;
if ($args[0] eq 'stat') {
$response{node}->[0]->{data}->[0]= getstate($_);
$callback->(\%response);
} elsif ($args[0] eq 'enact') {
setstate($_);
} elsif ($args[0]) { #If anything else, send it on to the destiny plugin, then setstate
setstate($_);
}
}
}
1;

View File

@ -0,0 +1,199 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::rhel;
use Storable qw(dclone);
use Sys::Syslog;
use xCAT::Table;
use xCAT::Template;
use xCAT::Postage;
use Data::Dumper;
use Getopt::Long;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
use File::Path;
use File::Copy;
my %discids = (
"1170973598.629055" => "rhelc5",
"1170978545.752040" => "rhels5"
);
sub handled_commands {
return {
copycd => "rhel",
mkinstall => "nodetype:os=rh.*"
}
}
sub process_request {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my $distname = undef;
my $arch = undef;
my $path = undef;
if ($request->{command}->[0] eq 'copycd') {
return copycd($request,$callback,$doreq);
} elsif ($request->{command}->[0] eq 'mkinstall') {
return mkinstall($request,$callback,$doreq);
}
}
sub mkinstall {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my @nodes = @{$request->{node}};
my $node;
my $ostab = xCAT::Table->new('nodetype');
my %doneimgs;
foreach $node (@nodes) {
my $osinst;
my $ent = $ostab->getNodeAttribs($node,['profile','os','arch']);
unless ($ent->{os} and $ent->{arch} and $ent->{profile}) {
$callback->({error=>["No profile defined in nodetype for $node"],errorcode=>[1]});
next; #No profile
}
my $os = $ent->{os};
my $arch = $ent->{arch};
my $profile = $ent->{profile};
unless (-r "/usr/share/xcat/install/rh/".$ent->{profile}.".tmpl") {
$callback->({error=>["No kickstart template exists for ".$ent->{profile}],errorcode=>[1]});
next;
}
#Call the Template class to do substitution to produce a kickstart file in the autoinst dir
xCAT::Template->subvars("/usr/share/xcat/install/rh/".$ent->{profile}.".tmpl","/install/autoinst/".$node,$node);
mkpath "/install/postscripts/";
xCAT::Postage->writescript($node,"/install/postscripts/".$node);
if (-r "/install/$os/$arch/images/pxeboot/vmlinuz"
and -r "/install/$os/$arch/images/pxeboot/initrd.img") {
unless ($doneimgs{"$os|$arch"}) {
#TODO: driver slipstream, targetted for network.
mkpath("/tftpboot/xcat/$os/$arch");
copy("/install/$os/$arch/images/pxeboot/vmlinuz","/tftpboot/xcat/$os/$arch/");
copy("/install/$os/$arch/images/pxeboot/initrd.img","/tftpboot/xcat/$os/$arch/");
$doneimgs{"$os|$arch"}=1;
}
#We have a shot...
my $restab = xCAT::Table->new('noderes');
my $ent = $restab->getNodeAttribs($node,['nfsserver','serialport','primarynic','installnic']);
my $hmtab = xCAT::Table->new('nodehm');
my $sent = $hmtab->getNodeAttribs($node,['serialspeed','serialflow']);
unless ($ent and $ent->{nfsserver}) {
$callback->({error=>["No noderes.nfsserver defined for ".$ent->{profile}],errorcode=>[1]});
next;
}
my $kcmdline="nofb utf8 ks=http://".$ent->{nfsserver}."/install/autoinst/".$node;
if ($ent->{installnic}) {
$kcmdline.=" ksdevice=".$ent->{installnic};
} elsif ($ent->{primarynic}) {
$kcmdline.=" ksdevice=".$ent->{primarynic};
} else {
$kcmdline .= " ksdevice=eth0";
}
#TODO: dd=<url> for driver disks
if (defined $ent->{serialport}) {
unless ($sent->{serialspeed}) {
$callback->({error=>["serialport defined, but no serialspeed for $node in nodehm table"],errorcode=>[1]});
next;
}
$kcmdline.=" console=ttyS".$ent->{serialport}.",".$sent->{serialspeed};
if ($sent->{serialflow} =~ /(ctsrts|cts|hard)/) {
$kcmdline .= "n8r";
}
}
$kcmdline .= " noipv6";
$restab->setNodeAttribs($node,{
kernel=>"xcat/$os/$arch/vmlinuz",
initrd=>"xcat/$os/$arch/initrd.img",
kcmdline=>$kcmdline
});
} else {
$callback->({error=>["Install image not found in /install/$os/$arch"],errorcode=>[1]});
}
}
}
sub copycd {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my $installroot;
my $sitetab = xCAT::Table->new('site');
if ($sitetab) {
(my $ref) = $sitetab->getAttribs({key=>installdir},value);
print Dumper($ref);
if ($ref and $ref->{value}) {
$installroot = $ref->{value};
}
}
@ARGV= @{$request->{arg}};
GetOptions(
'n=s' => \$distname,
'a=s' => \$arch,
'p=s' => \$path
);
unless ($path) {
#this plugin needs $path...
return;
}
if ($distname and $distname !~ /^rh/) {
#If they say to call it something other than RH, give up?
return;
}
unless (-r $path."/.discinfo") {
return;
}
my $dinfo;
open($dinfo,$path."/.discinfo");
my $did = <$dinfo>;
chomp($did);
my $desc = <$dinfo>;
chomp($desc);
my $darch = <$dinfo>;
chomp($darch);
if ($darch and $darch =~ /i.86/) {
$darch = "x86";
}
close($dinfo);
if ($desc =~ /^Red Hat Enterprise Linux Client 5$/) {
unless ($distname) {
$distname = "rhelc5";
}
} elsif ($desc =~ /^Red Hat Enterprise Linux Server 5$/) {
unless ($distname) {
$distname = "rhels5";
}
}
print $desc;
unless ($distname) {
return; #Do nothing, not ours..
}
if ($darch) {
unless ($arch) {
$arch = $darch;
}
if ($arch and $arch ne $darch) {
$callback->({error=>"Requested RedHat architecture $arch, but media is $darch"});
return;
}
}
%{$request} = (); #clear request we've got it.
$callback->({data=>"Copying media to $installroot/$distname/$arch/"});
my $omask=umask 0022;
mkpath("$installroot/$distname/$arch");
umask $omask;
my $rc = system("cd $path; find . | cpio -dump $installroot/$distname/$arch");
chmod 0755,"$installroot/$distname/$arch";
if ($rc != 0) {
$callback->({error=>"Media copy operation failed, status $rc"});
} else {
$callback->({data=>"Media copy operation successful"});
}
}
1;

View File

@ -0,0 +1,213 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::sles;
use Storable qw(dclone);
use Sys::Syslog;
use xCAT::Table;
use xCAT::Template;
use xCAT::Postage;
use Data::Dumper;
use Getopt::Long;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
use File::Path;
use File::Copy;
sub handled_commands {
return {
copycd => "sles",
mkinstall => "nodetype:os=sles.*"
}
}
sub process_request {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my $distname = undef;
my $arch = undef;
my $path = undef;
if ($request->{command}->[0] eq 'copycd') {
return copycd($request,$callback,$doreq);
} elsif ($request->{command}->[0] eq 'mkinstall') {
return mkinstall($request,$callback,$doreq);
}
}
sub mkinstall {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my @nodes = @{$request->{node}};
my $node;
my $ostab = xCAT::Table->new('nodetype');
my %doneimgs;
foreach $node (@nodes) {
my $osinst;
my $ent = $ostab->getNodeAttribs($node,['profile','os','arch']);
unless ($ent->{os} and $ent->{arch} and $ent->{profile}) {
$callback->({error=>["No profile defined in nodetype for $node"],errorcode=>[1]});
next; #No profile
}
my $os = $ent->{os};
my $arch = $ent->{arch};
my $profile = $ent->{profile};
unless (-r "/usr/share/xcat/install/sles/".$ent->{profile}.".tmpl") {
$callback->({error=>["No AutoYaST template exists for ".$ent->{profile}],errorcode=>[1]});
next;
}
#Call the Template class to do substitution to produce a kickstart file in the autoinst dir
xCAT::Template->subvars("/usr/share/xcat/install/sles/".$ent->{profile}.".tmpl","/install/autoinst/".$node,$node);
mkpath "/install/postscripts/";
xCAT::Postage->writescript($node,"/install/postscripts/".$node);
if (-r "/install/$os/$arch/1/boot/$arch/loader/linux"
and -r "/install/$os/$arch/1/boot/$arch/loader/initrd") {
#TODO: driver slipstream, targetted for network.
unless ($doneimgs{"$os|$arch"}) {
mkpath("/tftpboot/xcat/$os/$arch");
copy("/install/$os/$arch/1/boot/$arch/loader/linux","/tftpboot/xcat/$os/$arch/");
copy("/install/$os/$arch/1/boot/$arch/loader/initrd","/tftpboot/xcat/$os/$arch/");
$doneimgs{"$os|$arch"}=1;
}
#We have a shot...
my $restab = xCAT::Table->new('noderes');
my $hmtab = xCAT::Table->new('nodehm');
my $ent = $restab->getNodeAttribs($node,['nfsserver','serialport','primarynic','installnic']);
my $sent = $hmtab->getNodeAttribs($node,['serialspeed','serialflow']);
unless ($ent and $ent->{nfsserver}) {
$callback->({error=>["No server for $node defined"],errorcode=>[1]});
next;
}
my $kcmdline="autoyast=http://".$ent->{nfsserver}."/install/autoinst/".$node." install=http://".$ent->{nfsserver}."/install/$os/$arch/1";
if ($ent->{installnic}) {
$kcmdline.=" netdevice=".$ent->{installnic};
} elsif ($ent->{primarynic}) {
$kcmdline.=" netdevice=".$ent->{primarynic};
} else {
$kcmdline .= " netdevice=eth0";
}
#TODO: driver disk handling should in SLES case be a mod of the install source, nothing to see here
if (defined $ent->{serialport}) {
unless ($sent->{serialspeed}) {
$callback->({error=>["serialport defined, but no serialspeed for $node in nodehm table"],errorcode=>[1]});
next;
}
$kcmdline.=" console=ttyS".$ent->{serialport}.",".$sent->{serialspeed};
if ($sent and ($sent->{serialflow} =~ /(ctsrts|cts|hard)/)) {
$kcmdline .= "n8r";
}
}
$restab->setNodeAttribs($node,{
kernel=>"xcat/$os/$arch/linux",
initrd=>"xcat/$os/$arch/initrd",
kcmdline=>$kcmdline
});
}
}
}
sub copycd {
my $request = shift;
my $callback = shift;
my $doreq = shift;
my $installroot;
my $sitetab = xCAT::Table->new('site');
if ($sitetab) {
(my $ref) = $sitetab->getAttribs({key=>installdir},value);
print Dumper($ref);
if ($ref and $ref->{value}) {
$installroot = $ref->{value};
}
}
@ARGV= @{$request->{arg}};
GetOptions(
'n=s' => \$distname,
'a=s' => \$arch,
'p=s' => \$path
);
unless ($path) {
#this plugin needs $path...
return;
}
if ($distname and $distname !~ /^sles/) {
#If they say to call it something other than SLES, give up?
return;
}
unless (-r $path."/content") {
return;
}
my $dinfo;
open($dinfo,$path."/content");
while (<$dinfo>) {
if (m/^DEFAULTBASE\s+(\S+)/) {
$darch = $1;
chomp($darch);
last;
}
}
close($dinfo);
unless ($darch) {
return;
}
my $dirh;
opendir($dirh,$path);
my $discnumber;
my $totaldiscnumber;
while (my $pname = readdir($dirh)) {
if ($pname =~ /media.(\d+)/) {
$discnumber=$1;
chomp($discnumber);
my $mfile;
open($mfile,$path."/".$pname."/media");
<$mfile>;
<$mfile>;
$totaldiscnumber=<$mfile>;
chomp($totaldiscnumber);
close($mfile);
open($mfile,$path."/".$pname."/products");
my $prod = <$mfile>;
close($mfile);
if ($prod =~ m/SUSE-Linux-Enterprise-Server/) {
my @parts = split /\s+/,$prod;
my @subparts = split /-/,$parts[2];
$distname="sles".$subparts[0];
}
}
}
unless ($distname and $discnumber) {
return;
}
if ($darch and $darch =~ /i.86/) {
$darch = "x86";
} elsif ($darch and $darch =~ /ppc/) {
$darch = "ppc64";
}
if ($darch) {
unless ($arch) {
$arch = $darch;
}
if ($arch and $arch ne $darch) {
$callback->({error=>"Requested SLES architecture $arch, but media is $darch"});
return;
}
}
%{$request} = (); #clear request we've got it.
$callback->({data=>"Copying media to $installroot/$distname/$arch/$discnumber"});
my $omask=umask 0022;
mkpath("$installroot/$distname/$arch/$discnumber");
umask $omask;
my $rc = system("cd $path; find . | nice -n 20 cpio -dump $installroot/$distname/$arch/$discnumber/");
chmod 0755,"$installroot/$distname/$arch";
chmod 0755,"$installroot/$distname/$arch/$discnumber";
if ($rc != 0) {
$callback->({error=>"Media copy operation failed, status $rc"});
} else {
$callback->({data=>"Media copy operation successful"});
}
}
1;

View File

@ -0,0 +1,53 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::switch;
use IO::Socket;
use Data::Dumper;
use xCAT::MacMap;
use Sys::Syslog;
use Storable;
my $macmap;
sub handled_commands {
$macmap = xCAT::MacMap->new();
return {
findme => 'switch',
};
}
sub process_request {
my $req = shift;
my $cb = shift;
my $doreq = shift;
my $ip = $req->{'!xcat_clientip'};
my $mac = '';
my $arptable = `/sbin/arp -n`;
my @arpents = split /\n/,$arptable;
foreach (@arpents) {
if (m/^($ip)\s+\S+\s+(\S+)\s/) {
$mac=$2;
last;
}
}
unless ($mac) {
return;
}
my $node = $macmap->find_mac($mac);
if ($node) {
my $mactab = xCAT::Table->new('mac',-create=>1);
$mactab->setNodeAttribs($node,{mac=>$mac});
$mactab->close();
my %request = (
command => ['makedhcp'],
node => [$node]
);
$doreq->(\%request);
$req->{command}=['discovered'];
$req->{noderange} = [$node];
$doreq->($req);
%{$req}=();#Clear req structure, it's done..
undef $mactab;
} else {
#Shouldn't complain, might be blade, but how to log total failures?
}
}
1;

View File

@ -0,0 +1,593 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#####################################################
#
# xCAT plugin package to handle various commands that work with the
# xCAT tables
#
# Supported commands:
# nodeadd
# nodels
# nodech
# tabdump
# tabrestore
# noderm
# To be implemented:
# gettab
# chtab
# tabls
# getnodecfg (?? this doesn't seem much different from gettab)
# nr
# These were xCAT 1.2 commands. Are they still useful in xCAT 1.3?
# addattr
# delattr
# chtype
#
#####################################################
package xCAT_plugin::tabutils;
use xCAT::Table;
use xCAT::Schema;
use Data::Dumper;
use xCAT::NodeRange;
use xCAT::Schema; #noderm will need to build list of tables..
#use Getopt::Long qw(GetOptionsFromArray);
1;
#some quick aliases to table/value
my %shortnames = (
groups => [qw(nodelist groups)],
tags => [qw(nodelist groups)],
mgt => [qw(nodehm mgt)],
switch => [qw(switch switch)],
);
#####################################################
# Return list of commands handled by this plugin
#####################################################
sub handled_commands {
return {
gettab => "tabutils",
tabdump => "tabutils",
tabrestore => "tabutils",
tabch => "tabutils",
nodech => "tabutils",
nodeadd => "tabutils",
noderm => "tabutils",
tabls => "tabutils",
nodels => "tabutils",
getnodecfg => "tabutils",
addattr => "tabutils",
delattr => "tabutils",
chtype => "tabutils",
nr => "tabutils"
}
}
my %usage = (
nodech => "Usage: nodech <noderange> [table.column=value] [table.column=value] ...",
nodeadd => "Usage: nodeadd <noderange> [table.column=value] [table.column=value] ...",
noderm => "Usage: noderm <noderange>",
tabdump => "Usage: tabdump <tablename>\n where <tablename> is one of the following:\n ".join("\n ",keys %xCAT::Schema::tabspec),
tabrestore => "Usage: tabrestore <tablename>.csv",
);
#####################################################
# Process the command
#####################################################
sub gettab {
my $req = shift;
my $callback = shift;
my $keyspec = shift @{$req->{arg}};
my @keypairs = split /,/,$keyspec;
my %keyhash;
foreach (@keypairs) {
(my $key, my $value) = split /=/,$_;
$keyhash{$key}=$value;
}
my %tabhash;
foreach my $tabvalue (@{$req->{arg}}) {
(my $table,my $column) = split /\./,$tabvalue;
$tabhash{$table}->{$column} = 1;
}
foreach my $tabn (keys %tabhash) {
my $tab = xCAT::Table->new($tabn);
(my $ent) = $tab->getAttribs(\%keyhash,keys %{$tabhash{$tabn}});
foreach my $coln (keys %{$tabhash{$tabn}}) {
$callback->({data=>["$tabn.$coln:".$ent->{$coln}]});
}
$tab->close;
}
}
sub process_request {
use Getopt::Long;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
my $request = shift;
my $callback = shift;
my $nodes = $request->{node};
my $command = $request->{command}->[0];
my $args = $request->{arg};
unless ($args or $nodes or $request->{data}) {
if ($usage{$command}) {
$callback->({data=>[$usage{$command}]});
return;
}
}
if ($command eq "nodels") {
return nodels($nodes,$args,$callback,$request->{noderange}->[0]);
} elsif ($command eq "noderm" or $command eq "rmnode") {
return noderm($nodes,$args,$callback);
} elsif ($command eq "nodeadd" or $command eq "addnode") {
return chnode($nodes,$args,$callback,1);
} elsif ($command eq "nodech" or $command eq "chnode") {
return chnode($nodes,$args,$callback,0);
} elsif ($command eq "tabrestore") {
return tabrestore($request,$callback);
} elsif ($command eq "tabdump") {
return tabdump($args,$callback);
} elsif ($command eq "gettab") {
return gettab($request,$callback);
} else {
print "$command not implemented yet\n";
return (1,"$command not written yet");
}
}
sub noderm {
my $nodes = shift;
my $args = shift;
my $cb = shift;
my @tablist = ("-d");
foreach (keys %{xCAT::Schema::tabspec}) {
if (grep /^node$/,@{$xCAT::Schema::tabspec{$_}->{cols}}) {
push @tablist,$_;
}
}
chnode($nodes,\@tablist,$cb,0);
}
sub tabrestore {
#request->{data} is an array of CSV formatted lines
my $request = shift;
my $cb = shift;
my $table = $request->{table}->[0];
my $linenumber = 1;
my $tab = xCAT::Table->new($table,-create =>1,-autocommit=>0);
unless ($tab) {
$cb->({error=>"Unable to open $table"});
return;
}
$tab->delEntries(); #Yes, delete *all* entries
my $header = shift @{$request->{data}};
$header =~ s/"//g; #Strip " from overzealous CSV apps
$header =~ s/^#//;
$header =~ s/\s+$//;
my @colns = split(/,/,$header);
my $line;
my $rollback=0;
LINE: foreach $line (@{$request->{data}}) {
$linenumber++;
$line =~ s/\s+$//;
my $origline = $line; #save for error reporting
my %record;
my $col;
foreach $col (@colns) {
if ($line =~ /^,/ or $line eq "") { #Match empty, or end of line that is empty
#TODO: should we detect when there weren't enough CSV fields on a line to match colums?
$record{$col}=undef;
$line =~ s/^,//;
} elsif ($line =~ /^[^,]*"/) { # We have stuff in quotes... pain...
#I don't know what I'm doing, so I'll do it a hard way....
if ($line !~ /^"/) {
$rollback = 1;
$cb->({error=>"CSV missing opening \" for record with \" characters on line $linenumber, character ".index($origline,$line).": $origline"});
next LINE;
}
my $offset=1;
my $nextchar;
my $ent = "";
while (not $ent) {
$offset = index($line,'"',$offset);
$offset++;
if ($offset <=0) {
#MALFORMED CSV, request rollback, report an error
$rollback=1;
$cb->({error=>"CSV unmatched \" in record on line $linenumber, character ".index($origline,$line).": $origline"});
next LINE;
}
$nextchar = substr($line,$offset,1);
if ($nextchar eq '"') {
$offset++;
} elsif ($offset eq length($line) or $nextchar eq ',') {
$ent = substr($line,0,$offset,'');
$line =~ s/^,//;
chop $ent;
$ent = substr($ent,1);
$ent =~ s/""/"/g;
$record{$col}=$ent;
} else {
$cb->({error=>"CSV unescaped \" in record on line $linenumber, character ".index($origline,$line).": $origline"});
$rollback=1;
next LINE;
}
}
} elsif ($line =~ /^([^,]+)/) { #easiest case, no Text::Balanced needed..
$record{$col} = $1;
$line =~ s/^([^,]+)(,|$)//;
}
}
if ($line) {
$rollback = 1;
$cb->({error=>"Too many fields on line $linenumber: $origline | $line"});
next LINE;
}
#TODO: check for error from DB and rollback
my @rc =$tab->setAttribs(\%record,\%record);
if (not defined($rc[0])) {
$rollback = 1;
$cb->({error=>"DB error ".$rc[1]. " with line $linenumber: ".$origline});
}
}
if ($rollback) {
$tab->rollback();
$tab->close;
undef $tab;
return;
} else {
$tab->commit; #Made it all the way here, commit
}
}
sub tabdump {
#TODO: need to return header for not-yet existing, but schemad tabs
#TODO: schema defined column order.
my $args = shift;
my $cb = shift;
my $table="";
foreach (@$args) {
unless (/^-/) {
if ($table) {
return 1; #TODO: Error, usage
}
$table=$_;
}
}
my $tabh = xCAT::Table->new($table);
my %rsp;
unless ($tabh) {
if (defined($xCAT::Schema::tabspec{$table})) {
my $header = join ",",@{$xCAT::Schema::tabspec{$table}->{cols}};
$header="#".$header;
push @{$rsp{data}},$header;
$cb->(\%rsp);
return;
}
$cb->({error=>"No such table: $table"});
return 1;
}
my $recs=$tabh->getAllEntries();
my $rec;
my $firstline = 1;
unless (@$recs) {
if (defined($xCAT::Schema::tabspec{$table})) {
my $header = join ",",@{$xCAT::Schema::tabspec{$table}->{cols}};
$header="#".$header;
push @{$rsp{data}},$header;
$cb->(\%rsp);
return;
}
}
foreach $rec (@$recs) {
my $line ='';
if ($firstline) {
$firstline = 0;
$line = join ",",@{$tabh->{colnames}};
$line = "#".$line;
push @{$rsp{data}},$line;
$line = '';
}
foreach (@{$tabh->{colnames}}) {
$rec->{$_} =~ s/"/""/g;
if (defined $rec->{$_}) {
$line = $line . '"' . $rec->{$_} . '",';
} else {
$line .= ',';
}
}
$line =~ s/,$//;
$line = $line . $lineappend;
push @{$rsp{data}},$line;
}
$cb->(\%rsp);
}
sub chnode {
my $nodes=shift;
my $args=shift;
my $callback=shift;
my $addmode=shift;
print $addmode;
if ($addmode) {
my $idx=0;
foreach my $arg (@$args) {
unless ($arg =~ /^-/) {
$nodes = [noderange($arg,0)];
splice(@$args,$idx,1);
last;
}
$idx++;
}
unless ($nodes) {
$callback->({error=>"No range to add detected\n"});
return;
}
}
my $column;
my $value;
my $temp;
my %tables;
my $tab;
my $deletemode;
#No GetOptionsFromArray...
#GetOptionsFromArray($args,"d|delete" => \$deletemode);
#print Dumper($deletemode);
foreach (@$args) {
if (m/^-/) { #A quick and dirty option parser in lieu of lacking Getoptinos
if (m/^--/) {
if (m/--delete/) {
$deletemode=1;
next;
} else {
$callback->({data=>["ERROR: Malformed argument $_ ignored"]});
next;
}
} else {
if (m/^-d$/) {
$deletemode=1;
next;
} else {
$callback->({data=>["ERROR: Malformed argument $_ ignored"]});
next;
}
}
}
if ($deletemode) {
if (m/[=\.]/) {
$callback->({data=>["ERROR: . and = not valid in delete mode"]});
next;
}
$tables{$_} = 1;
next;
}
unless (m/=/) {
$callback->({data=>["ERROR: Malformed argument $_ ignored"]});
next;
}
($temp,$value)=split('=',$_,2);
my $op='=';
if ($temp =~ /,$/) {
$op=',=';
chop($temp);
} elsif ($temp =~ /\^$/) {
$op='^=';
chop($temp);
}
if ($shortnames{$temp}) {
($table,$column) = @{$shortnames{$temp}};
} else {
($table,$column) = split('\.',$temp,2);
}
$tables{$table}->{$column}=[$value,$op];
}
foreach $tab (keys %tables) {
my $tabhdl = xCAT::Table->new($tab,-create => 1,-autocommit => 0);
if ($tabhdl) {
foreach (@$nodes) {
if ($deletemode) {
$tabhdl->delEntries({'node'=>$_});
} else {
#$tabhdl->setNodeAttribs($_,$tables{$tab});
my %uhsh;
my $node = $_;
foreach (keys %{$tables{$tab}}) {
my $op = $tables{$tab}->{$_}->[1];
my $val = $tables{$tab}->{$_}->[0];
my $key = $_;
if ($op eq '=') {
$uhsh{$key}=$val;
} elsif ($op eq ',=') { #splice assignment
my $cent = $tabhdl->getNodeAttribs($node,[$key]);
my $curval;
if ($cent) { $curval = $cent->{$key}; }
if ($curval) {
my @vals = split(/,/,$curval);
unless (grep /^$val$/,@vals) {
@vals=(@vals,$val);
my $newval = join(',',@vals);
$uhsh{$key}=$newval;
}
} else {
$uhsh{$key}=$val;
}
} elsif ($op eq '^=') {
my $cent = $tabhdl->getNodeAttribs($node,[$key]);
my $curval;
if ($cent) { $curval = $cent->{$key}; }
if ($curval) {
my @vals = split(/,/,$curval);
if (grep /^$val$/,@vals) { #only bother if there
@vals = grep(!/^$val$/,@vals);
my $newval = join(',',@vals);
$uhsh{$key}=$newval;
}
} #else, what they asked for is the case alredy
}
}
if (keys %uhsh) {
$tabhdl->setNodeAttribs($node,\%uhsh);
}
}
}
$tabhdl->commit;
} else {
$callback->({data=>["ERROR: Unable to open table $tab in configuration"]});
}
}
}
#####################################################
# nodels command
#####################################################
sub nodels {
my $nodes=shift;
my $args=shift;
my $callback=shift;
my $noderange=shift;
my $VERSION;
my $HELP;
sub nodels_usage {
my %rsp;
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " nodels [-?|-h|--help] ";
$rsp->{data}->[2]= " nodels [-v|--version] ";
$rsp->{data}->[3]= " nodels [noderange] ";
##### xcat 1.2 nodels usage:
# $rsp->{data}->[1]= " nodels [noderange] [group|pos|type|rg|install|hm|all]";
# $rsp->{data}->[2]= " ";
# $rsp->{data}->[3]= " nodels [noderange] hm.{power|reset|cad|vitals|inv|cons}";
# $rsp->{data}->[4]= " hm.{bioscons|eventlogs|getmacs|netboot}";
# $rsp->{data}->[5]= " hm.{eth0|gcons|serialbios|beacon}";
# $rsp->{data}->[6]= " hm.{bootseq|serialbps|all}";
# $rsp->{data}->[7]= " ";
# $rsp->{data}->[8]= " nodels [noderange] rg.{tftp|nfs_install|install_dir|serial}";
# $rsp->{data}->[9]= " rg.{usenis|install_roll|acct|gm|pbs}";
# $rsp->{data}->[10]=" rg.{access|gpfs|netdevice|prinic|all}";
$callback->($rsp);
}
@ARGV=@{$args};
if ( !GetOptions(
'h|?|help' => \$HELP,
'v|version' => \$VERSION,
) ) {
&nodels_usage;
}
# Help
if ($HELP) {
&nodels_usage;
return;
}
# Version
if ($VERSION) {
my %rsp;
$rsp->{data}->[0]= "1.3";
$callback->($rsp);
return;
}
# TODO -- Parse command arguments
# my $opt;
# my %attrs;
# foreach $opt (@ARGV) {
# if ($opt =~ /^group/) {
# }
# }
my $argc = @ARGV;
if (@$nodes > 0 or $noderange) { #Make sure that there are zero nodes *and* that a noderange wasn't requested
# TODO - gather data for each node
# for now just return the flattened list of nodes)
my %rsp; #build up fewer requests, be less chatty
if ($argc) {
my %tables;
foreach (@ARGV) {
my $table;
my $column;
my $temp=$_;
if ($shortnames{$temp}) {
($table,$column) = @{$shortnames{$temp}};
} else {
($table,$column) = split('\.',$temp,2);
}
unless (grep /^$column$/,@{$tables{$table}}) {
push @{$tables{$table}},[$column,$temp]; #Mark this as something to get
}
}
my $tab;
my %noderecs;
foreach $tab (keys %tables) {
my $tabh = xCAT::Table->new($tab);
unless ($tabh) { next; }
#print Dumper($tables{$tab});
my $node;
foreach $node (@$nodes) {
my @cols;
my %labels;
foreach (@{$tables{$tab}}) {
push @cols,$_->[0];
$labels{$_->[0]}=$_->[1];
}
my $rec=$tabh->getNodeAttribs($node,\@cols);
foreach (keys %$rec) {
my %datseg;
$datseg{data}->[0]->{desc} = [$labels{$_}];
$datseg{data}->[0]->{contents} = [$rec->{$_}];
$datseg{name} = [$node]; #{}->{contents} = [$rec->{$_}];
push @{$noderecs{$node}},\%datseg;
}
}
#$rsp->{node}->[0]->{data}->[0]->{desc}->[0] = $_;
#$rsp->{node}->[0]->{data}->[0]->{contents}->[0] = $_;
$tabh->close();
undef $tabh;
}
foreach (sort (keys %noderecs)) {
push @{$rsp->{"node"}},@{$noderecs{$_}};
}
} else {
foreach (@$nodes) {
my $noderec;
$noderec->{name}->[0]=($_);
push @{$rsp->{node}},$noderec;
}
}
$callback->($rsp);
} else {
# no noderange specified on command line, return list of all nodes
my $nodelisttab;
if ($nodelisttab=xCAT::Table->new("nodelist")) {
my @attribs=("node");
my @ents=$nodelisttab->getAllAttribs(@attribs);
foreach (@ents) {
my %rsp;
if ($_->{node}) {
$rsp->{node}->[0]->{name}->[0]=($_->{node});
# $rsp->{node}->[0]->{data}->[0]->{contents}->[0]="$_->{node} node contents";
# $rsp->{node}->[0]->{data}->[0]->{desc}->[0]="$_->{node} node desc";
$callback->($rsp);
}
}
}
}
return 0;
}

View File

@ -0,0 +1,162 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------
=head1
xCAT plugin package to handle xdsh
Supported command:
xdsh-> dsh
xdcp-> dcp
=cut
#-------------------------------------------------------
package xCAT_plugin::xdsh;
use xCAT::Table;
use xCAT::Utils;
use xCAT::MsgUtils;
1;
#-------------------------------------------------------
=head3 handled_commands
Return list of commands handled by this plugin
=cut
#-------------------------------------------------------
sub handled_commands
{
return {
xdsh => "xdsh",
xdcp => "xdsh"
};
}
#-------------------------------------------------------
=head3 process_request
Process the command
=cut
#-------------------------------------------------------
sub process_request
{
my $request = shift;
my $callback = shift;
my $nodes = $request->{node};
my $command = $request->{command}->[0];
my $args = $request->{arg};
my %rsp;
$::DSH = "/opt/csm/bin/dsh";
$::DCP = "/opt/csm/bin/dcp";
# check that dsh is installed
if (!-e $::DSH)
{
$rsp->{data}->[0] =
"dsh is not installed. Cannot process the command\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
else
{
if (($command eq "xdsh") || ($command eq "xdcp"))
{
return
xdsh($nodes, $args, $callback, $command,
$request->{noderange}->[0]);
}
else
{ # error
$rsp->{data}->[0] =
"Unknown command $command. Cannot process the command\n";
xCAT::MsgUtils->message("E", $rsp, $callback);
}
}
}
#-------------------------------------------------------
=head3 xdsh
Builds and runs the dsh or dcp command
=cut
#-------------------------------------------------------
sub xdsh
{
my $nodes = shift;
my $args = shift;
my $callback = shift;
my $command = shift;
my $noderange = shift;
#
# set XCAT Context
#
$ENV{DSH_CONTEXT} = "XCAT";
#
# if nodes, Put nodes in a file so we do
# not risk hitting a command line
# limit
my $node_file;
if ($nodes)
{
$node_file = xCAT::Utils->make_node_list_file($nodes);
$ENV{'DSH_LIST'} = $node_file; # export the file for dsh
}
#
# call dsh or dcp
#
my $dsh_dcp_command = "";
my %rsp;
if ($command eq "xdsh")
{
$dsh_dcp_command = $::DSH;
}
else
{
$dsh_dcp_command = $::DCP;
}
$dsh_dcp_command .= " ";
foreach my $arg (@$args)
{ # add arguments
$dsh_dcp_command .= $arg; # last argument must be command to run
$dsh_dcp_command .= " ";
}
$dsh_dcp_command .= "2>&1";
my @local_results = `$dsh_dcp_command`; # run the dsh command
my $rc = $? >> 8;
my $i = 0;
chop @local_results;
foreach my $line (@local_results)
{
$rsp->{data}->[$i] = $line;
$i++;
}
#$rsp->{data}->[$i] = "Return Code = $rc\n";
xCAT::Utils->close_delete_file($::NODE_LIST_FILE, $node_file);
xCAT::MsgUtils->message("I", $rsp, $callback);
#xCAT::MsgUtils->message("I", $rsp);
#$callback->($rsp);
return 0;
}

View File

@ -0,0 +1,97 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
export LOCKDIR=/var/lock/xcat
function needhelp
{
if [ "$#" = "1" ]
then
for i in $*
do
test "$i" = "--help" && echo "\nhttp://xcat.org for support." && return 0
test "$i" = "-h" && echo "http://xcat.org for support.\n" && return 0
test "$i" = "--version" && echo "$VERSION" && exit 0
test "$i" = "-v" && echo "$VERSION" && exit 0
done
fi
return 1
}
function getlock
{
LOCK=$1
TIMEOUT=$2
let t=0
mkdir -p $LOCKDIR
if [ -r $LOCKDIR/$LOCK.pid ]
then
PID=$(cat $LOCKDIR/$LOCK.pid)
while ps -p $PID >/dev/null 2>&1
do
sleep 1
let t=t+1
if (($t -gt $TIMEOUT))
then
return 1
fi
done
fi
echo "$$" > $LOCKDIR/$LOCK.pid
return 0
}
function lockstatus
{
LOCK=$1
if [ -r $LOCKDIR/$LOCK.pid ]
then
PID=$(cat $LOCKDIR/$LOCK.pid)
if ps -p $PID >/dev/null 2>&1
then
echo "locked by PID $PID"
ps -fp $PID | tail -1
else
echo "stale lock PID $PID, remove $LOCKDIR/$LOCK.pid"
fi
return 0
fi
echo "nolock"
return 0
}
function freelock
{
LOCK=$1
FORCE=$2
mkdir -p $LOCKDIR
if [ "$FORCE" = "1" ]
then
rm -f $LOCKDIR/$LOCK.pid >/dev/null 2>&1
return 0
fi
if [ -r $LOCKDIR/$LOCK.pid ]
then
PID=$(cat $LOCKDIR/$LOCK.pid)
if [ "$PID" = "$$" ]
then
rm -f $LOCKDIR/$LOCK.pid
else
return 1
fi
fi
return 0
}

100
xCAT-server-2.0/usr/sbin/chtab Executable file
View File

@ -0,0 +1,100 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use xCAT::Table;
use xCAT::NodeRange;
use Getopt::Long;
use strict;
#This or something like this must always be available and not depend on server
#Otherwise, can't set things to let server run in the first place
sub usage {
print "Usage:\n";
print " To add or update rows for tables:
chtab keycolname=keyvalue[,keycolname=keyvalue...] [tablename.colname=newvalue] [tablename.colname=newvalue]...\n";
print " To delete rows from tables:
chtab -d|--delete keycolname=keyvalue[,keycolname=keyvalue...] tablename [tablename]...\n";
print " To display usage and other information:
chtab [-h|--help|-v|--Version]\n\n";
print " -d|--delete Delete the rows from a list of tables.
-v|--version Display the version of this command.
-h|--help Display this usage information.
keycolname=keyvalue a column name-and-value pair that identifies the rows in a table to be changed.
tablename.colname=newvalue the new value for the specified row and column of the table.\n";
}
my %tables;
# options can be bundled up like -vV
Getopt::Long::Configure("bundling") ;
$Getopt::Long::ignorecase=0;
# parse the options
if(!GetOptions(
'd|delete' => \$::DELETE,
'h|help' => \$::HELP,
'v|version' => \$::VERSION,))
{
&usage;
exit(1);
}
# display the usage if -h or --help is specified
if ($::HELP) { &usage; exit(0);}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
print "chtab version 1.0\n";
exit(0);
}
my $target = shift @ARGV;
unless ($target) {
usage;
exit(1);
}
my %keyhash;
my @keypairs=split(/,/,$target);
foreach (@keypairs) {
m/(.*)=(.*)/;
my $key=$1;
my $val=$2;
$keyhash{$key}=$val;
}
if ($::DELETE) {
#delete option is specified
my @tables_to_del=@ARGV;
for (@tables_to_del) {
$tables{$_} = xCAT::Table->new($_,-create => 1,-autocommit => 0);
$tables{$_}->delEntries(\%keyhash);
$tables{$_}->commit;
}
}
else {
#update or create option
my %tableupdates;
for (@ARGV) {
my $temp;
my $table;
my $column;
my $value;
($table,$temp) = split('\.',$_,2);
($column,$value) = split("=",$temp,2);
unless ($tables{$table}) {
$tables{$table} = xCAT::Table->new($table,-create => 1,-autocommit => 0);
}
$tableupdates{$table}{$column}=$value;
}
#commit all the changes
foreach (keys %tables) {
if (exists($tableupdates{$_})) {
$tables{$_}->setAttribs(\%keyhash,\%{$tableupdates{$_}});
}
$tables{$_}->commit;
}
}

57
xCAT-server-2.0/usr/sbin/mknb Executable file
View File

@ -0,0 +1,57 @@
#!/bin/bash
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
if [ $# -ne 1 ]; then
echo "Usage: mknb <arch>"
exit 1
fi
if [ ! -d /usr/share/xcat/netboot/$1 ]; then
echo "Unsupported architecture: $1"
exit 1
fi
if [ ! -r ~/.ssh/id_rsa.pub ]; then
#echo "Need to generate ssh keys"
ssh-keygen -t rsa -q -b 2048 -N "" -f ~/.ssh/id_rsa
#exit 1
fi
mkdir -p /tmp/mknb.$$
cp -a /usr/share/xcat/netboot/$1/nbroot/* /tmp/mknb.$$/
mkdir -p /tmp/mknb.$$/root/.ssh
cp ~/.ssh/id_rsa.pub /tmp/mknb.$$/root/.ssh/authorized_keys
if [ -f /install/postscripts/hostkeys/ssh_host_key ]; then
cp /install/postscripts/hostkeys/ssh_host_key /tmp/mknb.$$/etc/ssh_host_key
cp /install/postscripts/hostkeys/ssh_host_rsa_key /tmp/mknb.$$/etc/ssh_host_rsa_key
cp /install/postscripts/hostkeys/ssh_host_dsa_key /tmp/mknb.$$/etc/ssh_host_dsa_key
fi
if [ ! -f /tmp/mknb.$$/etc/ssh_host_key ]; then
echo Generating SSH1 RSA Key...
/usr/bin/ssh-keygen -t rsa1 -f /tmp/mknb.$$/etc/ssh_host_key -C '' -N ''
echo Generating SSH2 RSA Key...
/usr/bin/ssh-keygen -t rsa -f /tmp/mknb.$$/etc/ssh_host_rsa_key -C '' -N ''
echo Generating SSH2 DSA Key...
/usr/bin/ssh-keygen -t dsa -f /tmp/mknb.$$/etc/ssh_host_dsa_key -C '' -N ''
fi
cd /tmp/mknb.$$
echo "Packing nbfs.$1.gz"
find . | cpio -o -H newc | gzip -9 > /tftpboot/xcat/nbfs.$1.gz
cd -
rm -rf /tmp/mknb.$$
if [ "$1" = "x86_64" -a ! -f /tftpboot/pxelinux.0 -a -f /usr/lib/syslinux/pxelinux.0 ]; then
cp /usr/lib/syslinux/pxelinux.0 /tftpboot/pxelinux.0
fi
if [ "$1" = "x86_64" -a ! -f /tftpboot/pxelinux.cfg/default ]; then
mkdir -p /tftpboot/pxelinux.cfg
echo "default xCAT
LABEL xCAT
KERNEL xcat/nbk.x86_64
APPEND initrd=xcat/nbfs.x86_64.gz xcatd="`gettab key=master site.value|awk -F: '{print $2}'`:`gettab key=xcatdport site.value|awk -F: '{print $2}'` > /tftpboot/pxelinux.cfg/default
fi
if [ "$1" = "ppc64" -a ! -f /tftpboot/etc/yaboot.conf ]; then
mkdir -p /tftpboot/etc
echo "timeout=5
label=xcat
image=xcat/nbk.ppc64
initrd=xcat/nbfs.ppc64.gz
append=\"xcatd="`gettab key=master site.value|awk -F: '{print $2}'`:`gettab key=xcatdport site.value|awk -F: '{print $2}'`\"> /tftpboot/etc/yaboot.conf
fi

685
xCAT-server-2.0/usr/sbin/xcatd Executable file
View File

@ -0,0 +1,685 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use Socket;
use IO::Socket;
use IO::Handle;
use IO::Select;
use IO::Socket::SSL;
use IO::Socket::INET;
use XML::Simple;
use xCAT::Table;
use Data::Dumper;
use Getopt::Long;
use Sys::Syslog;
use xCAT::NotifHandler;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
use Storable qw(dclone);
use POSIX qw(WNOHANG setsid);
use strict;
my $pidfile;
GetOptions(
'pidfile|p=s' => \$pidfile
);
my $plugins_dir='/usr/lib/xcat/plugins';
my $quit = 0;
my $port;
my $sport;
my $domain;
my $xcatdir;
my $sitetab=xCAT::Table->new('site');
unless ($sitetab) {
print ("ERROR: Unable to open basic site table for configuration\n");
}
my ($tmp) = $sitetab->getAttribs({'key'=>'xcatdport'},'value');
unless ($tmp) {
die "ERROR:Need xcatdport defined in site table, try chtab key=xcatdport site.value=3001";
}
$port = $tmp->{value};
$sport = $tmp->{value}+1;
($tmp) = $sitetab->getAttribs({'key'=>'xcatconfdir'},'value');
$xcatdir = ($tmp ? $tmp->{value} : "/etc/xcat");
my $progname;
$SIG{PIPE} = sub { die "SIGPIPE $$progname encountered a broken pipe (probably Ctrl-C by client)" };
sub daemonize {
chdir('/');
umask 0;
my $pid;
defined($pid = fork) or die "Can't fork: $!";
if ($pid) {
if ($pidfile) {
open(PFILE, '>', $pidfile);
print PFILE $pid;
close (PFILE);
} else {
printf ("xCATd starting as PID $pid \n");
}
exit;
}
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>/dev/null';
open STDERR, '>/dev/null';
$0='xcatd';
$progname = \$0;
setsid or die "Can't start new session";
}
my %cmd_handlers;
sub do_installm_service {
#This function servers as a handler for messages from installing nodes
my $socket = IO::Socket::INET->new(LocalPort=>$sport,
Proto => 'tcp',
ReuseAddr => 1,
Listen => 64);
unless ($socket) {
syslog("local1|err","xcatd unable to open install monitor services on $sport");
die;
}
until ($quit) {
$SIG{ALRM} = sub { die "XCATTIMEOUT"; };
my $conn;
next unless $conn = $socket->accept;
my $client = gethostbyaddr(inet_aton($conn->peerhost),AF_INET);
$client =~ s/\..*//;
my $node;
($node) = noderange($client); #ensure this is coming from a node IP at least
unless ($node) { #Means the source isn't a valid deal...
close($conn);
next;
}
eval {
alarm(2);
print $conn "ready\n";
while (my $text = <$conn>) {
alarm(0);
print $conn "done\n";
$text =~ s/\r//g;
if ($text =~ /next/) {
my %request = (
command => [ 'nodeset' ],
node => [ $node ],
arg => [ 'next' ],
);
close($conn);
my $pid=fork();
unless ($pid) { #fork off the nodeset and potential slowness
plugin_command(\%request,undef,\&convey_response);
exit(0);
}
}
alarm(2);
}
alarm(0);
};
if ($@) {
if ($@ =~ /XCATTIMEOUT/) {
syslog("local1|err","xcatd installmonitor timed out talking to $node");
} else {
syslog("local1|err","xcatd: possible BUG encountered by xCAT install monitor service: ".$@);
}
}
}
}
sub do_udp_service { #This function opens up a UDP port
#It will do similar to the standard service, except:
#-Obviously, unencrypted and messages are not guaranteed
#-For that reason, more often than not plugins designed with
#-this method will not expect to have a callback
#Also, this throttles to handle one message at a time, so no forking either
#Explicitly, to handle whatever operations nodes periodically send during discover state
#Could be used for heartbeating and such as desired
my $socket = IO::Socket::INET->new(LocalPort => $port,
Proto => 'udp');
openlog("xCAT UDP",'','local1');
unless ($socket) {
syslog("err","xCAT UDP service unable to open port $port: $!");
closelog();
die "Unable to start UDP on $port";
}
my $data;
my $part;
my $sport;
my $client;
my $peerhost;
until ($quit) {
eval { while ($part = $socket->recv($data,1500)) {
($sport,$client) = sockaddr_in($part);
$peerhost=gethostbyaddr($client,AF_INET)."\n";
my $req = eval { XMLin($data, SuppressEmpty=>undef,ForceArray=>1) };
if ($req and $req->{command} and ($req->{command}->[0] eq "findme")) {
$req->{'!xcat_clienthost'}=gethostbyaddr($client,AF_INET)."\n";
$req->{'!xcat_clientip'}=inet_ntoa($client);
$req->{'!xcat_clientport'}=$sport;
if (defined($cmd_handlers{"findme"})) {
plugin_command($req,undef,\&convey_response);
}
}
if ($quit) { last; }
}
};
if ($@) {
syslog("local1|err","xcatd: possible BUG encountered by xCAT UDP service: ".$@);
}
}
}
sub scan_plugins {
my @plugins=glob($plugins_dir."/*.pm");
foreach (@plugins) {
/.*\/([^\/]*).pm$/;
my $modname = $1;
require "$_";
no strict 'refs';
my $cmd_adds=${"xCAT_plugin::".$modname."::"}{handled_commands}->();
foreach (keys %$cmd_adds) {
my $value = $_;
if (defined($cmd_handlers{$_})) {
my $add=1;
#This next bit of code iterates through the handlers.
#If the value doesn't contain an equal, and has an equivalent entry added by
# another plugin already, don't add (otherwise would hit the DB multiple times)
# a better idea, restructure the cmd_handlers as a multi-level hash
# prove out this idea real quick before doing that
foreach (@{$cmd_handlers{$_}}) {
if (($_->[1] eq $cmd_adds->{$value}) and (($cmd_adds->{$value} !~ /=/) or ($_->[0] eq $modname))) {
$add = 0;
}
}
if ($add) { push @{$cmd_handlers{$_}},[$modname,$cmd_adds->{$_}]; }
#die "Conflicting handler information from $modname";
} else {
$cmd_handlers{$_} = [ [$modname,$cmd_adds->{$_}] ];
}
}
}
}
scan_plugins;
daemonize;
$SIG{CHLD} = sub { while (waitpid(-1,WNOHANG) > 0) {} };
$SIG{TERM} = $SIG{INT} = sub { printf("Asked to quit...\n"); $quit++ };
my $pid = fork;
defined $pid or die "Unable to fork for UDP/TCP";
unless ($pid) {
$$progname="xcatd: UDP listener";
do_udp_service;
exit(0);
}
$pid = fork;
defined $pid or die "Unable to fork installmonitor";
unless ($pid) {
$$progname="xcatd: install monitor";
do_installm_service;
exit(0);
}
$$progname="xcatd: SSL listener";
openlog("xCAT SSL","","local1");
my $listener = IO::Socket::SSL->new(
LocalPort => $port,
Listen => 64,
Reuse => 1,
SSL_key_file=>$xcatdir."/cert/server-key.pem",
SSL_cert_file=>$xcatdir."/cert/server-cert.pem",
SSL_ca_file=>$xcatdir."/cert/ca.pem",
SSL_verify_mode=> 1
);
unless ($listener) {
kill $pid;
syslog("err","xCAT service unable to open SSL services on $port: $!");
closelog();
die "ERROR:Unable to start xCAT service on port $port.";
}
closelog();
#setup signal in NotifHandler so that the cache can be updated
xCAT::NotifHandler::setup($$);
my $peername;
until ($quit) {
next unless my $connection=$listener->accept;
my $child = fork(); #Yes we fork, IO::Socket::SSL is not threadsafe..
unless (defined $child) {
die "xCATd cannot fork";
}
if ($child == 0) {
$listener->close;
my $peerhost=undef;
my $peer=$connection->peer_certificate("owner");
if ($peer) {
$peer =~ m/CN=([^\/]*)/;
$peername = $1;
} else {
$peername=undef;
}
my ($tmp) = $sitetab->getAttribs({'key'=>'domain'},'value');
if (defined $tmp->{value}) {
$domain = $tmp->{value};
}
$peerhost = gethostbyaddr(inet_aton($connection->peerhost),AF_INET);
$peerhost =~ s/\.$domain\.*$//;
$peerhost =~ s/-eth\d*$//;
$peerhost =~ s/-myri\d*$//;
$peerhost =~ s/-ib\d*$//;
#printf('info'.": xcatd: connection from ".($peername ? $peername . "@" . $peerhost : $peerhost)."\n");
$$progname="xCATd SSL: Instance for ".($peername ? $peername ."@".$peerhost : $peerhost);
service_connection($connection,$peername,$peerhost);
exit(0);
}
$connection->close(SSL_no_shutdown => 1); #Without no shutdown, you can guess what the client ends up thinking..
}
$listener->close;
my $parent_fd;
my %resps;
sub plugin_command {
my $req = shift;
my $sock = shift;
my $callback = shift;
my %handler_hash;
use xCAT::NodeRange;
$Main::resps={};
my @nodes;
if ($req->{node}) {
@nodes = @{$req->{node}};
} elsif ($req->{noderange}) {
@nodes = noderange($req->{noderange}->[0]);
if (nodesmissed) {
my $rsp = {errorcode=>1,error=>"Invalid nodes in noderange:".join(',',nodesmissed)};
if ($sock) {
print $sock XMLout($rsp,RootName=>'xcatresponse' ,NoAttr=>1);
}
return ($rsp);
}
}
if (@nodes) { $req->{node} = \@nodes; }
if (defined($cmd_handlers{$req->{command}->[0]})) {
my $hdlspec;
foreach (@{$cmd_handlers{$req->{command}->[0]}}) {
$hdlspec =$_->[1];
my $ownmod = $_->[0];
if ($hdlspec =~ /:/) { #Specificed a table lookup path for plugin name
my $table;
my $cols;
($table,$cols) = split(/:/,$hdlspec);
my @colmns=split(/,/,$cols);
my @columns;
my $hdlrtable=xCAT::Table->new($table);
unless ($hdlrtable) {
#TODO: proper error handling
}
my $node;
my $colvals = {};
foreach my $colu (@colmns) {
if ($colu =~ /=/) { #a value redirect to a pattern/specific name
my $coln; my $colv;
($coln,$colv) = split(/=/,$colu,2);
$colvals->{$coln} = $colv;
push (@columns,$coln);
} else {
push (@columns,$colu);
}
}
unless (@nodes) { #register the plugin in the event of usage
$handler_hash{$ownmod} = 1;
}
foreach $node (@nodes) {
my $attribs = $hdlrtable->getNodeAttribs($node,\@columns);
unless (defined($attribs)) { next; } #TODO: This really ought to craft an unsupported response for this request
foreach (@columns) {
my $col=$_;
if (defined($attribs->{$col})) {
if ($colvals->{$col}) { #A pattern match style request.
if ($attribs->{$col} =~ /$colvals->{$col}/) {
$handler_hash{$ownmod}->{$node} = 1;
last;
}
} else {
$handler_hash{$attribs->{$col}}->{$node} = 1;
last;
}
}
}
}
} else {
unless (@nodes) {
$handler_hash{$hdlspec} = 1;
}
foreach (@nodes) { #Specified a specific plugin, not a table lookup
$handler_hash{$hdlspec}->{$_} = 1;
}
}
}
} else {
return 1; #TODO: error back that request has no known plugin for it
}
my $children=0;
$SIG{CHLD} = sub {while (waitpid(-1, WNOHANG) > 0) { $children--; } };
my $check_fds;
if ($sock) {
$check_fds = new IO::Select;
}
foreach (keys %handler_hash) {
my $modname = $_;
if (-r $plugins_dir."/".$modname.".pm") {
require $plugins_dir."/".$modname.".pm";
$children++;
my $pfd; #will be referenced for inter-process messaging.
my $child;
if ($sock) { #If $sock not passed in, don't fork..
socketpair($pfd, $parent_fd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!";
#pipe($pfd,$cfd);
$parent_fd->autoflush(1);
$pfd->autoflush(1);
$child = fork;
} else {
$child = 0;
}
unless (defined $child) { die "Fork failed"; }
if ($child == 0) {
my $oldprogname=$$progname;
$$progname=$oldprogname.": $modname instance";
if ($sock) { close $pfd; }
unless ($handler_hash{$_} == 1) {
my @nodes = sort {($a =~ /(\d+)/)[0] <=> ($b =~ /(\d+)/)[0] || $a cmp $b } (keys %{$handler_hash{$_}});
$req->{node}=\@nodes;
}
no strict "refs";
${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request);
$$progname=$oldprogname;
if ($sock) {
close($parent_fd);
exit(0);
}
} else {
close $parent_fd;
$check_fds->add($pfd);
}
}
}
unless ($sock) { return $Main::resps };
while ($children > 0) {
relay_fds($check_fds,$sock);
}
#while (relay_fds($check_fds,$sock)) {}
my %done;
$done{serverdone} = {};
if ($req->{transid}) {
$done{transid}=$req->{transid}->[0];
}
if ($sock) { print $sock XMLout(\%done,RootName => 'xcatresponse',NoAttr=>1); }
}
sub do_request {
my $req = shift;
my $second = shift;
my $rsphandler = \&build_response;
my $sock = undef;
if ($second) {
if (ref($second) eq "CODE") {
$rsphandler = $second;
} elsif (ref($second) eq "GLOB") {
$sock = $second;
}
}
#my $sock = shift; #If no sock, will return a response hash
if ($cmd_handlers{$req->{command}->[0]}) {
return plugin_command($req,$sock,$rsphandler);
} elsif ($req->{command}->[0] eq "noderange" and $req->{noderange}) {
my @nodes = noderange($req->{noderange}->[0]);
my %resp;
if (nodesmissed) {
$resp{warning}="Invalid nodes in noderange:".join ',',nodesmissed;
}
$resp{serverdone} = {};
@{$resp{node}}=@nodes;
if ($req->{transid}) {
$resp{transid}=$req->{transid}->[0];
}
if ($sock) {
print $sock XMLout(\%resp,RootName => 'xcatresponse',NoAttr=>1);
} else {
return (\%resp);
}
} else {
my %resp=(error=>"Unsupported request");
$resp{serverdone} = {};
if ($req->{transid}) {
$resp{transid}=$req->{transid}->[0];
}
if ($sock) {
print $sock XMLout(\%resp,RootName => 'xcatresponse',NoAttr=>1);
} else {
return (\%resp);
}
}
}
sub convey_response {
my $resp=shift;
#TODO: This is where the following will/may happen:
#-Track transaction id
#-Save output for deferred commands
unless ($parent_fd) {
build_response($resp);
return;
}
print $parent_fd XMLout($resp,KeyAttr=>[], NoAttr=>1,RootName=>'xcatresponse');
<$parent_fd>; #Block until parent acks data
#print "woo";
# KeyAttr => [], NoAttr => 1)
}
sub build_response {
# Handle responses from do_request calls made directly from a plugin
# Merge this response into the full response hash. We'll collect all
# the responses and ship it back on the return to the plugin.
# Note: Need to create a new "deep clone" copy of each response structure
# otherwise the next call will overwrite the reference we pushed on
# the response array
my $resp = shift;
foreach (keys %$resp) {
my $subresp = dclone($resp->{$_});
push (@{$Main::resps->{$_}}, @{$subresp});
}
}
sub service_connection {
my $sock = shift;
my $peername = shift;
my $peerhost = shift;
my $peerport = $sock->peerport;
my %tables=();
#some paranoid measures could reduce a third party abusing stage3 image to attempting to get USER/PASS for BMCs:
# -Well, minimally, ignore requests if requesting node is not in spconfig mode (stage3)
# -Option to generate a random password per 'getipmi' request. This reduces the exposure to a D.O.S. hopefully
#Give only 15 seconds of silence allowed or terminate connection. Using alarm since we are in thread-unsafe world anyway
my $timedout = 0;
$SIG{ALRM} = sub { $timedout = 1; die; };
eval {
my $request;
my $req=undef;
alarm(15);
while (<$sock>) {
alarm(0);
$request .= $_;
#$req = eval { XMLin($request, ForceArray => [ 'attribute' , 'attributepair' ]) };
if ($request =~ m/<\/xcatrequest>/) {
$req = eval { XMLin($request, SuppressEmpty=>undef,ForceArray=>1) };
#we have a full request..
#printf $request."\n";
$request="";
if (validate($peername,$peerhost,$req)) {
$req->{'!xcat_authname'} = [$peername];
$req->{'!xcat_clienthost'} = [$peerhost];
$req->{'!xcat_clientport'}= [$peerport];
$$progname="xCATd SSL: ".$req->{command}->[0]." for ".($peername ? $peername ."@".$peerhost : $peerhost);
if ($cmd_handlers{$req->{command}->[0]}) {
return plugin_command($req,$sock,\&convey_response);
} elsif ($req->{command}->[0] eq "noderange" and $req->{noderange}) {
my @nodes = noderange($req->{noderange}->[0]);
my %resp;
if (nodesmissed) {
$resp{warning}="Invalid nodes in noderange:".join ',',nodesmissed;
}
$resp{serverdone} = {};
@{$resp{node}}=@nodes;
if ($req->{transid}) {
$resp{transid}=$req->{transid}->[0];
}
print $sock XMLout(\%resp,RootName => 'xcatresponse',NoAttr=>1);
next;
} else {
my %resp=(error=>"Unsupported request");
$resp{serverdone} = {};
if ($req->{transid}) {
$resp{transid}=$req->{transid}->[0];
}
print $sock XMLout(\%resp,RootName => 'xcatresponse',NoAttr=>1);
next;
}
} else {
my %resp=(error=>"Permission denied for request");
$resp{serverdone} = {};
if ($req->{transid}) {
$resp{transid}=$req->{transid}->[0];
}
my $response=XMLout(\%resp,RootName =>'xcatresponse',NoAttr => 1);
print $sock $response;
next;
}
}
alarm(15);
}
};
if ($@) { # The eval statement caught a program bug..
unless ($@ =~ /^SIGPIPE/) {
syslog("local1|err","xcatd: possible BUG encountered by xCAT TCP service: ".$@);
} else {
syslog("local1|info","xcatd: Unexpected client disconnect");
}
}
alarm(0);
foreach (keys %tables) {
$tables{$_}->commit;
}
$sock->close;
if ($timedout == 1) {
printf ("Client timeout");
}
}
sub relay_fds { #Relays file descriptors from pipes to children to the SSL socket
my $fds = shift;
my $sock = shift;
unless ($sock) { return 0; }
my $collate = ( scalar @_ > 0 ? shift : 0);
my @readyset = $fds->can_read(1);
my $rfh;
my $rc = @readyset;
my $text;
foreach $rfh (@readyset) { #go through each child, extract a complete, atomic message
my $line;
while ($line = <$rfh>) { #Will break on complete </xcatresponse> messages, avoid interleave
print $sock $line;
if ($line =~ /<\/xcatresponse>/) {
last;
}
}
if ($line) {
print $rfh "fin\n"; #Notify convey_response message done
} else {
$fds->remove($rfh);
close($rfh);
}
}
return $rc;
}
sub validate {
#BIG TODO, make this do something meaningful
#here is where we check if $peername is allowed to do $request. $peername if set signifies client has a
#cert that the xCAT CA accepted. This will be a policy table with $peername as key
#things like 'stage2/stage3' and install images will have no client certificate.
#A client key for something that a third party could easily tftp down themselves means nothing
#however, privacy between the nodes can be maintained, and $peerhost will be checked just like 1.2.0.
# returns 1 if policy engine allows the action, 0 if denied
my $peername=shift;
my $peerhost=shift;
my $request=shift;
my $policytable = xCAT::Table->new('policy');
unless ($policytable) {
syslog("err","Unable to open policy data, denying");
return 0;
}
my @policies = $policytable->getTable;
my $rule;
foreach $rule (@policies) {
if ($rule->{name} and $rule->{name} ne '*') {
#TODO: more complex matching (lists, wildcards)
next unless ($peername eq $rule->{name});
}
if ($rule->{time} and $rule->{time} ne '*') {
#TODO: time ranges
}
if ($rule->{host} and $rule->{host} ne '*') {
#TODO: more complex matching (lists, noderanges?, wildcards)
next unless ($peerhost eq $rule->{host});
}
if ($rule->{commands} and $rule->{commands} ne '*') {
#TODO: syntax for multiple commands
next unless ($request->{command}->[0] eq $rule->{commands});
}
if ($rule->{parameters} and $rule->{parameters} ne '*') {
next; #TODO: not ignore this field
}
if ($rule->{noderange} and $rule->{noderange} ne '*') {
next; #TODO: not ignore this field
}
# If we are still in, that means this rule is the first match and dictates behavior.
if ($rule->{rule}) {
if ($rule->{rule} =~ /allow/i or $rule->{rule} =~ /accept/i) {
my $logst = "xCAT: Allowing ".$request->{command}->[0];
if ($peername) { $logst .= " for " . $peername };
syslog("authpriv|info",$logst);
return 1;
} else {
my $logst = "xCAT: Denying ".$request->{command}->[0];
if ($peername) { $logst .= " for " . $peername };
syslog("authpriv|info",$logst);
return 0;
}
} else { #Shouldn't be possible....
syslog("err","Impossible line in xcatd reached");
return 0;
}
}
#Reached end of policy table, reject by default.
syslog("err","Request matched no policy rule: ".$request->{command}->[0]);
return 0;
}

View File

@ -0,0 +1,73 @@
# $Id: Makefile,v 1.4 2006/06/20 18:55:37 jmates Exp $
#
# NOTE If running OpenSSL 0.9.8a or higher, see -newkey, below.
#
# Automates the setup of a custom Certificate Authority and provides
# routines for signing and revocation of certificates. To use, first
# customize the commands in this file and the settings in openssl.cnf,
# then run:
#
# make init
#
# Then, copy in certificate signing requests, and ensure their suffix is
# .csr before signing them with the following command:
#
# make sign
#
# To revoke a key, name the certificate file with the cert option
# as shown below:
#
# make revoke cert=foo.cert
#
# This will revoke the certificate and call gencrl; the revocation list
# will then need to be copied somehow to the various systems that use
# your CA cert.
requests = *.csr
sign: ${requests}
# remove -batch option if want chance to not certify a particular request
${requests}: FORCE
@openssl ca -config openssl.cnf -in $@ -out ${@:.csr=.cert}
@[ -f ${@:.csr=.cert} ] && rm $@
revoke:
@test $${cert:?"usage: make revoke cert=certificate"}
@openssl ca -config openssl.cnf -revoke $(cert)
@$(MAKE) gencrl
gencrl:
@openssl ca -config openssl.cnf -gencrl -out ca-crl.pem
clean:
-rm ${requests}
# creates required supporting files, CA key and certificate
init:
@test ! -f serial
@mkdir crl certs private
@chmod go-rwx private
@echo '01' > serial
@touch index
# NOTE use "-newkey rsa:2048" if running OpenSSL 0.9.8a or higher
# @openssl req -nodes -config openssl.cnf -days 2650 -x509 -newkey rsa:2048 -out ca-cert.pem -outform PEM
help:
@echo make sign
@echo ' - signs all *.csr files in this directory'
@echo
@echo make revoke cert=filename
@echo ' - revokes certificate in named file and calls gencrl'
@echo
@echo make gencrl
@echo ' - updates Certificate Revocation List (CRL)'
@echo
@echo make clean
@echo ' - removes all *.csr files in this directory'
@echo
@echo make init
@echo ' - required initial setup command for new CA'
# for legacy make support
FORCE:

View File

@ -0,0 +1,313 @@
#
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
#
# This definition stops the following lines choking if HOME isn't
# defined.
HOME = .
RANDFILE = $ENV::HOME/.rnd
# Extra OBJECT IDENTIFIER info:
#oid_file = $ENV::HOME/.oid
oid_section = new_oids
# To use this configuration file with the "-extfile" option of the
# "openssl x509" utility, name here the section containing the
# X.509v3 extensions to use:
# extensions =
# (Alternatively, use a configuration file that has only
# X.509v3 extensions in its main [= default] section.)
[ new_oids ]
# We can add new OIDs in here for use by 'ca' and 'req'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = ##XCATCADIR## # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
new_certs_dir = $dir/certs # default place for new certs.
certificate = $dir/ca-cert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/ca-key.pem # The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
# Extension copying option: use with caution.
# copy_extensions = copy
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions = crl_ext
default_days = 7300 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha1 # which md to use.
preserve = no # keep passed DN ordering
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ req ]
default_bits = 2048
default_keyfile = private/ca-key.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
# Passwords for private keys if not present they will be prompted for
# input_password = secret
# output_password = secret
# This sets a mask for permitted string types. There are several options.
# default: PrintableString, T61String, BMPString.
# pkix : PrintableString, BMPString.
# utf8only: only UTF8Strings.
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
# MASK:XXXX a literal mask value.
# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
# so use this option with caution!
string_mask = nombstr
# req_extensions = v3_req # The extensions to add to a certificate request
[ req_distinguished_name ]
#countryName = Country Name (2 letter code)
#countryName_default = US
#countryName_min = 2
#countryName_max = 2
#stateOrProvinceName = State or Province Name (full name)
#stateOrProvinceName_default = Some-State
#localityName = Locality Name (eg, city)
#0.organizationName = Organization Name (eg, company)
#0.organizationName_default = Internet Widgits Pty Ltd
# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd
#organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
commonName = Common Name (eg, YOUR name)
commonName_max = 64
#emailAddress = Email Address
#emailAddress_max = 64
# SET-ex3 = SET extension number 3
[ req_attributes ]
#challengePassword = A challenge password
#challengePassword_min = 4
#challengePassword_max = 20
#unstructuredName = An optional company name
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
# For normal client use this is typical
# nsCertType = client, email
# and for everything including object signing:
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# This will be displayed in Netscape's comment listbox.
nsComment = "OpenSSL Generated Certificate"
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move
# Copy subject details
# issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
# Extensions for a typical CA
# PKIX recommendation.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
# This is what PKIX recommends but some broken software chokes on critical
# extensions.
#basicConstraints = critical,CA:true
# So we do this instead.
basicConstraints = CA:true
# Key usage: this is typical for a CA certificate. However since it will
# prevent it being used as an test self-signed certificate it is best
# left out by default.
# keyUsage = cRLSign, keyCertSign
# Some might want this also
# nsCertType = sslCA, emailCA
# Include email address in subject alt name: another PKIX recommendation
# subjectAltName=email:copy
# Copy issuer details
# issuerAltName=issuer:copy
# DER hex encoding of an extension: beware experts only!
# obj=DER:02:03
# Where 'obj' is a standard or added object
# You can even override a supported extension:
# basicConstraints= critical, DER:30:03:01:01:FF
[ crl_ext ]
# CRL extensions.
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
# issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always
[ proxy_cert_ext ]
# These extensions should be added when creating a proxy certificate
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
# For normal client use this is typical
# nsCertType = client, email
# and for everything including object signing:
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# This will be displayed in Netscape's comment listbox.
nsComment = "OpenSSL Generated Certificate"
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move
# Copy subject details
# issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName
# This really needs to be in place for it to be a proxy certificate.
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo

View File

@ -0,0 +1,45 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use xCAT::Table;
use File::Basename;
my $scriptname = $0;
$mptab = xCAT::Table->new('mp');
unless ($mptab) {
sleep 5; #Try not to overwhelm logfiles...
die "mp table must be configured";
}
$mpatab = xCAT::Table->new('mpa');
$passtab = xCAT::Table->new('passwd');
my $username = "USERID";
my $passsword = "PASSW0RD";
my $mm;
my $slot;
my $dba;
if ($passtab) {
($dba) = $passtab->getAttribs({key=>blade},qw(username password));
if ($dba->{username}) {
$username = $dba->{username};
}
if ($dba->{password}) {
$password = $dba->{password};
}
}
$dba = $mptab->getNodeAttribs($ARGV[0],[qw(mpa id)]);
$mm = $dba->{mpa};
$slot = $dba->{id};
if ($mpatab) {
($dba) = $mpatab->getAttribs({mpa=>$mm},qw(username password));
if ($dba) {
if ($dba->{username}) { $username = $dba->username; }
if ($dba->{password}) { $password = $dba->password; }
}
}
my $pathtochild= dirname($scriptname). "/";
exec $pathtochild."blade.expect $mm $slot $username $password";

View File

@ -0,0 +1,35 @@
#!/usr/bin/env expect
set timeout 45
set bcmm [lindex $argv 0]
set bayno [lindex $argv 1]
set username [lindex $argv 2]
set password [lindex $argv 3]
set cmdline "console -o -T blade\[$bayno\]"
spawn telnet $bcmm
expect -re ".*username: "
send "$username\r"
expect -re ".*password: "
send "$password\r"
expect -re ".*system> "
send "$cmdline\r"
expect {
eof {
exit
}
-re ".*system> " {
sleep 5
send "$cmdline\r"
}
"?" {
interact {
-o
"system> " {
sleep 5
send "$cmdline\r"
}
}
}
}

View File

@ -0,0 +1,29 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
use xCAT::Table;
my $dba;
my $ipmitab = xCAT::Table->new('ipmi');
unless ($ipmitab) { sleep 5; die "Unable to open IPMI table"; }
my $passtab = xCAT::Table->new('passwd');
my $username = 'USERID';
my $password = 'PASSW0RD';
my $node = $ARGV[0];
my $bmc = $node;
if ($passtab) {
($dba) = $passtab->getAttribs({key=>'ipmi'},qw(username password));
if ($dba) {
if ($dba->{username}) { $username = $dba->{username}; }
if ($dba->{password}) { $password = $dba->{password}; }
}
}
$dba = $ipmitab->getNodeAttribs($ARGV[0],[qw(bmc username password)]);
if ($dba) {
if ($dba->{bmc}) { $bmc = $dba->{bmc}; }
if ($dba->{username}) { $username = $dba->{username}; }
if ($dba->{password}) { $password = $dba->{password}; }
}
system "ipmitool -I lanplus -U $username -P $password -H $bmc sol deactivate"; #Stop any active session
exec "ipmitool -I lanplus -U $username -P $password -H $bmc sol activate";

View File

@ -0,0 +1,184 @@
#RedHat Enterprise Linux 4 AS Only
#egan@us.ibm.com
#
lang en_US
langsupport en_US
network --bootproto dhcp
#
# Where's the source?
# nfs --server hostname.of.server or IP --dir /path/to/RH/CD/image
#
nfs --server #XCATVAR:INSTALL_NFS# --dir #XCATVAR:INSTALL_SRC_DIR#
#device ethernet e100
keyboard "#TABLE:site.tab:keyboard:1#"
#
# Clear the MBR
#
zerombr yes
#
# Wipe out the disk
#
clearpart --all --initlabel
#clearpart --linux
#
# Customize to fit your needs
# /boot is strongly recommended
#
#No RAID
part /boot --size 50 --ondisk sda --fstype ext3
part swap --size 1024 --ondisk sda
part / --size 6000 --grow --ondisk sda --fstype ext3
#RAID 0 /scr for performance
#part / --size 1024 --ondisk sda
#part swap --size 512 --ondisk sda
#part /var --size 1024 --ondisk sdb
#part swap --size 512 --ondisk sdb
#part raid.01 --size 1 --grow --ondisk sda
#part raid.02 --size 1 --grow --ondisk sdb
#raid /scr --level 0 --device md0 raid.01 raid.02
#Full RAID 1 Sample
#part raid.01 --size 50 --ondisk sda
#part raid.02 --size 50 --ondisk sdb
#raid /boot --level 1 --device md0 raid.01 raid.02
#
#part raid.11 --size 1024 --ondisk sda
#part raid.12 --size 1024 --ondisk sdb
#raid / --level 1 --device md1 raid.11 raid.12
#
#part raid.21 --size 1024 --ondisk sda
#part raid.22 --size 1024 --ondisk sdb
#raid /var --level 1 --device md2 raid.21 raid.22
#
#part raid.31 --size 1024 --ondisk sda
#part raid.32 --size 1024 --ondisk sdb
#raid swap --level 1 --device md3 raid.31 raid.32
#
#part raid.41 --size 1 --grow --ondisk sda
#part raid.42 --size 1 --grow --ondisk sdb
#raid /scr --level 1 --device md4 raid.41 raid.42
#
# bootloader config
# --append <args>
# --useLilo
# --md5pass <crypted MD5 password for GRUB>
#
bootloader
#
# install or upgrade
#
install
#
# text mode install (default is graphical)
#
text
#
# firewall
#
firewall --disabled
#
# mouse selection
#
#mouse genericps/2 --emulthree
mouse none
#
# Select a zone
# Add the --utc switch if your hardware clock is set to GMT
#
#timezone US/Hawaii
#timezone US/Pacific
#timezone US/Mountain
#timezone US/Central
#timezone US/Eastern
timezone --utc #TABLE:site.tab:timezone:1#
#
# Don't do X
#
skipx
#
# Geez!
#
key --skip
#
# To generate an encrypted root password use:
#
# perl -e 'print crypt("blah","Xa") . "\n";'p
# openssl passwd -apr1 -salt xxxxxxxx password
#
# where "blah" is your root password.
#
#rootpw --iscrypted XaLGAVe1C41x2
#rootpw XaLGAVe1C41x2 --iscrypted
#rootpw #TABLE:passwd.tab:rootpw:1#
rootpw --iscrypted #COMMAND:perl -e 'print crypt("#TABLE:passwd.tab:rootpw:1#","Xa") . "\n";'p#
#
# NIS setup: auth --enablenis --nisdomain sensenet
# --nisserver neptune --useshadow --enablemd5
#
# OR
auth --useshadow --enablemd5
#
# SE Linux
#
selinux --disabled
#
# Reboot after installation
#
reboot
#
#end of section
#
%packages --resolvedeps
@Everything
@ Everything
@ System Tools
@ X Window System
@ Legacy Software Development
#kernel-smp
autofs
ksh
tcsh
ntp
tftp
xinetd
rsh
rsh-server
psacct
nfs-utils
net-snmp
rsync
yp-tools
ypserv
ypbind
m4
sendmail-cf
gdb
binutils
openssh-server
util-linux
compat-libstdc++-33
%pre
#COMMAND:genscript pre #ENV:OSVER# #ENV:ARCH##
%post
#COMMAND:genscript post #ENV:OSVER# #ENV:ARCH##

View File

@ -0,0 +1,178 @@
#RedHat Enterprise Linux 4 AS Only
#egan@us.ibm.com
#
lang en_US
langsupport en_US
network --bootproto dhcp
#
# Where's the source?
# nfs --server hostname.of.server or IP --dir /path/to/RH/CD/image
#
#nfs --server #XCATVAR:INSTALL_NFS# --dir #XCATVAR:INSTALL_SRC_DIR#
url --url http://#TABLE:noderes:$NODE:nfsserver#/install/#TABLE:nodetype:$NODE:os#/#TABLE:nodetype:$NODE:arch#
#device ethernet e100
keyboard "us"
#
# Clear the MBR
#
zerombr yes
#
# Wipe out the disk
#
clearpart --all --initlabel
#clearpart --linux
#
# Customize to fit your needs
#
#No RAID
#/boot really significant for this sort of setup nowadays?
#part /boot --size 50 --fstype ext3
part swap --size 1024
part / --size 1 --grow --fstype ext3
#RAID 0 /scr for performance
#part / --size 1024 --ondisk sda
#part swap --size 512 --ondisk sda
#part /var --size 1024 --ondisk sdb
#part swap --size 512 --ondisk sdb
#part raid.01 --size 1 --grow --ondisk sda
#part raid.02 --size 1 --grow --ondisk sdb
#raid /scr --level 0 --device md0 raid.01 raid.02
#Full RAID 1 Sample
#part raid.01 --size 50 --ondisk sda
#part raid.02 --size 50 --ondisk sdb
#raid /boot --level 1 --device md0 raid.01 raid.02
#
#part raid.11 --size 1024 --ondisk sda
#part raid.12 --size 1024 --ondisk sdb
#raid / --level 1 --device md1 raid.11 raid.12
#
#part raid.21 --size 1024 --ondisk sda
#part raid.22 --size 1024 --ondisk sdb
#raid /var --level 1 --device md2 raid.21 raid.22
#
#part raid.31 --size 1024 --ondisk sda
#part raid.32 --size 1024 --ondisk sdb
#raid swap --level 1 --device md3 raid.31 raid.32
#
#part raid.41 --size 1 --grow --ondisk sda
#part raid.42 --size 1 --grow --ondisk sdb
#raid /scr --level 1 --device md4 raid.41 raid.42
#
# bootloader config
# --append <args>
# --useLilo
# --md5pass <crypted MD5 password for GRUB>
#
bootloader
#
# install or upgrade
#
install
#
# text mode install (default is graphical)
#
text
#
# firewall
#
firewall --disabled
#
# mouse selection
#
#mouse genericps/2 --emulthree
mouse none
#
# Select a zone
# Add the --utc switch if your hardware clock is set to GMT
#
#timezone US/Hawaii
#timezone US/Pacific
#timezone US/Mountain
#timezone US/Central
#timezone US/Eastern
timezone --utc #TABLE:site:key=timezone:value#
#
# Don't do X
#
skipx
#
# To generate an encrypted root password use:
#
# perl -e 'print crypt("blah","Xa") . "\n";'p
# openssl passwd -apr1 -salt xxxxxxxx password
#
# where "blah" is your root password.
#
#rootpw --iscrypted XaLGAVe1C41x2
#rootpw XaLGAVe1C41x2 --iscrypted
rootpw --iscrypted #CRYPT:passwd:key=system,username=root:password#
#rootpw --iscrypted #COMMAND:perl -e 'print crypt("#TABLE:passwd.tab:rootpw:1#","Xa") . "\n";'p#
#
# NIS setup: auth --enablenis --nisdomain sensenet
# --nisserver neptune --useshadow --enablemd5
#
# OR
auth --useshadow --enablemd5
#
# SE Linux
#
selinux --disabled
#
# Reboot after installation
#
reboot
#
#end of section
#
%packages --resolvedeps
@ Network Servers
@ System Tools
@ X Window System
@ Legacy Software Development
autofs
tcsh
ntp
tftp
xinetd
rsh
rsh-server
psacct
nfs-utils
net-snmp
rsync
yp-tools
ypserv
ypbind
m4
sendmail-cf
gdb
binutils
openssh-server
util-linux
compat-libstdc++-33
%pre
#INCLUDE:../scripts/pre.rh#
%post
#INCLUDE:../scripts/post.rh#

View File

@ -0,0 +1,180 @@
#RedHat Enterprise Linux 4 AS Only
#egan@us.ibm.com
#
lang en_US
langsupport en_US
network --bootproto dhcp
#
# Where's the source?
# nfs --server hostname.of.server or IP --dir /path/to/RH/CD/image
#
#nfs --server #XCATVAR:INSTALL_NFS# --dir #XCATVAR:INSTALL_SRC_DIR#
url --url http://#TABLE:noderes:$NODE:nfsserver#/install/#TABLE:nodetype:$NODE:os#/#TABLE:nodetype:$NODE:arch#
#device ethernet e100
keyboard "us"
#
# Clear the MBR
#
zerombr yes
#
# Wipe out the disk
#
clearpart --all --initlabel
#clearpart --linux
key --skip
#
# Customize to fit your needs
#
#No RAID
#/boot really significant for this sort of setup nowadays?
#part /boot --size 50 --fstype ext3
part swap --size 1024
part / --size 1 --grow --fstype ext3
#RAID 0 /scr for performance
#part / --size 1024 --ondisk sda
#part swap --size 512 --ondisk sda
#part /var --size 1024 --ondisk sdb
#part swap --size 512 --ondisk sdb
#part raid.01 --size 1 --grow --ondisk sda
#part raid.02 --size 1 --grow --ondisk sdb
#raid /scr --level 0 --device md0 raid.01 raid.02
#Full RAID 1 Sample
#part raid.01 --size 50 --ondisk sda
#part raid.02 --size 50 --ondisk sdb
#raid /boot --level 1 --device md0 raid.01 raid.02
#
#part raid.11 --size 1024 --ondisk sda
#part raid.12 --size 1024 --ondisk sdb
#raid / --level 1 --device md1 raid.11 raid.12
#
#part raid.21 --size 1024 --ondisk sda
#part raid.22 --size 1024 --ondisk sdb
#raid /var --level 1 --device md2 raid.21 raid.22
#
#part raid.31 --size 1024 --ondisk sda
#part raid.32 --size 1024 --ondisk sdb
#raid swap --level 1 --device md3 raid.31 raid.32
#
#part raid.41 --size 1 --grow --ondisk sda
#part raid.42 --size 1 --grow --ondisk sdb
#raid /scr --level 1 --device md4 raid.41 raid.42
#
# bootloader config
# --append <args>
# --useLilo
# --md5pass <crypted MD5 password for GRUB>
#
bootloader
#
# install or upgrade
#
install
#
# text mode install (default is graphical)
#
text
#
# firewall
#
firewall --disabled
#
# mouse selection
#
#mouse genericps/2 --emulthree
mouse none
#
# Select a zone
# Add the --utc switch if your hardware clock is set to GMT
#
#timezone US/Hawaii
#timezone US/Pacific
#timezone US/Mountain
#timezone US/Central
#timezone US/Eastern
timezone --utc #TABLE:site:key=timezone:value#
#
# Don't do X
#
skipx
#
# To generate an encrypted root password use:
#
# perl -e 'print crypt("blah","Xa") . "\n";'p
# openssl passwd -apr1 -salt xxxxxxxx password
#
# where "blah" is your root password.
#
#rootpw --iscrypted XaLGAVe1C41x2
#rootpw XaLGAVe1C41x2 --iscrypted
rootpw --iscrypted #CRYPT:passwd:key=system,username=root:password#
#rootpw --iscrypted #COMMAND:perl -e 'print crypt("#TABLE:passwd.tab:rootpw:1#","Xa") . "\n";'p#
#
# NIS setup: auth --enablenis --nisdomain sensenet
# --nisserver neptune --useshadow --enablemd5
#
# OR
auth --useshadow --enablemd5
#
# SE Linux
#
selinux --disabled
#
# Reboot after installation
#
reboot
#
#end of section
#
%packages --resolvedeps
@ Network Servers
@ System Tools
@ X Window System
@ Legacy Software Development
autofs
ksh
tcsh
ntp
tftp
xinetd
rsh
rsh-server
psacct
nfs-utils
net-snmp
rsync
yp-tools
ypserv
ypbind
m4
sendmail-cf
gdb
binutils
openssh-server
util-linux
compat-libstdc++-33
%pre
#INCLUDE:../scripts/pre.rh#
%post
#INCLUDE:../scripts/post.rh#

View File

@ -0,0 +1,44 @@
<chroot-scripts config:type="list">
<script>
<filename>boot.sh</filename>
<interpreter>shell</interpreter>
<source>
<![CDATA[
#!/bin/sh
AWK=`find / -name awk | head -1`
#old awk /mounts/instsys/bin/awk -f
cat >/tmp/updateflag.awk <<EOF
#!$AWK -f
BEGIN {
xcatdport = #TABLE:site:key=xcatiport:value#
xcatdhost = "#XCATVAR:XCATMASTER#"
ns = "/inet/tcp/0/" xcatdhost "/" xcatdport
while(1) {
if((ns |& getline) > 0)
print \$0
if(\$0 == "ready")
print "next" |& ns
if(\$0 == "done")
break
}
close(ns)
exit 0
}
EOF
chmod 755 /tmp/updateflag.awk
/tmp/updateflag.awk
]]>
</source>
</script>
</chroot-scripts>

View File

@ -0,0 +1,58 @@
#
# Setup hostname
#
echo "post scripts" >/root/post.log
export PRINIC=#TABLE:noderes:THISNODE:primarynic#
if [ -z "$PRINIC" ]
then
export PRINIC=eth0
fi
IP=$(ifconfig $PRINIC | grep inet | awk '{print $2}' | awk -F: '{print $2}')
if [ -z $IP ]
then
dhclient eth0
IP=$(ifconfig $PRINIC | grep inet | awk '{print $2}' | awk -F: '{print $2}')
fi
echo "search #TABLE:site:key=domain:value#" >/etc/resolv.conf
for i in $(echo #TABLE:site:key=nameservers:value# | tr ',' ' ')
do
echo "nameserver $i"
done >>/etc/resolv.conf
export HOSTNAME=$(host $IP 2>/dev/null | awk '{print $5}' | awk -F. '{print $1}')
hostname $HOSTNAME
#
# Run xCAT post install
#
export MASTER_IP="#XCATVAR:XCATMASTER#"
export MASTER_IPS="#XCATVAR:XCATMASTER#"
mkdir -p /xcatpost
RAND=$(perl -e 'print int(rand(50)). "\n"')
sleep $RAND
for i in $(seq 1 20)
do
GOTIT=0
for i in $MASTER_IPS
do
# mount -r $i:$XCATROOT $XCATROOT
mount -o ro,nolock $i:/install/postscripts /xcatpost
if [ "$?" = "0" ]
then
GOTIT=1
break
fi
done
if [ "$GOTIT" = "1" ]
then
break
fi
RAND=$(perl -e 'print int(rand(5)). "\n"')
sleep $RAND
done
#mount -r #XCATVAR:MASTER_IP#:$XCATROOT $XCATROOT
#mount -o ro,nolock #XCATVAR:MASTER_IP#:$XCATROOT $XCATROOT
#$XCATROOT/bin/postage
/xcatpost/#TABLE:nodelist:THISNODE:node#
cd /
umount /xcatpost
rmdir /xcatpost
exit 0

View File

@ -0,0 +1,84 @@
<post-scripts config:type="list">
<script>
<filename>xcat.sh</filename>
<interpreter>shell</interpreter>
<source>
<![CDATA[
#!/bin/sh
cd /etc/sysconfig/network
rm -f ifcfg-eth-id*
rm -f ifcfg-myri*
cat >ifcfg-eth0 <<EOF
DEVICE=eth0
BOOTPROTO=dhcp
STARTMODE=onboot
EOF
export PRINIC=#TABLE:noderes:$NODE:primarynic#
if [ -z "$PRINIC" ]; then
export PRINIC=eth0
fi
if [ "$PRINIC" != "eth0" ]
then
cd /etc/sysconfig/network
if [ ! -r ifcfg-$PRINIC ]
then
cp -f ifcfg-eth0 ifcfg-$PRINIC
perl -pi -e "s/eth0/$PRINIC/" ifcfg-$PRINIC
echo "DHCLIENT_PRIMARY_DEVICE=yes" >> ifcfg-$PRINIC
fi
fi
perl -pi -e 's/^FIREWALL="yes"/FIREWALL="no"/' /etc/sysconfig/network/config
/etc/init.d/network restart
RAND=$(perl -e 'print int(rand(50)). "\n"')
sleep $RAND
jsi=0
while [ $(hostname) == 'linux' ]
do
if [ $jsi -gt 10 ]; then
logger "Slept too long!"
exit
fi
let jsi=jsi+1
sleep 1
done
echo "Slept $jsi seconds before hostname made sense."
HOSTNAME=$(hostname -s)
echo $HOSTNAME
/sbin/portmap
export MASTER_IP=#XCATVAR:XCATMASTER#
export MASTER_IPS=#XCATVAR:XCATMASTER#
mkdir -p /xcatpost
for i in $(seq 1 20)
do
GOTIT=0
for i in $MASTER_IPS
do
mount -r $i:/install/postscripts /xcatpost
if [ "$?" = "0" ]
then
GOTIT=1
break
fi
done
if [ "$GOTIT" = "1" ]
then
break
fi
RAND=$(perl -e 'print int(rand(5)). "\n"')
sleep $RAND
done
cd /
/xcatpost/#TABLE:nodelist:$NODE:node#
umount /xcatpost
rmdir /xcatpost
]]>
</source>
</script>
</post-scripts>

View File

@ -0,0 +1,123 @@
if grep n8r /proc/cmdline >& /dev/null;
then
stty crtscts
fi
for x in 0 1 2 3 4 5 6 7 8
do
mknod /dev/vcs$x c 7 $x
mknod /dev/vcsa$x c 7 $[$x+128]
done
chmod 644 /dev/vcs*
chown root /dev/vcs*
cat >/tmp/foo.py <<EOF
#!/usr/bin/python
import socket
import os
import linecache
import re
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('#XCATVAR:XCATMASTER#',#TABLE:site:key=xcatiport:value#))
response = sock.recv(100)
if(response == "ready\n"):
sock.send("installmonitor\n")
response = sock.recv(100)
sock.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
port = 3001
sock.bind(('', port))
sock.listen(5)
try:
while 1:
newSocket, address = sock.accept()
while 1:
received = newSocket.recv(200)
if not received:
break
command = re.split('\s+',received)
if(command[0] == "stat"):
ilog = ""
firstline = ""
line = ""
post = 0
percent = 0
count = 0
numpack = 0
if(os.path.isfile('/mnt/sysimage/root/install.log')):
ilog = '/mnt/sysimage/root/install.log'
if(os.path.isfile('/mnt/sysimage/tmp/install.log')):
ilog = '/mnt/sysimage/tmp/install.log'
if(os.path.isfile('/mnt/sysimage/root/post.log')):
ilog = '/mnt/sysimage/root/post.log'
post = 1
if(ilog):
count = len(open(ilog).readlines())
firstline = linecache.getline(ilog,1)
line = linecache.getline(ilog,count)
linecache.clearcache()
if(line and not post):
r1 = re.compile("^Installing (\d+) ")
m1 = r1.search(firstline)
if m1:
numpack = int(m1.group(1))
if(numpack > 0):
percent = int(((count - 2) * 100)/numpack + .5)
if(percent > 100):
percent = 100
if(percent < 0):
percent = 0
r2 = re.compile("^Installing (.*)\.")
m2 = r2.search(line)
if m2:
newline = m2.group(1)
newline = newline + " ("
newline = newline + str(percent)
newline = newline + "%)"
# newline = newline + " ["
# count = count - 2
# newline = newline + str(count)
# newline = newline + "/"
# newline = newline + str(numpack)
# newline = newline + "]"
else:
newline = "prep"
line = "installing " + newline
if(line and post):
line = "installing " + line
if(not line):
line = "installing prep"
newSocket.send(line)
break
# if(command[0] == "sh"): #DEBUG purposes only, wide open root priv command here.
# newcommand = ""
# for i in command[1:]:
# newcommand = newcommand + i + " "
# output = os.popen(newcommand).read()
# newSocket.send(output)
# break
if(command[0] == "screendump"):
newcommand = "cat /dev/vcs"
for i in command[1:]:
newcommand = newcommand + i
output = os.popen(newcommand).read()
newSocket.send(output)
break
newSocket.close()
finally:
sock.close()
EOF
chmod 755 /tmp/foo.py
/tmp/foo.py >/foo.log 2>&1 &

View File

@ -0,0 +1,98 @@
<pre-scripts config:type="list">
<script>
<filename>foo.sh</filename>
<interpreter>shell</interpreter>
<source>
<![CDATA[
#!/bin/sh
AWK=`find / -name awk | tail -1`
#old awk /mounts/instsys/bin/awk -f
cat >/tmp/bar.awk <<EOF
#!$AWK -f
BEGIN {
xcatdport = "#TABLE:site:key=xcatiport:value#"
xcatdhost = "#XCATVAR:XCATMASTER#"
ns = "/inet/tcp/0/" xcatdhost "/" xcatiport
print "xCAT_xcatd" |& ns
while(1) {
ns |& getline
if(\$0 == "ready")
print "installmonitor" |& ns
if(\$0 == "done")
break
}
close(ns)
exit 0
}
EOF
if [ ! -c /dev/vcs ]; then
mknod /dev/vcs c 7 0
fi
cat >/tmp/foo.awk <<EOF
#!$AWK -f
BEGIN {
ns = "/inet/tcp/3001/0/0"
while(1) {
ns |& getline
# if(\$1 == "sh") { #TODO: ENABLE IF DEBUG
# sub(/^sh +/,"",\$0)
# output = \$0
# while((output | getline) > 0)
# print \$0 |& ns
# print "EOO" |& ns
# close(output)
# }
if(\$1 == "screendump") {
output = "chvt " \$2 ";cat /dev/vcs"
while((output | getline) > 0)
print \$0 |& ns
close(output)
}
if(\$1 == "stat") {
while((getline < "/mnt/var/log/YaST2/y2logRPM") > 0) {
line = \$0
}
close("/mnt/var/log/YaST2/y2logRPM")
if(line ~ /\.rpm /) {
sub(/\.[^\.]+\.rpm .*$/,"",line)
sub(/^.* /,"",line)
}
else {
line = "prep"
}
print ("installing " line) |& ns
}
close(ns)
}
}
EOF
chmod 755 /tmp/foo.awk
chmod 755 /tmp/bar.awk
/tmp/bar.awk &
/tmp/foo.awk >/tmp/foo.log 2>&1 &
]]>
</source>
</script>
</pre-scripts>

View File

@ -0,0 +1,116 @@
<?xml version="1.0"?>
<!DOCTYPE profile SYSTEM "/usr/share/YaST2/include/autoinstall/profile.dtd">
<profile xmlns="http://www.suse.com/1.0/yast2ns" xmlns:config="http://www.suse.com/1.0/configns">
<install>
<bootloader>
<write_bootloader config:type="boolean">true</write_bootloader>
<activate config:type="boolean">true</activate>
<kernel_parameters></kernel_parameters>
<lba_support config:type="boolean">false</lba_support>
<linear config:type="boolean">false</linear>
<location>mbr</location>
</bootloader>
<general>
<clock>
<hwclock>GMT</hwclock>
<timezone>#TABLE:site:key=timezone:value#</timezone>
</clock>
<keyboard>
<keymap>english-us</keymap>
</keyboard>
<language>en_US</language>
<mode>
<confirm config:type="boolean">false</confirm>
<forceboot config:type="boolean">false</forceboot>
<interactive_boot config:type="boolean">false</interactive_boot>
<reboot config:type="boolean">true</reboot>
</mode>
<mouse>
<id>non</id>
</mouse>
</general>
<partitioning config:type="list">
<drive>
<device>/dev/sda</device>
<initialize config:type="boolean">true</initialize>
<use>all</use>
<partitions config:type="list">
<partition>
<filesystem config:type="symbol">ext2</filesystem>
<mount>/boot</mount>
<partition_id config:type="integer">131</partition_id>
<partition_nr config:type="integer">1</partition_nr>
<size>50MB</size>
</partition>
<partition>
<mount>swap</mount>
<partition_nr config:type="integer">2</partition_nr>
<size>auto</size>
</partition>
<partition>
<filesystem config:type="symbol">ext3</filesystem>
<mount>/var</mount>
<partition_id config:type="integer">131</partition_id>
<partition_nr config:type="integer">3</partition_nr>
<size>2GB</size>
</partition>
<partition>
<filesystem config:type="symbol">ext3</filesystem>
<mount>/</mount>
<partition_id config:type="integer">131</partition_id>
<partition_nr config:type="integer">4</partition_nr>
<size>max</size>
</partition>
</partitions>
</drive>
</partitioning>
<software>
<patterns config:type="list">
<pattern>base</pattern>
<pattern>base-32bit</pattern>
<pattern>32bit</pattern>
<pattern>x11-32bit</pattern>
<pattern>x11</pattern>
</patterns>
<packages config:type="list">
<package>xntp</package>
<package>rsync</package>
</packages>
</software>
</install>
<configure>
<users config:type="list">
<user>
<username>root</username>
<user_password>#CRYPT:passwd:key=system,username=root:password#</user_password>
<encrypted config:type="boolean">true</encrypted>
<forename/>
<surname/>
</user>
</users>
<networking>
<dns>
<dhcp_hostname config:type="boolean">true</dhcp_hostname>
<dhcp_resolv config:type="boolean">true</dhcp_resolv>
<domain>local</domain>
<hostname>linux</hostname>
</dns>
<interfaces config:type="list">
<interface>
<bootproto>dhcp</bootproto>
<device>eth0</device>
<startmode>onboot</startmode>
</interface>
</interfaces>
<routing>
<ip_forward config:type="boolean">false</ip_forward>
<routes config:type="list"/>
</routing>
</networking>
<scripts>
#INCLUDE:../scripts/pre.sles#
#INCLUDE:../scripts/chroot.sles#
#INCLUDE:../scripts/post.sles#
</scripts>
</configure>
</profile>

View File

@ -0,0 +1,19 @@
#!/bin/ksh
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#egan@us.ibm.com
#(C)IBM Corp
case "$OSVER" in
sles*|suse*|ul*)
perl -pi -e 's/^ENABLE_SYSRQ.*/ENABLE_SYSRQ="yes"/' /etc/sysconfig/sysctl
;;
rh*)
if egrep "^kernel\.sysrq" /etc/sysctl.conf >/dev/null 2>&1
then
perl -pi -e 's/^kernel\.sysrq.*/kernel.sysrq = 1/' /etc/sysctl.conf
else
echo "kernel.sysrq = 1" >>/etc/sysctl.conf
fi
;;
esac

Some files were not shown because too many files have changed in this diff Show More