Add COPR support to states.pkgrepo (#57259)

This commit is contained in:
Brendan Early 2020-09-20 11:04:47 -05:00 committed by Daniel Wozniak
parent 1c64b8a841
commit 59c9983105
4 changed files with 160 additions and 18 deletions

1
changelog/57258.added Normal file
View file

@ -0,0 +1 @@
Added COPR option to states.pkgrepo

View file

@ -107,6 +107,12 @@ def _strip_headers(output, *args):
return ret
def _get_copr_repo(copr):
copr = copr.split(":", 1)[1]
copr = copr.split("/", 1)
return "copr:copr.fedorainfracloud.org:{}:{}".format(copr[0], copr[1])
def _get_hold(line, pattern=__HOLD_PATTERN, full=True):
"""
Resolve a package name from a line containing the hold expression. If the
@ -2720,7 +2726,7 @@ def list_repos(basedir=None, **kwargs):
return repos
def get_repo(name, basedir=None, **kwargs): # pylint: disable=W0613
def get_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613
"""
Display a repo from <basedir> (default basedir: all dirs in ``reposdir``
yum option).
@ -2735,16 +2741,19 @@ def get_repo(name, basedir=None, **kwargs): # pylint: disable=W0613
"""
repos = list_repos(basedir)
if repo.startswith("copr:"):
repo = _get_copr_repo(repo)
# Find out what file the repo lives in
repofile = ""
for repo in repos:
if repo == name:
repofile = repos[repo]["file"]
for list_repo in repos:
if list_repo == repo:
repofile = repos[list_repo]["file"]
if repofile:
# Return just one repo
filerepos = _parse_repo_file(repofile)[1]
return filerepos[name]
return filerepos[repo]
return {}
@ -2764,6 +2773,10 @@ def del_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613
salt '*' pkg.del_repo myrepo basedir=/path/to/dir
salt '*' pkg.del_repo myrepo basedir=/path/to/dir,/path/to/another/dir
"""
if repo.startswith("copr:"):
repo = _get_copr_repo(repo)
# this is so we know which dirs are searched for our error messages below
basedirs = _normalize_basedir(basedir)
repos = list_repos(basedirs)
@ -2856,6 +2869,12 @@ def mod_repo(repo, basedir=None, **kwargs):
"Only one of 'mirrorlist' and 'baseurl' can be specified"
)
use_copr = False
if repo.startswith("copr:"):
copr_name = repo.split(":", 1)[1]
repo = _get_copr_repo(repo)
use_copr = True
# Build a list of keys to be deleted
todelete = []
# list() of keys because the dict could be shrinking in the for loop.
@ -2897,20 +2916,47 @@ def mod_repo(repo, basedir=None, **kwargs):
"of the following basedir directories exist: {0}".format(basedirs)
)
repofile = "{0}/{1}.repo".format(newdir, repo)
if use_copr:
# Is copr plugin installed?
copr_plugin_name = ""
if _yum() == "dnf":
copr_plugin_name = "dnf-plugins-core"
else:
copr_plugin_name = "yum-plugin-copr"
if "name" not in repo_opts:
raise SaltInvocationError(
"The repo does not exist and needs to be created, but a name "
"was not given"
)
if not __salt__["pkg_resource.version"](copr_plugin_name):
raise SaltInvocationError(
"{} must be installed to use COPR".format(copr_plugin_name)
)
if "baseurl" not in repo_opts and "mirrorlist" not in repo_opts:
raise SaltInvocationError(
"The repo does not exist and needs to be created, but either "
"a baseurl or a mirrorlist needs to be given"
)
filerepos[repo] = {}
# Enable COPR
out = _call_yum(["copr", "enable", copr_name, "-y"])
if out["retcode"]:
raise CommandExecutionError(
"Unable to add COPR '{0}'. '{1}' exited with "
"status {2!s}: '{3}' ".format(
copr_name, _yum(), out["retcode"], out["stderr"]
)
)
# Repo has been added, update repos list
repos = list_repos(basedirs)
repofile = repos[repo]["file"]
header, filerepos = _parse_repo_file(repofile)
else:
repofile = "{0}/{1}.repo".format(newdir, repo)
if "name" not in repo_opts:
raise SaltInvocationError(
"The repo does not exist and needs to be created, but a name "
"was not given"
)
if "baseurl" not in repo_opts and "mirrorlist" not in repo_opts:
raise SaltInvocationError(
"The repo does not exist and needs to be created, but either "
"a baseurl or a mirrorlist needs to be given"
)
filerepos[repo] = {}
else:
# The repo does exist, open its file
repofile = repos[repo]["file"]

