Skip to content

Commit

Permalink
Add ExternalRegistryHelper for working with microservice
Browse files Browse the repository at this point in the history
  • Loading branch information
manics committed Feb 21, 2023
1 parent c9c86bf commit 3fbfe6b
Showing 1 changed file with 97 additions and 0 deletions.
97 changes: 97 additions & 0 deletions binderhub/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,100 @@ class FakeRegistry(DockerRegistry):

async def get_image_manifest(self, image, tag):
return None


class ExternalRegistryHelper(DockerRegistry):
"""
A registry that uses a micro-service to check and create image
repositories.
Also handles creation of tokens for pushing to a registry if required.
"""

service_url = Unicode(
"http://binderhub-container-registry-helper:8080",
allow_none=False,
help="The URL of the registry helper micro-service.",
config=True,
)

auth_token = Unicode(
"secret-token",
help="The auth token to use when accessing the registry helper micro-service.",
config=True,
)

async def _request(self, endpoint, **kwargs):
client = httpclient.AsyncHTTPClient()
repo_url = f"{self.service_url}{endpoint}"
headers = {"Authorization": f"Bearer {self.auth_token}"}
repo = await client.fetch(repo_url, headers=headers, **kwargs)
return json.loads(repo.body.decode("utf-8"))

async def _get_image(self, image, tag):
repo_url = f"/image/{image}:{tag}"
self.log.debug(f"Checking whether image exists: {repo_url}")
try:
image_json = await self._request(repo_url)
return image_json
except httpclient.HTTPError as e:
if e.code == 404:
return None
else:
raise

async def get_image_manifest(self, image, tag):
"""
Checks whether the image exists in the registry.
If the container repository doesn't exist create the repository.
image: The image name without the registry domain and tag, but
including all prefix components (e.g. a namespace). The registry
helper should automatically take care of converting the full path
into the necessary API components
tag: The image tag
Returns the image manifest if the image exists, otherwise None
"""

repo_url = f"/repo/{image}"
self.log.debug(f"Checking whether repository exists: {repo_url}")
try:
repo_json = await self._request(repo_url)
except httpclient.HTTPError as e:
if e.code == 404:
repo_json = None
else:
raise

if repo_json:
return await self._get_image(image, tag)
else:
self.log.debug(f"Creating repository: {repo_url}")
await self._request(repo_url, method="POST", body="")
return None

async def get_credentials(self, image, tag):
"""
Get the registry credentials for the given image and tag if supported
by the remote helper, otherwise returns None
Returns a dictionary of login fields.
"""
token_url = f"/token/{image}:{tag}"
self.log.debug(f"Getting registry token: {token_url}")
token_json = None
try:
token_json = await self._request(token_url, method="POST", body="")
except httpclient.HTTPError as e:
if e.code != 404:
raise
# https://docker-py.readthedocs.io/en/stable/api.html#docker.api.daemon.DaemonApiMixin.login
token = {
k: v
for (k, v) in token_json.items()
if k in ["username", "password", "registry"]
}
self.log.debug(f"Returning registry token: {token}")
return token

0 comments on commit 3fbfe6b

Please sign in to comment.