Create completely offline Ansible Tower bundle installation

Ansible

Updated on March, 2021 as Ansible Tower installation has changed since this blog was originally posted. This blog was updated using Ansible Tower 3.8.x but the next iteration of Ansible Tower will be changing again. So please read the warning in this blog!

Ansible Tower installation package exists in two forms: (1) online setup, and (2) offline bundled setup. However the bundled package, still depends on OS-based repositories for specific OS dependencies. These packages cannot be included into the bundle because it would have to include all packages for each and every OS version (RHEL 8.0, 8.1, 8.3, etc). That would be redundant to duplicate all of that information. The assumption is that you have a mirror of these repositories that are accessible from your server infrastructure. Optimally, this is handled by Red Hat Satellite!

However, I have still received a number of requests for packaging a true offline Ansible Tower install. Some customers still have specific situations that for various reasons have their servers in complete “offline” mode with no access to internet and no access to an intranet mirror repository.

This article shows you how to prepare a true “offline” Ansible Tower installation that includes every dependent package for your specific OS version.

WARNING: Ansible Tower installation package has changed since this blog was originally written. It is now much more complicated to attempt to gather all package dependencies. In fact I would argue it’s truly not worth it. In this day and age, it should always be possible to connect your servers to official OS repositories (RHEL for example) as these repos have been highly vetted and are used worldwide. If you do not have access to these repositories, you can still download the ISO and mount it to the servers. Therefore, this blog has been changed as a reflection of this opinion.

Why?

It’s an important question to ask yourself! As stated above, Ansible Tower can be easily installed as long as you have the standard required repositories available. For example, for RHEL8:

> yum repolist
Updating Subscription Management repositories.
repo id                                                                 repo name
rhel-8-for-x86_64-appstream-rpms                                        Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
rhel-8-for-x86_64-baseos-rpms                                           Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)

Again, it is not recommended anymore to prepare a completely offline installation package. However, below are some tips if you wish to attempt this.

Warning… these steps are not complete and not guaranteed.

Prepare Machine

I use Vagrant for this since it’s the quickest way to startup a machine for testing purposes.

The following commands gets you started quickly:

# Initialize vagrant box
vagrant init generic/rhel8
# Ensure you have the latest box version
vagrant box upgrade
# Start the machine
vagrant up
# Login to the machine
vagrant ssh

# Escalate to root access
sudo su -
# Download latest version of Ansible Tower bundle package
wget https://releases.ansible.com/ansible-tower/setup-bundle/ansible-tower-setup-bundle-latest.tar.gz

Prepare Repositories

As stated, the bundled package still needs access to OS specific repositories. The Vagrant box includes them as a result of registering subscription-manager. These are the required repositories:

> yum repolist
Updating Subscription Management repositories.
repo id                                                                 repo name
rhel-8-for-x86_64-appstream-rpms                                        Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)
rhel-8-for-x86_64-baseos-rpms                                           Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)

If you have these repositories, then you are good and can move on to the next step.

If you do not have access to these repositories for some reason, you will need to download the ISO for your OS version, push it to the vagrant box and mount it so you can create the repositories to point to the ISO content.

  • Download ISO from Red Hat
  • Copy ISO file to machine using scp or vagrant-scp plugin

      # Copy ISO to machine
      vagrant scp rhel-8.3-x86_64-dvd.iso default:/tmp/rhel-8.3-x86_64-dvd.iso
    
  • Mount and create repositories using similar instructions as noted in this solution

    Note that for RHEL 8 ISO, there are actually two repositories (not just one) for AppStream and BaseOS so you would need to create two repo definitions under /etc/yum.repos.d/ path.

Prepare Tower

Now let’s prepare the Ansible Tower installation folder.

  • Unpack the Ansible Tower bundle

      cd ~
      tar -xvf ansible-tower-setup-bundle-*.tar.gz
    
  • Modify the Inventory (optional)

    We only need to set the passwords and nothing else! Set them to password because you will eventually package this folder and use it for future installs.

      # Edit the inventory
      cd ansible-tower-setup-bundle-*
      vi inventory
    
      # Set the following to 'password'
      admin_password='password'
      pg_password='password'
      automationhub_admin_password='password'
      automationhub_pg_password='password'
    

Download Packages

The packages we will need are listed in the ansible-tower-setup-bundle-*/bundle/el8/base_packages.txt file located within the Ansible Tower installation folder. Note that the file exists under both el8 and el7 folders as they require different packages.

> find . -name "base_packages.txt"
./bundle/el7/base_packages.txt
./bundle/el8/base_packages.txt

