Wednesday, December 10, 2008

RPM FOO Creating RPMS from Tar files

Working in Linux shops for years, one of the most challenging obstacles is coming out with a way to manage and maintain standard software and configurations across multiple servers. Using RPMS To distribute configurations via YUM and automated Installs via Kick-start. Is a good system management practice and has many advantages over other distribution methods.

Most of these examples, I list below don't need any pre or post scripts to deploy but just a good way to check versions, track, install and remove packages.

The following are some of the uses I use custom RPMS for.

  • SSH Keys
  • Web Site Releases
  • Standard System Configurations
  • And a million other things.

The advantages to using RPMS are numerous and ,well, lets just say it brings a lot more sanity to a chaotic world of system administration. RPM's most notable purpose is to install and back out of releases and configurations in a structured and organized manner.

But then again, its said that building and maintaining RPM packages has a high learning curve, and building RPM spec files is somewhat of a black art.

So here are the simple method to build your own RPMS.

On a RHEL 5 or CentOS 5 box (Probably works on RHEL 4 as well but I haven't tested it).

1. Yum install rpm-build
2. Tar up the files from the root directory ( and I don't mean /root )
3. Copy and Paste the script from below and save the script named bintar2rpm.
4. chmod 755 bintar2rpm
5. Execute the following command ./bintar2rpm Example.tar
6. Now answer the questions Summary of the rpm package (aka what is it)
7. Name of the rpm example.rpm
8. Major Version meaning 1 or 2 (Numeric input )
9. Release 0 or 1 ( So with the Major Version being 1 or 2 it will be 1.0 or 2.1)
10. License its distributed under: Privately, FreeBSD or GPL V2/V3

Sit back and watch it build the RPM for you on the hardware platform you are on.
It usually puts it the rpm in /usr/src/RPMS/$ARCH

Thanks to Bart Scaefer to a good patch that makes this work more like it was designed to.
As well as he added gzip support for the tar files.

There you go an RPM package in under a minute.


#!/usr/bin/perl
#Created by G. Ran Fawcett of Info-struct Systems
#Edited to support gzip'd tar files and alternate install path
# by Bart Schaefer
#For support and assistance contact gryanfawcett at gmail dot com
#Licnced under GPL v3
#Version 1.0-b
# Reason for using all system calls is to make this portable without any additional modules
if ( ! -e '/usr/bin/rpmbuild')
{
print "Missing Build Tools or Build Environment please install rpm-build";
exit 1;
}

if ( $ARGV[0] eq '' )
{
print "Error Missing tar file: try -h for usage\n";
exit 1;
}


if ($ARGV[0] eq '-h')
{
print "bintar2rpm Package by G. Ryan Fawcett gryanfawcett at gmail dot com\n";
print "Usage: bintar2rpm example.tar installdir\n";
exit 1;
}

$BuildRoot = "/tmp/bintar2rpm$$";

$TarPackage = $ARGV[0];
if ( $TarPackage =~ /gz$/ )
{
$tarOpts = 'zf';
}
else
{
$tarOpts = 'f';
}

$ExtractTo = $ARGV[1] || "/";
if ( $ExtractTo !~ m:^/: )
{
print "Install directory must be a full path from the root\n";
exit 1;
}

system("mkdir -p $BuildRoot$ExtractTo");
@FileList = `tar -C $BuildRoot$ExtractTo -xv$tarOpts $TarPackage 2>/dev/null`;

if ( $ExtractTo !~ m:/$: )
{
$ExtractTo .= "/";
}

print "Summary: ";
$Summary = %3CSTDIN%3E%0A ;
chomp $Summary;
print "Name: ";
$Name = ;
chomp $Name;
print "Version: ";
$Version = ;
chomp $Version;
print "Release: ";
$Release = ;
chomp $Release;
print "License: ";
$License = ;
chomp $License;
$Group = 'Application/Production';
$ARCH = `uname -i`;
chomp $ARCH;

$FileOutput = "$Name" . "-" . "$Version" . "-" . "$Release" . "\." . "$ARCH" . "\.spec";

open(SpecFile, ">$FileOutput");
print SpecFile "Name: $Name\n";
print SpecFile "Summary: $Summary\n";
print SpecFile "Version: $Version\n";
print SpecFile "Release: $Release\n";
print SpecFile "License: $License\n";
print SpecFile "Group: $Group\n";
print SpecFile "Source: $TarPackage\n";
print SpecFile "Requires: /bin/sh\n";
print SpecFile "\%Description\n";
print SpecFile "The following is $Name version $Version\n";
print Specfile "\n\%prep\n";
print SpecFile "\n\%setup\n";
print SpecFile "\n\%files\n";

for $_ (@FileList)
{
$_ =~ s:^/::;
print SpecFile "$ExtractTo$_";
}
print SpecFile"\n\%post\n";
close(Specfile);

system("cp $FileOutput /usr/src/redhat/SPECS");
system("cp $TarPackage /usr/src/redhat/SOURCES");
system("rpmbuild --buildroot=$BuildRoot -bb /usr/src/redhat/SPECS/$FileOutput");
print "Cleaning up ...\n";
system("rm -rf $BuildRoot");