View file

@ -83,6 +83,14 @@ package managers are APT, DNF, YUM and Zypper. Here is some example SLS:
installed. To check if this package is installed, run ``dpkg -l python-apt``.
``python-apt`` will need to be manually installed if it is not present.
.. code-block:: yaml
hello-copr:
pkgrepo.managed:
- copr: mymindstorm/hello
pkg.installed:
- name: hello
"""
# Import Python libs
@ -111,7 +119,7 @@ def __virtual__():
return "pkg.mod_repo" in __salt__
def managed(name, ppa=None, **kwargs):
def managed(name, ppa=None, copr=None, **kwargs):
"""
This state manages software package repositories. Currently, :mod:`yum
<salt.modules.yumpkg>`, :mod:`apt <salt.modules.aptpkg>`, and :mod:`zypper
@ -141,6 +149,12 @@ def managed(name, ppa=None, **kwargs):
reverse will be passed as ``enabled``. For example passing
``disabled=True`` will assume ``enabled=False``.
copr
Fedora and RedHat based distributions only. Use community packages
outside of the main package repository.
.. versionadded:: 3002
humanname
This is used as the "name" value in the repo file in
``/etc/yum.repos.d/`` (or ``/etc/zypp/repos.d`` for SUSE distros).
@ -369,6 +383,11 @@ def managed(name, ppa=None, **kwargs):
)
elif __grains__["os_family"] in ("RedHat", "Suse"):
if __grains__["os_family"] in "RedHat":
if copr is not None:
repo = ":".join(("copr", copr))
kwargs["name"] = name
if "humanname" in kwargs:
kwargs["name"] = kwargs.pop("humanname")
if "name" not in kwargs:
@ -550,6 +569,19 @@ def absent(name, **kwargs):
The name of the package repo, as it would be referred to when running
the regular package manager commands.
**FEDORA/REDHAT-SPECIFIC OPTIONS**
copr
Use community packages outside of the main package repository.
.. versionadded:: 3002
.. code-block:: yaml
hello-copr:
pkgrepo.absent:
- copr: mymindstorm/hello
**UBUNTU-SPECIFIC OPTIONS**
ppa
@ -596,6 +628,11 @@ def absent(name, **kwargs):
if not name.startswith("ppa:"):
name = "ppa:" + name
if "copr" in kwargs and __grains__["os_family"] in "RedHat":
name = kwargs.pop("copr")
if not name.startswith("copr:"):
name = "copr:" + name
remove_key = any(kwargs.get(x) is not None for x in ("keyid", "keyid_ppa"))
if remove_key and "pkg.del_repo_key" not in __salt__:
ret["result"] = False

View file

@ -266,3 +266,61 @@ class PkgrepoTest(ModuleCase, SaltReturnAssertsMixin):
os.remove(fn_)
except OSError:
pass
@requires_salt_states("pkgrepo.absent", "pkgrepo.managed")
@requires_system_grains
@slowTest
def test_pkgrepo_05_copr_with_comments(self, grains):
"""
Test copr
"""
kwargs = {}
if grains["os_family"] == "RedHat":
if (
grains["osfinger"] == "CentOS Linux-7"
or grains["osfinger"] == "Amazon Linux-2"
):
self.skipTest("copr plugin not installed on Centos 7 CI")
kwargs = {
"name": "hello-copr",
"copr": "mymindstorm/hello",
"enabled": False,
"comments": ["This is a comment"],
}
else:
self.skipTest(
"{}/{} test case needed".format(grains["os_family"], grains["os"])
)
try:
# Run the state to add the repo
ret = self.run_state("pkgrepo.managed", **kwargs)
self.assertSaltTrueReturn(ret)
# Run again with modified comments
kwargs["comments"].append("This is another comment")
ret = self.run_state("pkgrepo.managed", **kwargs)
self.assertSaltTrueReturn(ret)
ret = ret[next(iter(ret))]
self.assertEqual(
ret["changes"],
{
"comments": {
"old": ["This is a comment"],
"new": ["This is a comment", "This is another comment"],
}
},
)
# Run a third time, no changes should be made
ret = self.run_state("pkgrepo.managed", **kwargs)
self.assertSaltTrueReturn(ret)
ret = ret[next(iter(ret))]
self.assertFalse(ret["changes"])
self.assertEqual(
ret["comment"],
"Package repo '{0}' already configured".format(kwargs["name"]),
)
finally:
# Clean up
self.run_state("pkgrepo.absent", copr=kwargs["copr"])