However the package names use nevra (name-epoch:version-release.architecture) format - see below example. While yum/dnf supports installing packages using the nevra format, we may not have all of these exact same versions available in our specific repositories.

> tail ./bundle/el8/base_packages.txt
xmlsec1-0:1.2.25-4.el8.x86_64
xmlsec1-openssl-0:1.2.25-4.el8.i686
xmlsec1-openssl-0:1.2.25-4.el8.x86_64
xorg-x11-font-utils-1:7.5-40.el8.x86_64
xorg-x11-server-utils-0:7.7-27.el8.x86_64
xz-0:5.2.4-3.el8.x86_64
xz-libs-0:5.2.4-3.el8.i686
xz-libs-0:5.2.4-3.el8.x86_64
zlib-0:1.2.11-17.el8.i686
zlib-0:1.2.11-17.el8.x86_64

So we will use a small Python script to help us extract the package name element of the nevra format and create a new package file that can be used by yumdownloader tool.

Let us first prepare the folder where the extra packages will be downloaded. Since I’m dealing with a RHEL8 system, I navigate inside the EL8 folder - you might need EL7.

# Navigate again inside the tower bundle folder
cd ~/ansible-tower-setup-bundle-*
# Create new repo folder inside the bundle repos folder
mkdir bundle/el8/repos/others
# Navigate to the new folder
cd bundle/el8/repos/others

Save the following Python script as convert.py inside the others folder. It basically takes a filename as argument and outputs the names of the packages. It will help us convert the base_packages.txt to something usable for yumdownloader. (You can also elect to use version_utils)

import sys
import re

if len(sys.argv)<2:
  print("No argument provided. Exiting.")
  exit()
filename=sys.argv[1]

with open(filename) as f:
  for line in f:
    pkgname = re.split('-[0-9]*:', line)

    print(pkgname[0])

Now we just run it all and magically we will be downloading all the necessary packages into our others folder.

# Convert base_packages.txt to base.txt with only package name
cd ~/ansible-tower-setup-bundle-*/bundle/el8/repos/others
# Convert the base packages using Python script
python3 convert.py ../../base_packages.txt > base.txt
# Remove exception with `dejavu-lgc-sans-fonts` and `sshpass` packages not available in the repositories
grep -v "dejavu-lgc-sans-fonts" base.txt | grep -v "sshpass" > base_clean.txt

# Install packages to help us download locally and create a local repo
yum install yum-utils createrepo

# Download packages to local folder
yumdownloader $(cat ../base_clean.txt)

# WARNING - See warning statement below...

# Prepare local folder repository with metadata using `createrepo` tool
createrepo .

WARNING: In addition to the base_packages.txt and the downloading all dependencies for them, you may need to additionally download dependencies for the packages inside the ansible-tower-dependencies folder (try using repoquery --resolve --requires *.rpm). I noticed the setup.sh installer script creates a temporary yum repo that points to this folder to be able to install the Ansible engine required for installing Ansible Tower. Additionally, the setup.sh calls the installation playbook that performs a couple commands to enable dnf modules (nginx and postgresql) and these also required access to the OS repositories. So this is where the problems start happening and why I marked this blog with a big warning in the beginning! It gets complex and will only get worse in the following versions. So save yourself the trouble and simply attach the OS repositories. Do not attempt to find and download all package dependencies!

Now that the local repo has been prepared, we can have the Ansible Tower installer reference it during installation by adding it to the repo template file which is used to generate a yum repo file for use during installation.

cd ~/ansible-tower-setup-bundle-*
cat << EOF >> ./roles/repos_el/templates/tower_bundle.j2

[others]
name=Others
baseurl=file://{{ bundle_install_folder }}/others
enabled=1
gpgcheck=0
EOF

Re-package the bundle

That’s it! Now you can re-package your new bundle and bring it to your Data Center or wherever and simply install Ansible Tower in a completely offline situation.

Remember that this bundle will only work with the specific OS and version you used in this process! For any other OS version you will need to do this again.

# navigate to home folder
cd ~
# create tar ball of the new bundle
tar -czvf ansible-tower-bundle-offline.tar.gz ansible-tower-setup-bundle-*

If you want to test the installation, just disable all of your repos before attempting the installation. You can additionally pre-install the downloaded packages.

# Disable all repositories
yum-config-manager --disable \*

# Optional - install the packages manually on target machine
cd bundle/el8/repos/other/
yum --disablerepo=* localinstall --skip-broken *.rpm

However, for a proper test, you should destroy your vagrant machine and recreate it and use only your new bundled package to install Tower.

Good luck!