mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-09 18:26:30 +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_RATING = "rating"
|
||||||
ATTR_REFRESH_TOKEN = "refresh_token"
|
ATTR_REFRESH_TOKEN = "refresh_token"
|
||||||
ATTR_REGISTRIES = "registries"
|
ATTR_REGISTRIES = "registries"
|
||||||
|
ATTR_REGISTRY = "registry"
|
||||||
ATTR_REPOSITORIES = "repositories"
|
ATTR_REPOSITORIES = "repositories"
|
||||||
ATTR_REPOSITORY = "repository"
|
ATTR_REPOSITORY = "repository"
|
||||||
ATTR_SCHEMA = "schema"
|
ATTR_SCHEMA = "schema"
|
||||||
|
@ -10,7 +10,13 @@ from packaging import version as pkg_version
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from . import CommandReturn
|
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 ..coresys import CoreSys, CoreSysAttributes
|
||||||
from ..exceptions import DockerAPIError, DockerError, DockerNotFound, DockerRequestError
|
from ..exceptions import DockerAPIError, DockerError, DockerNotFound, DockerRequestError
|
||||||
from ..utils import process_lock
|
from ..utils import process_lock
|
||||||
@ -19,6 +25,7 @@ from .stats import DockerStats
|
|||||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
IMAGE_WITH_HOST = re.compile(r"^((?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,})\/.+")
|
IMAGE_WITH_HOST = re.compile(r"^((?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,})\/.+")
|
||||||
|
DOCKER_HUB = "hub.docker.com"
|
||||||
|
|
||||||
|
|
||||||
class DockerInterface(CoreSysAttributes):
|
class DockerInterface(CoreSysAttributes):
|
||||||
@ -87,17 +94,46 @@ class DockerInterface(CoreSysAttributes):
|
|||||||
"""Pull docker image."""
|
"""Pull docker image."""
|
||||||
return self.sys_run_in_executor(self._install, tag, image, latest)
|
return self.sys_run_in_executor(self._install, tag, image, latest)
|
||||||
|
|
||||||
def _docker_login(self, hostname: str) -> None:
|
def _get_credentials(self, image: str) -> dict:
|
||||||
"""Try to log in to the registry if there are credentials available."""
|
"""Return a dictionay with credentials for docker login."""
|
||||||
if hostname in self.sys_docker.config.registries:
|
registry = None
|
||||||
credentials = self.sys_docker.config.registries[hostname]
|
credentials = {}
|
||||||
|
matcher = IMAGE_WITH_HOST.match(image)
|
||||||
|
|
||||||
self.sys_docker.docker.login(
|
# Custom registry
|
||||||
registry=hostname,
|
if matcher:
|
||||||
username=credentials[ATTR_USERNAME],
|
if matcher.group(1) in self.sys_docker.config.registries:
|
||||||
password=credentials[ATTR_PASSWORD],
|
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(
|
def _install(
|
||||||
self, tag: str, image: Optional[str] = None, latest: bool = False
|
self, tag: str, image: Optional[str] = None, latest: bool = False
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -109,10 +145,10 @@ class DockerInterface(CoreSysAttributes):
|
|||||||
|
|
||||||
_LOGGER.info("Downloading docker image %s with tag %s.", image, tag)
|
_LOGGER.info("Downloading docker image %s with tag %s.", image, tag)
|
||||||
try:
|
try:
|
||||||
# If the image name contains a path to a registry, try to log in
|
if self.sys_docker.config.registries:
|
||||||
path = IMAGE_WITH_HOST.match(image)
|
# Try login if we have defined credentials
|
||||||
if path:
|
self._docker_login(image)
|
||||||
self._docker_login(path.group(1))
|
|
||||||
docker_image = self.sys_docker.images.pull(f"{image}:{tag}")
|
docker_image = self.sys_docker.images.pull(f"{image}:{tag}")
|
||||||
if latest:
|
if latest:
|
||||||
_LOGGER.info("Tagging image %s with version %s as latest", image, tag)
|
_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