diff --git a/README.md b/README.md index 8d7e4e3..ac17efb 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,8 @@ A script to create and update mirrors of RPM repositories using `reposync`. Runs on -* RHEL 8 (and compatible) -* RHEL 9 (and compatible) - +- RHEL 8 (and compatible) +- RHEL 9 (and compatible) ## Installation @@ -57,7 +56,6 @@ setfacl --recursive --modify user:mirror:rwx "$base_path" setfacl --default --recursive --modify user:mirror:rwx "$base_path" ``` - ## How to Provide a RPM-based Repository on your Mirror Server If you want to provide an RPM-based repository, it must be present in `/etc/yum.repos.d`. However, it does not need to be enabled, so we generally recommend disabling it (to prevent the mirror server itself from accidentally using it). @@ -79,10 +77,10 @@ module_hotfixes = 1 In `/etc/mirror.yml`, set the location for the repo to be mirrored. This path should be unique to prevent multiple repos from overwriting each other. The path will then be created by the script. ```yaml -base_path: '/var/www/html/mirror' +base_path: "/var/www/html/mirror" reposync_repos: - - repoid: 'mirror-rhel8-mariadb-10.6' - relative_target_path: 'MariaDB/mariadb-10.6/yum/rhel/8/x86_64' + - repoid: "mirror-rhel8-mariadb-10.6" + relative_target_path: "MariaDB/mariadb-10.6/yum/rhel/8/x86_64" ``` Determine whether or not it is necessary to run `createrepo`. If the mirrored repo is not identical to the upstream repo (e.g. due to `includepkgs` or `excludepkgs` directives), you need to run `createrepo`. If this is not the case, you should avoid running it, as it will destroy RHEL's module information. @@ -107,12 +105,12 @@ restorecon -Fvr $BASE_PATH `reposync_repos`: Optional, list. List of repositories to mirror using `reposync`.
Subkeys: -* `repoid`: Mandatory, string. Repo-ID. Can be found using `dnf repolist`. -* `relative_target_path`: Mandatory, string. Target path where the repo should be placed, relative to `base_path`. -* `createrepo`: Optional, boolean. If `createrepo` should be ran on the repo after mirroring or not. Only use this if the mirrored repo is not idential to the upstream repo (for example due to `includepkgs` or `excludepkgs` directives). Else, you should avoid running it, since it destroys RHEL's module information. Defaults to `false`. - +- `repoid`: Mandatory, string. Repo-ID. Can be found using `dnf repolist`. +- `relative_target_path`: Mandatory, string. Target path where the repo should be placed, relative to `base_path`. +- `createrepo`: Optional, boolean. If `createrepo` should be ran on the repo after mirroring or not. Only use this if the mirrored repo is not idential to the upstream repo (for example due to `includepkgs` or `excludepkgs` directives). Else, you should avoid running it, since it destroys RHEL's module information. Defaults to `false`. +- `keep_old_rpms`: Optional, boolean. If set to `true`, the reposync command is executed without the `--delete` flag to keep older packages. Defaults to `false`. ## Exit Codes -* 0: success / config valid -* 1: failed to read config / config invalid +- 0: success / config valid +- 1: failed to read config / config invalid diff --git a/__pycache__/mirror-update_test.cpython-313.pyc b/__pycache__/mirror-update_test.cpython-313.pyc new file mode 100644 index 0000000..96f68b1 Binary files /dev/null and b/__pycache__/mirror-update_test.cpython-313.pyc differ diff --git a/example.yml b/example.yml index 45f2191..0476c6d 100644 --- a/example.yml +++ b/example.yml @@ -5,11 +5,4 @@ reposync_repos: - repoid: 'rocky8-appstream' relative_target_path: 'rocky/8/AppStream/x86_64/os/' createrepo: true - -github_repos: - - - github_user: 'maxbube' - github_repo: 'mydumper' - relative_target_path: 'mydumper/el/8' - rpm_regex: 'mydumper-{latest_version}[-\d]*.el8.x86_64.rpm' - number_of_rpms_to_keep: 3 + keep_old_rpms: false diff --git a/mirror-update b/mirror-update index 50d044d..5dc8f64 100755 --- a/mirror-update +++ b/mirror-update @@ -168,10 +168,18 @@ class MirrorUpdate: if not self.mkdir(target_path): continue - cmd = "reposync --assumeyes --delete --download-metadata --download-path='{TARGET_PATH}' --downloadcomps --newest-only --norepopath --repoid='{REPOID}'".format( + cmd_args = "--assumeyes --download-metadata --download-path='{TARGET_PATH}' --downloadcomps --newest-only --norepopath --repoid='{REPOID}'".format( REPOID=repo["repoid"], TARGET_PATH=target_path, ) + + if "keep_old_rpms" not in repo or repo["keep_old_rpms"] == False: + cmd_args = cmd_args + " --delete" + + cmd = "reposync {CMD_ARGS}".format( + CMD_ARGS=cmd_args, + ) + if not self.run_cmd(cmd): continue diff --git a/mirror-update_test.py b/mirror-update_test.py new file mode 100644 index 0000000..fdd5e89 --- /dev/null +++ b/mirror-update_test.py @@ -0,0 +1,49 @@ +import unittest + +class TestCommandBuilder(unittest.TestCase): + def test_add_delete_flag_if_not_explicitly_disabled(self): + target_path = "/test/" + repo = { + "repoid": "test" + } + + cmd_args = "--assumeyes --download-metadata --download-path='{TARGET_PATH}' --downloadcomps --newest-only --norepopath --repoid='{REPOID}'".format( + REPOID=repo["repoid"], + TARGET_PATH=target_path, + ) + + if "keep_old_rpms" not in repo or repo["keep_old_rpms"] == False: + cmd_args = cmd_args + " --delete" + + cmd = "reposync {CMD_ARGS}".format( + CMD_ARGS=cmd_args, + ) + + self.assertEqual(cmd, "reposync --assumeyes --download-metadata --download-path='{TARGET_PATH}' --downloadcomps --newest-only --norepopath --repoid='{REPOID}' --delete".format( + REPOID=repo["repoid"], + TARGET_PATH=target_path, + )) + + def test_ignore_delete_flag_if_disabled(self): + target_path = "/test/" + repo = { + "repoid": "test", + "keep_old_rpms": True + } + + cmd_args = "--assumeyes --download-metadata --download-path='{TARGET_PATH}' --downloadcomps --newest-only --norepopath --repoid='{REPOID}'".format( + REPOID=repo["repoid"], + TARGET_PATH=target_path, + ) + + if "keep_old_rpms" not in repo or repo["keep_old_rpms"] == False: + cmd_args = cmd_args + " --delete" + + cmd = "reposync {CMD_ARGS}".format( + CMD_ARGS=cmd_args, + ) + + self.assertEqual(cmd, "reposync --assumeyes --download-metadata --download-path='{TARGET_PATH}' --downloadcomps --newest-only --norepopath --repoid='{REPOID}'".format( + REPOID=repo["repoid"], + TARGET_PATH=target_path, + ))