How to configure local customised repository for zypper based installation in SuSE Enterprise Linux

Earlier I had written an article with a detailed step-by-step guide to create autoyast.xml for automated scratch installation of SLES 11 and SLES 12.

Step by Step Guide to create autoyast xml file for SuSE Linux (SLES) with examples

In this article, I will show the detailed steps to create a custom repository for SuSE Linux Enterprise Linux.

Generate GPG Key

Before starting, you will need a GPG key which will be used to sign the content of the repository. If you already have an existing GPG key, then you can ignore this section. Otherwise, create a new GPG key for your custom repository.

NOTE: Here the highlighted sections are the input values which must be given for creating a key. You can provide different input based on your requirement.

gpg --gen-key

Example output:

gpg (GnuPG) 2.0.9; Copyright (C) 2008 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) DSA and Elgamal (default)
   (2) DSA (sign only)
   (5) RSA (sign only)
Your selection? 5

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

You need a user ID to identify your key; the software constructs the user ID from the Real Name, Comment and Email Address in this form:
    "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"

Real name: Deepak Prasad (GoLinuxHub)
Email address: golinuxhub1@gmail.com
Comment: This is a test Key

You selected this USER-ID:
    "Deepak Prasad (GoLinuxHub) (This is a test Key) <golinuxhub1@gmail.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

You will be asked to enter and confirm a passphrase for the key.

After the key is generated successfully, verify the available keys on your node:

gpg --list-keys

Example output:

/root/.gnupg/pubring.gpg
------------------------
pub   1024D/9C800ACA 2000-10-19 [expired: 2018-03-17]
uid                  SuSE Package Signing Key <build@suse.de>

pub   1024R/307E3D54 2006-03-21 [expired: 2018-03-17]
uid                  SuSE Package Signing Key <build@suse.de>

pub   2048R/39DB7C82 2013-01-31 [expired: 2017-01-30]
uid                  SuSE Package Signing Key <build@suse.de>

pub   4096R/031D26CD 2018-06-21
uid                  Deepak Prasad (GoLinuxHub) (This is a test Key) <golinuxhub1@gmail.com>

Here 031D26CD is the GPG key ID which we will use for signing the contents of the repository.

Create a text file with passphrase

Next create a plain text file with the passphrase which was used for the respective GPG key ID.

echo "mypassw0rd" > /tmp/password

This will be used at a later stage.

Create directory structure

For this article I will create my directory structure under /tmp/deeprasa for the custom SuSE repository.

Make sure below RPM is installed on your node: inst-source-utils.

You can download and install it using zypper or rpm.

Next navigate inside the directory where you want to create the repository structure.

cd /tmp/deeprasa
create_update_source.sh .

Example output:

Creating ./updates..
/EXTRA_PROV not found, trying to find it elsewhere...
INFO:    datadirs       : ./updates/
INFO:    languages      : english
INFO:    output dir     : ./updates/
WARNING: extra_provides : file ./updates//EXTRA_PROV not found!
INFO:    processed 0 packages in 1 volumes
INFO:    now recoding to UTF-8: packages packages.DU packages.en

This will create the below structure:

ls -l *

Example output:

updates:
total 20
-rw-r--r-- 1 root root    0 Jun 21 11:12 content
-rw-r--r-- 1 root root   42 Jun 21 11:12 directory.yast
drwxr-xr-x 2 root root 4096 Jun 21 11:12 media.1
-rw-r--r-- 1 root root   10 Jun 21 11:12 packages
-rw-r--r-- 1 root root   10 Jun 21 11:12 packages.DU
-rw-r--r-- 1 root root   10 Jun 21 11:12 packages.en

yast:
total 8
-rw-r--r-- 1 root root 11 Jun 21 11:12 instorder
-rw-r--r-- 1 root root 20 Jun 21 11:12 order

Copy the RPMs for the custom repository

Next create directories under /tmp/deeprasa/updates where you will copy all the RPMs.

cd /tmp/deeprasa/updates
mkdir -p suse/x86_64 suse/i686 suse/noarch

