65598582f5
OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=179
180 lines
6.8 KiB
Diff
180 lines
6.8 KiB
Diff
From 355e1e29e8f3286eeb13bc2d05089c096c9e01e3 Mon Sep 17 00:00:00 2001
|
|
From: Alexander Graul <agraul@suse.com>
|
|
Date: Mon, 18 May 2020 16:39:27 +0200
|
|
Subject: [PATCH] Add docker logout (#237)
|
|
|
|
Docker logout works analog to login. It takes none, one or more registries as
|
|
arguments. If there are no arguments, all known (specified in pillar)
|
|
docker registries are logged out of. If arguments are present, they are
|
|
interpreted as a list of docker registries to log out of.
|
|
---
|
|
salt/modules/dockermod.py | 80 ++++++++++++++++++++++++++++
|
|
tests/unit/modules/test_dockermod.py | 59 ++++++++++++++++++++
|
|
2 files changed, 139 insertions(+)
|
|
|
|
diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py
|
|
index 934038c927..176b4db926 100644
|
|
--- a/salt/modules/dockermod.py
|
|
+++ b/salt/modules/dockermod.py
|
|
@@ -1586,6 +1586,86 @@ def logout(*registries):
|
|
return ret
|
|
|
|
|
|
+def logout(*registries):
|
|
+ """
|
|
+ .. versionadded:: 3001
|
|
+
|
|
+ Performs a ``docker logout`` to remove the saved authentication details for
|
|
+ one or more configured repositories.
|
|
+
|
|
+ Multiple registry URLs (matching those configured in Pillar) can be passed,
|
|
+ and Salt will attempt to logout of *just* those registries. If no registry
|
|
+ URLs are provided, Salt will attempt to logout of *all* configured
|
|
+ registries.
|
|
+
|
|
+ **RETURN DATA**
|
|
+
|
|
+ A dictionary containing the following keys:
|
|
+
|
|
+ - ``Results`` - A dictionary mapping registry URLs to the authentication
|
|
+ result. ``True`` means a successful logout, ``False`` means a failed
|
|
+ logout.
|
|
+ - ``Errors`` - A list of errors encountered during the course of this
|
|
+ function.
|
|
+
|
|
+ CLI Example:
|
|
+
|
|
+ .. code-block:: bash
|
|
+
|
|
+ salt myminion docker.logout
|
|
+ salt myminion docker.logout hub
|
|
+ salt myminion docker.logout hub https://mydomain.tld/registry/
|
|
+ """
|
|
+ # NOTE: This function uses the "docker logout" CLI command to remove
|
|
+ # authentication information from config.json. docker-py does not support
|
|
+ # this usecase (see https://github.com/docker/docker-py/issues/1091)
|
|
+
|
|
+ # To logout of all known (to Salt) docker registries, they have to be collected first
|
|
+ registry_auth = __salt__["config.get"]("docker-registries", {})
|
|
+ ret = {"retcode": 0}
|
|
+ errors = ret.setdefault("Errors", [])
|
|
+ if not isinstance(registry_auth, dict):
|
|
+ errors.append("'docker-registries' Pillar value must be a dictionary")
|
|
+ registry_auth = {}
|
|
+ for reg_name, reg_conf in six.iteritems(
|
|
+ __salt__["config.option"]("*-docker-registries", wildcard=True)
|
|
+ ):
|
|
+ try:
|
|
+ registry_auth.update(reg_conf)
|
|
+ except TypeError:
|
|
+ errors.append(
|
|
+ "Docker registry '{0}' was not specified as a "
|
|
+ "dictionary".format(reg_name)
|
|
+ )
|
|
+
|
|
+ # If no registries passed, we will logout of all known registries
|
|
+ if not registries:
|
|
+ registries = list(registry_auth)
|
|
+
|
|
+ results = ret.setdefault("Results", {})
|
|
+ for registry in registries:
|
|
+ if registry not in registry_auth:
|
|
+ errors.append("No match found for registry '{0}'".format(registry))
|
|
+ continue
|
|
+ else:
|
|
+ cmd = ["docker", "logout"]
|
|
+ if registry.lower() != "hub":
|
|
+ cmd.append(registry)
|
|
+ log.debug("Attempting to logout of docker registry '%s'", registry)
|
|
+ logout_cmd = __salt__["cmd.run_all"](
|
|
+ cmd, python_shell=False, output_loglevel="quiet",
|
|
+ )
|
|
+ results[registry] = logout_cmd["retcode"] == 0
|
|
+ if not results[registry]:
|
|
+ if logout_cmd["stderr"]:
|
|
+ errors.append(logout_cmd["stderr"])
|
|
+ elif logout_cmd["stdout"]:
|
|
+ errors.append(logout_cmd["stdout"])
|
|
+ if errors:
|
|
+ ret["retcode"] = 1
|
|
+ return ret
|
|
+
|
|
+
|
|
# Functions for information gathering
|
|
def depends(name):
|
|
"""
|
|
diff --git a/tests/unit/modules/test_dockermod.py b/tests/unit/modules/test_dockermod.py
|
|
index 34e2e9c610..48526acb71 100644
|
|
--- a/tests/unit/modules/test_dockermod.py
|
|
+++ b/tests/unit/modules/test_dockermod.py
|
|
@@ -199,6 +199,65 @@ class DockerTestCase(TestCase, LoaderModuleMockMixin):
|
|
output_loglevel="quiet",
|
|
)
|
|
|
|
+ def test_logout_calls_docker_cli_logout_all(self):
|
|
+ client = Mock()
|
|
+ get_client_mock = MagicMock(return_value=client)
|
|
+ ref_out = {"stdout": "", "stderr": "", "retcode": 0}
|
|
+ registry_auth_data = {
|
|
+ "portus.example.com:5000": {
|
|
+ "username": "admin",
|
|
+ "password": "linux12345",
|
|
+ "email": "tux@example.com",
|
|
+ },
|
|
+ "portus2.example.com:5000": {
|
|
+ "username": "admin",
|
|
+ "password": "linux12345",
|
|
+ "email": "tux@example.com",
|
|
+ },
|
|
+ }
|
|
+
|
|
+ docker_mock = MagicMock(return_value=ref_out)
|
|
+ with patch.object(docker_mod, "_get_client", get_client_mock):
|
|
+ dunder_salt = {
|
|
+ "config.get": MagicMock(return_value=registry_auth_data),
|
|
+ "cmd.run_all": docker_mock,
|
|
+ "config.option": MagicMock(return_value={}),
|
|
+ }
|
|
+ with patch.dict(docker_mod.__salt__, dunder_salt):
|
|
+ ret = docker_mod.logout()
|
|
+ assert "retcode" in ret
|
|
+ assert ret["retcode"] == 0
|
|
+ assert docker_mock.call_count == 2
|
|
+
|
|
+ def test_logout_calls_docker_cli_logout_single(self):
|
|
+ client = Mock()
|
|
+ get_client_mock = MagicMock(return_value=client)
|
|
+ ref_out = {"stdout": "", "stderr": "", "retcode": 0}
|
|
+ registry_auth_data = {
|
|
+ "portus.example.com:5000": {
|
|
+ "username": "admin",
|
|
+ "password": "linux12345",
|
|
+ "email": "tux@example.com",
|
|
+ }
|
|
+ }
|
|
+ docker_mock = MagicMock(return_value=ref_out)
|
|
+ with patch.object(docker_mod, "_get_client", get_client_mock):
|
|
+ dunder_salt = {
|
|
+ "config.get": MagicMock(return_value=registry_auth_data),
|
|
+ "cmd.run_all": docker_mock,
|
|
+ "config.option": MagicMock(return_value={}),
|
|
+ }
|
|
+ with patch.dict(docker_mod.__salt__, dunder_salt):
|
|
+ ret = docker_mod.logout("portus.example.com:5000")
|
|
+ assert "retcode" in ret
|
|
+ assert ret["retcode"] == 0
|
|
+ docker_mock.assert_called_with(
|
|
+ ["docker", "logout", "portus.example.com:5000"],
|
|
+ python_shell=False,
|
|
+ output_loglevel="quiet",
|
|
+ )
|
|
+
|
|
+
|
|
def test_logout_calls_docker_cli_logout_all(self):
|
|
client = Mock()
|
|
get_client_mock = MagicMock(return_value=client)
|
|
--
|
|
2.29.2
|
|
|
|
|