There’s one aspect of CentOS’s binary compatibility with Red Hat that’s probably overlooked by a lot of sysadmins. Because the packages have a 1:1 relationship‡ between the two distributions, it’s possible to crossgrade from one to the other without much trouble.
Why would anyone want to do that, you might ask? There have been two cases in which I’ve made the switch:
- A Red Hat system’s subscription is expired, and it’s just not worth paying to continue it. Moving to CentOS allows you to continue to get patches.
- A system installed as CentOS is added to a RHN Satellite (or perhaps even RHN itself), and CentOS isn’t a supported distribution. With crossgrading, there’s not much sense in carrying the redundancy of both distros on the Satellite.
Making the switch
Crossgrading is surprisingly simple. The key to the switch is in the <distro>-release package. For CentOS, that’s centos-release, and redhat-release for RHEL. To move from one to the other, you basically just install that package.
As you’ll find when you try to install that package, some really important packages depend on the /etc/redhat-release file that it installs. Well… just one package - initscripts. But the the kernel (among others) depends on that one. To get around the conflicts raised, just use the “--force” argument to RPM.
Step-by-step
From Red Hat Enterprise Linux to CentOS
- Examine the contents of /etc/redhat-release and note the release you’re running. For example, redhat-release-5Server-5.4.0.3 = release 5.4.
- Note your system architecture. You can find this by running
uname -i
- Locate the appropriate redhat-release package. For example, on Red Hat 5.4 for i386, the package will be named like
redhat-release-5Server-5.4.N.N.i386.rpm. You can ignore the two trailing dotted numbers.
- Disable your RHN registration (this applies to Satellite clients too). chkconfig rhnsd off; service rhnsd stop. You may also need to remove the system profile from RHN/Satellite.
- Clear the yum cache.
yum clean all
- Install the package:
rpm -ivh --force redhat-release-5Server-5.N.N.N.i386.rpm
- Note that the base CentOS software repositories have been configured in /etc/yum.repos.d/CentOS-Base.repo.
From CentOS to Red Hat Enterprise Linux
- Examine the contents of /etc/redhat-release and note the release you’re running. For example, CentOS release 5.2 (Final) = release 5.2.
- Note your system architecture. You can find this by running
uname -i
- Locate the appropriate redhat-release package. For example, on CentOS 5.3 for i386, the package will be named like redhat-release-5Server-5.3.N.N.i386.rpm. You can ignore the two trailing dotted numbers.
- Clear the yum cache.
yum clean all
- Disable your base software repositories (
cd /etc/yum.repos.d; mv CentOS-Base.repo CentOS-Base.repo.disabled).
- Install the package:
rpm -ivh --force redhat-release-5Server-5.N.N.N.i386.rpm
Registering a crossgraded system to RHN/Satellite
- Create a directory named rhn-packages
- Into rhn-packages, Download the latest versions of these packages for your system architecture:
- Install the Red Hat package signing key http://www.redhat.com/security/37017186….) and import it.
rpm --import 37017186.txt
- Change directories into rhn-packages and install all the packages you’ve downloaded.
rpm -Uvh *.rpm. The command yum localinstall *.rpm may be a helpful alternative command if you run into dependency problems.
- Xen domUs (and maybe only to PVMs) appear to be lacking an smbios capability that the RHN client expects. The workaround:
- Edit the file /usr/share/rhn/up2date_client/capabilities.py
- Locate the neededCaps dictionary
- Locate the registration.smbios key
- Set version to 0 (from 1)
- Follow the usual process for registering your system to RHN or Satellite.
‡ Versus a one-to-many relationship. There are packages that are included/omitted from one or the other distro. Most notably, CentOS does not, as of this writing, include the RHN client packages.
Categories: System Administration
Tagged: centos rhel crossgrade
Note for the impatient: The fruit of my labor, a python program called rpmrebuild is available for download.
The problem
If you’ve ever tried to deploy others’ RPMs via Satellite, Yum, or probably any update manager, you know that sometimes it’s just impossible to get their signatures to verify, even with the vendor’s GPG key installed. In most of these cases, re-signing the RPM with your own key doesn’t even help. With Yum, you can turn off signature checking (arguably a bad idea), but on RHN Satellite, there’s no way around it except to install the packages manually.
Normally this isn’t so bad, but as I was working on a three-stage application hosting environment, I realized that this completely breaks the “Package Profile” feature of Satellite because some of the installed packages won’t be available in any channel. In order to create a reproducible, identical system build without a lot of extra steps, I had to find a way to get the VMwareTools package to work with Satellite.
Fixing the existing packages
I decided to try something I’d suspected was possible for a while, but had never looked into: rebuild the binary RPMs. I’ve only recently really learned how to build RPMs at all. Part of that process was to learn a lot more about what goes into an RPM. It’s really just a combination of three things: files (the package contents), installation/removal scripts, and metadata.
I knew I could get at the files, as I’d used rpm2cpio to extract individual package components before. I’d also poked around at a few packages with the rpm command’s - -query-format argument, so I knew there was a clean way to get at all of the metadata. With a specfile template and the output of rpm - -querytags in hand, I set out to make an automated package rebuilder.
Tearing it apart
You need two things to build an RPM: a) a spec file containing the package metadata, installation procedures, and a description of the build process and b) the source files for the package. I had the source files — the binary RPM — so all there was to do was to reverse-engineer a spec file. Here’s how to extract what you need from the RPM.
- Get the files out of the package using rpm2cpio
- Gather the required package metadata using rpm -qp - -qf=”%{TAG}” package.rpm. The following items are required in the spec file, so this is what I extracted.
- Package name (NAME)
- Package version (VERSION)
- Package release (RELEASE)
- Summary (SUMMARY)
- Vendor (VENDOR)
- Description (DESCRIPTION)
- Software group (GROUP)
- License (LICENSE)
- Extract the pre (PREIN), post (POSTIN), preun (PREUN), and postun (POSTUN) scripts using the same queryformat argument to rpm.
- Extract the package dependencies and provides using - -provides and - -requires
- Extract the file list, complete with permissions, owners, groups, and flags (%dir, %config, %doc). This was tricky, and required knowledge about array iterators in rpm.
Once you have all of this information, you’re ready to build a spec file and remake the RPM
Putting it back together
Now that you have the information for a complete spec file, you can automate the rebuild process just like you would a normal RPM build. Most of the information you’ve gathered will go directly into the applicable spots in the spec file. Here are some helpful hints for building that file.
- Turn off automatic stripping of installed binaries
- %define __spec_install_port /usr/lib/rpm/brp-compress
- %define __os_install_post /usr/lib/rpm/brp-compress
- Turn off automatic dependency and provides generation
- %define __find_requires %{nil}
- %define __find_provides %{nil}
- AutoReqProv: no
- Copy the source RPM to your rpmbuild %{_sourcedir} and name it in a SOURCEN line
- In %setup, extract the package contents to a folder in your %{_builddir} using rpm2cpio
- %build can be empty
- In %install, extract the cpio archive to the %{buildroot}
- Rather than use %defattr and try to group together files with the same permissions, add a %attr prefix to each line based on the file list you extracted.
- Unless you know you’ll need tight permissions on a directory, you can mostly omit directories from the list if a file inside the directory is also listed. Add a %dir prefix to empty directory entries.
The easy way
If this overview wasn’t quite detailed enough for you, take the easy way out and just download the python program I wrote to automate this process. You’ll need a working rpmbuild environment and Python 2.4, but there are no other requirements (for Python < 2.4, see the comments). Just run rpmrebuild package-to-rebuild.rpm and watch it go. The output will be in the usual RPMS/<arch> directory of your build environment.
Categories: How-to · System Administration
Tagged: python, rpm