My RPMs are present inside /tmp/rpms.

cp -av /tmp/rpms/ suse/x86_64/

Example output:

`/tmp/rpms/' -> `suse/x86_64/rpms'
`/tmp/rpms/bash-doc-3.2-147.35.1.x86_64.rpm' -> `suse/x86_64/rpms/bash-doc-3.2-147.35.1.x86_64.rpm'
`/tmp/rpms/bash-3.2-147.35.1.x86_64.rpm' -> `suse/x86_64/rpms/bash-3.2-147.35.1.x86_64.rpm'
`/tmp/rpms/bind-9.9.6P1-0.39.1.x86_64.rpm' -> `suse/x86_64/rpms/bind-9.9.6P1-0.39.1.x86_64.rpm'
`/tmp/rpms/bind-chrootenv-9.9.6P1-0.39.1.x86_64.rpm' -> `suse/x86_64/rpms/bind-chrootenv-9.9.6P1-0.39.1.x86_64.rpm'

Create necessary files

Once all the RPMs are copied, next it is time to create all other necessary files and directories which are needed for the repository.

cd /tmp/deeprasa/updates/suse
create_package_descr -x setup/descr/EXTRA_PROV -C

Example output:

INFO:    datadirs       : .
INFO:    languages      : english
INFO:    output dir     : ./setup/descr/
WARNING: extra_provides : file setup/descr/EXTRA_PROV not found!
INFO:    creating output directory ./setup/descr/
INFO:    processed 8 packages in 1 volumes
INFO:    now recoding to UTF-8: packages packages.DU packages.en

Next create the MD5SUMS file which will contain md5sum values of all the available RPMs.

create_md5sums ./

Example output:

INFO:   created MD5SUMS in /tmp/deeprasa/updates/suse/./setup/descr
INFO:   created MD5SUMS in /tmp/deeprasa/updates/suse/./x86_64

Below is my MD5SUMS file for the list of RPMs:

cat MD5SUMS

Example output:

8b29f664006cab0187d18647e22dea87  bash-3.2-147.35.1.x86_64.rpm
d1d426cd61af5ee8ee971ea61418d023  bash-doc-3.2-147.35.1.x86_64.rpm
26f0829b54d2b8260c1c0f5efb7ac3d1  bind-9.9.6P1-0.39.1.x86_64.rpm
a3450462b957602502b85d21bcbf38c8  bind-chrootenv-9.9.6P1-0.39.1.x86_64.rpm

Next create a file with the content of setup/descr as shown below:

cd ../setup/descr/
ls > directory.yast
ls -l

Example output:

total 24
-rw-r--r-- 1 root root  135 Jun 21 11:41 MD5SUMS
-rw-r--r-- 1 root root   56 Jun 21 11:44 directory.yast
-rw-r--r-- 1 root root 4927 Jun 21 11:40 packages
-rw-r--r-- 1 root root 1766 Jun 21 11:40 packages.DU
-rw-r--r-- 1 root root 1684 Jun 21 11:40 packages.en

Next create SHA1 sums:

cd /tmp/deeprasa/updates/
create_sha1sums -x -n .

I will use the default header as I had in my DVD for the columns under content.

sed -i '1iVENDOR        SUSE LINUX Products GmbH, Nuernberg, Germany' /tmp/deeprasa/updates/content

This will populate your content file as shown below:

cat content

Example output:

VENDOR        SUSE LINUX Products GmbH, Nuernberg, Germany
META SHA1 1206b18fb0b70c36ef39a1b2e9f105488836e42a  packages
META SHA1 1206b18fb0b70c36ef39a1b2e9f105488836e42a  packages.DU
META SHA1 1206b18fb0b70c36ef39a1b2e9f105488836e42a  packages.en

Assign GPG

Here our GPG key ID is 031D26CD, which we created at the first stage of this article.

