mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-08 17:56:33 +00:00
Add login support for dockerhub (#2218)
* Add login support for dockerhub * Remove registry
This commit is contained in:
parent
50e0fd159f
commit
8f4ac10361
@ -227,6 +227,7 @@ ATTR_PROVIDERS = "providers"
|
||||
ATTR_RATING = "rating"
|
||||
ATTR_REFRESH_TOKEN = "refresh_token"
|
||||
ATTR_REGISTRIES = "registries"
|
||||
ATTR_REGISTRY = "registry"
|
||||
ATTR_REPOSITORIES = "repositories"
|
||||
ATTR_REPOSITORY = "repository"
|
||||
ATTR_SCHEMA = "schema"
|
||||
|
@ -10,7 +10,13 @@ from packaging import version as pkg_version
|
||||
import requests
|
||||
|
||||
from . import CommandReturn
|
||||
from ..const import ATTR_PASSWORD, ATTR_USERNAME, LABEL_ARCH, LABEL_VERSION
|
||||
from ..const import (
|
||||
ATTR_PASSWORD,
|
||||
ATTR_REGISTRY,
|
||||
ATTR_USERNAME,
|
||||
LABEL_ARCH,
|
||||
LABEL_VERSION,
|
||||
)
|
||||
from ..coresys import CoreSys, CoreSysAttributes
|
||||
from ..exceptions import DockerAPIError, DockerError, DockerNotFound, DockerRequestError
|
||||
from ..utils import process_lock
|
||||
@ -19,6 +25,7 @@ from .stats import DockerStats
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
IMAGE_WITH_HOST = re.compile(r"^((?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,})\/.+")
|
||||
DOCKER_HUB = "hub.docker.com"
|
||||
|
||||
|
||||
class DockerInterface(CoreSysAttributes):
|
||||
@ -87,17 +94,46 @@ class DockerInterface(CoreSysAttributes):
|
||||
"""Pull docker image."""
|
||||
return self.sys_run_in_executor(self._install, tag, image, latest)
|
||||
|
||||
def _docker_login(self, hostname: str) -> None:
|
||||
"""Try to log in to the registry if there are credentials available."""
|
||||
if hostname in self.sys_docker.config.registries:
|
||||
credentials = self.sys_docker.config.registries[hostname]
|
||||
def _get_credentials(self, image: str) -> dict:
|
||||
"""Return a dictionay with credentials for docker login."""
|
||||
registry = None
|
||||
credentials = {}
|
||||
matcher = IMAGE_WITH_HOST.match(image)
|
||||
|
||||
self.sys_docker.docker.login(
|
||||
registry=hostname,
|
||||
username=credentials[ATTR_USERNAME],
|
||||
password=credentials[ATTR_PASSWORD],
|
||||
# Custom registry
|
||||
if matcher:
|
||||
if matcher.group(1) in self.sys_docker.config.registries:
|
||||
registry = matcher.group(1)
|
||||
credentials[ATTR_REGISTRY] = registry
|
||||
|
||||
# If no match assume "dockerhub" as registry
|
||||
elif DOCKER_HUB in self.sys_docker.config.registries:
|
||||
registry = DOCKER_HUB
|
||||
|
||||
if registry:
|
||||
stored = self.sys_docker.config.registries[registry]
|
||||
credentials[ATTR_USERNAME] = stored[ATTR_USERNAME]
|
||||
credentials[ATTR_PASSWORD] = stored[ATTR_PASSWORD]
|
||||
|
||||
_LOGGER.debug(
|
||||
"Logging in to %s as %s",
|
||||
registry,
|
||||
stored[ATTR_USERNAME],
|
||||
)
|
||||
|
||||
return credentials
|
||||
|
||||
def _docker_login(self, image: str) -> None:
|
||||
"""Try to log in to the registry if there are credentials available."""
|
||||
if not self.sys_docker.config.registries:
|
||||
return
|
||||
|
||||
credentials = self._get_credentials(image)
|
||||
if not credentials:
|
||||
return
|
||||
|
||||
self.sys_docker.docker.login(**credentials)
|
||||
|
||||
def _install(
|
||||
self, tag: str, image: Optional[str] = None, latest: bool = False
|
||||
) -> None:
|
||||
@ -109,10 +145,10 @@ class DockerInterface(CoreSysAttributes):
|
||||
|
||||
_LOGGER.info("Downloading docker image %s with tag %s.", image, tag)
|
||||
try:
|
||||
# If the image name contains a path to a registry, try to log in
|
||||
path = IMAGE_WITH_HOST.match(image)
|
||||
if path:
|
||||
self._docker_login(path.group(1))
|
||||
if self.sys_docker.config.registries:
|
||||
# Try login if we have defined credentials
|
||||
self._docker_login(image)
|
||||
|
||||
docker_image = self.sys_docker.images.pull(f"{image}:{tag}")
|
||||
if latest:
|
||||
_LOGGER.info("Tagging image %s with version %s as latest", image, tag)
|
||||
|
40
tests/docker/test_credentials.py
Normal file
40
tests/docker/test_credentials.py
Normal file
@ -0,0 +1,40 @@
|
||||
"""Test docker login."""
|
||||
# pylint: disable=protected-access
|
||||
from supervisor.coresys import CoreSys
|
||||
from supervisor.docker.interface import DOCKER_HUB, DockerInterface
|
||||
|
||||
|
||||
def test_no_credentials(coresys: CoreSys):
|
||||
"""Test no credentials."""
|
||||
docker = DockerInterface(coresys)
|
||||
coresys.docker.config.registries = {
|
||||
DOCKER_HUB: {"username": "Spongebob Squarepants", "password": "Password1!"}
|
||||
}
|
||||
assert not docker._get_credentials("ghcr.io/homeassistant")
|
||||
assert not docker._get_credentials("ghcr.io/homeassistant/amd64-supervisor")
|
||||
|
||||
|
||||
def test_no_matching_credentials(coresys: CoreSys):
|
||||
"""Test no matching credentials."""
|
||||
docker = DockerInterface(coresys)
|
||||
coresys.docker.config.registries = {
|
||||
DOCKER_HUB: {"username": "Spongebob Squarepants", "password": "Password1!"}
|
||||
}
|
||||
assert not docker._get_credentials("ghcr.io/homeassistant")
|
||||
assert not docker._get_credentials("ghcr.io/homeassistant/amd64-supervisor")
|
||||
|
||||
|
||||
def test_matching_credentials(coresys: CoreSys):
|
||||
"""Test no matching credentials."""
|
||||
docker = DockerInterface(coresys)
|
||||
coresys.docker.config.registries = {
|
||||
"ghcr.io": {"username": "Octocat", "password": "Password1!"},
|
||||
DOCKER_HUB: {"username": "Spongebob Squarepants", "password": "Password1!"},
|
||||
}
|
||||
|
||||
credentials = docker._get_credentials("ghcr.io/homeassistant/amd64-supervisor")
|
||||
assert credentials["registry"] == "ghcr.io"
|
||||
|
||||
credentials = docker._get_credentials("homeassistant/amd64-supervisor")
|
||||
assert credentials["username"] == "Spongebob Squarepants"
|
||||
assert "registry" not in credentials
|
Loading…
x
Reference in New Issue
Block a user