cd /tmp/deeprasa/updates/media.1
gpg --local-user 031D26CD -b --sign --armor --passphrase-file /tmp/password --batch products
gpg --local-user 031D26CD --export --armor > products.key
ls > directory.yast

NOTE: Here /tmp/password contains the passphrase assigned to the GPG key.

Next repeat the same for content:

cd /tmp/deeprasa/updates/
gpg --local-user 031D26CD -b --sign --armor --passphrase-file /tmp/password --batch content
gpg --local-user 031D26CD --export --armor > content.key

These will create:

-rw-r--r-- 1 root root  197 Jun 21 14:36 products.asc
-rw-r--r-- 1 root root 5541 Jun 21 14:36 products.key

and:

-rw-r--r-- 1 root root  197 Jun 21 14:36 content.asc
-rw-r--r-- 1 root root 5541 Jun 21 14:37 content.key

respectively.

Create archive of the repo

I will navigate to the directory where my repository exists and create test_repo.tgz.

cd /tmp/deeprasa/updates
tar -czvf ../test_repo.tgz *

Example output:

content
content.asc
content.key
directory.yast
media.1/
media.1/products.asc
media.1/products.key
media.1/media
media.1/products
media.1/directory.yast
packages
packages.DU
packages.en
suse/
suse/setup/
suse/setup/descr/
suse/setup/descr/directory.yast
suse/setup/descr/packages
suse/setup/descr/packages.en
suse/setup/descr/MD5SUMS
suse/setup/descr/packages.DU
suse/x86_64/
suse/x86_64/bash-doc-3.2-147.35.1.x86_64.rpm
suse/x86_64/bash-3.2-147.35.1.x86_64.rpm
suse/x86_64/MD5SUMS
suse/x86_64/bind-9.9.6P1-0.39.1.x86_64.rpm
suse/x86_64/bind-chrootenv-9.9.6P1-0.39.1.x86_64.rpm

So here our repository structure is complete. You can archive this and use it for installation via zypper.

Validate the repo

I will copy the archive I created above to my test setup where we will validate the repository using zypper.

Below is my setup detail:

180.144.62.60 -> NFS Server
180.144.62.61 -> NFS Client

So I will be creating a repository on my NFS client while the archive will be extracted on the server.

On Server

mkdir /tmp/repo && cd /tmp/repo
tar -xzvf test_repo.tgz

Below is the extracted content:

ls -l

Example output:

total 1108
-rw-r--r-- 1 root root   248 Jun 21  2018 content
-rw-r--r-- 1 root root   197 Jun 21  2018 content.asc
-rw-r--r-- 1 root root  5541 Jun 21  2018 content.key
-rw-r--r-- 1 root root    42 Jun 21  2018 directory.yast
drwxr-xr-x 2 root root  4096 Jun 21  2018 media.1
-rw-r--r-- 1 root root    10 Jun 21  2018 packages
-rw-r--r-- 1 root root    10 Jun 21  2018 packages.DU
-rw-r--r-- 1 root root    10 Jun 21  2018 packages.en
drwxr-xr-x 4 root root  4096 Jun 21  2018 suse

On Client

Now on the client side I will create a repository with an alias test_repo.

zypper addrepo nfs://180.144.62.160/tmp/repo test_repo

Example output:

Adding repository 'test_repo' [done]
Repository 'test_repo' successfully added
Enabled: Yes
Autorefresh: No
GPG check: Yes
URI: nfs://180.144.62.160/tmp/repo

Our repository is successfully created.

Let us check the available packages:

zypper pa

Example output:

Building repository 'test_repo' cache [done]
Loading repository data...
Reading installed packages...

S | Repository | Name           | Version        | Arch
--+------------+----------------+----------------+-------
v | test_repo  | bash           | 3.2-147.35.1   | x86_64
v | test_repo  | bash-doc       | 3.2-147.35.1   | x86_64
  | test_repo  | bind           | 9.9.6P1-0.39.1 | x86_64
  | test_repo  | bind-chrootenv | 9.9.6P1-0.39.1 | x86_64

So all looks good. I hope the article was useful.