diff --git a/binderhub/app.py b/binderhub/app.py index 560f54506..f15962520 100644 --- a/binderhub/app.py +++ b/binderhub/app.py @@ -431,7 +431,7 @@ def _pod_quota_deprecated(self, change): image_prefix = Unicode( "", help=""" - Prefix for all built docker images. + Fallback prefix for all built docker images. If you are pushing to gcr.io, this would start with: gcr.io// @@ -443,6 +443,42 @@ def _pod_quota_deprecated(self, change): config=True, ) + image_prefix_push = Unicode( + help=""" + Prefix for built docker images being pushed to the to container registry. + + If you are pushing to gcr.io, this would start with: + gcr.io// + + Set according to whatever registry you are pushing to. + + Defaults to "", which is probably not what you want :) + """, + config=True, + ) + + @default("image_prefix_push") + def _image_prefix_push_default(self): + return self.image_prefix + + image_prefix_pull = Unicode( + help=""" + Prefix for built docker images being pulled from container registry. + + If you are pushing to gcr.io, this would start with: + gcr.io// + + Set according to whatever registry you are pushing to. + + Defaults to "", which is probably not what you want :) + """, + config=True, + ) + + @default("image_prefix_pull") + def _image_prefix_pull_default(self): + return self.image_prefix + build_memory_request = ByteSpecification( 0, help=""" @@ -935,7 +971,8 @@ def initialize(self, *args, **kwargs): self.tornado_settings.update( { "log_function": log_request, - "image_prefix": self.image_prefix, + "image_prefix_pull": self.image_prefix_pull, + "image_prefix_push": self.image_prefix_push, "debug": self.debug, "default_opengraph_title": self.default_opengraph_title, "launcher": self.launcher, diff --git a/binderhub/builder.py b/binderhub/builder.py index f420febe7..1d0903a93 100644 --- a/binderhub/builder.py +++ b/binderhub/builder.py @@ -385,38 +385,52 @@ async def get(self, provider_prefix, _unescaped_spec): # generate a complete build name (for GitHub: `build-{user}-{repo}-{ref}`) - image_prefix = self.settings["image_prefix"] + image_prefix_push = self.settings["image_prefix_push"] + image_prefix_pull = self.settings["image_prefix_pull"] # Enforces max 255 characters before image safe_build_slug = _safe_build_slug( - provider.get_build_slug(), limit=255 - len(image_prefix) + provider.get_build_slug(), + limit=255 - max(len(image_prefix_push), len(image_prefix_pull)), ) build_name = _generate_build_name( provider.get_build_slug(), ref, prefix="build-" ) - image_name = self.image_name = ( + image_name_push = self.image_name_push = ( "{prefix}{build_slug}:{ref}".format( - prefix=image_prefix, build_slug=safe_build_slug, ref=ref + prefix=image_prefix_push, build_slug=safe_build_slug, ref=ref + ) + .replace("_", "-") + .lower() + ) + image_name_pull = self.image_name_pull = ( + "{prefix}{build_slug}:{ref}".format( + prefix=image_prefix_pull, build_slug=safe_build_slug, ref=ref ) .replace("_", "-") .lower() ) - image_without_tag, image_tag = _get_image_basename_and_tag(image_name) + image_push_without_tag, image_push_tag = _get_image_basename_and_tag( + image_name_push + ) + image_pull_without_tag, image_pull_tag = _get_image_basename_and_tag( + image_name_pull + ) if self.settings["use_registry"]: for _ in range(3): try: image_manifest = await self.registry.get_image_manifest( - image_without_tag, image_tag + image_pull_without_tag, image_pull_tag ) image_found = bool(image_manifest) break except HTTPClientError: app_log.exception( "Failed to get image manifest for %s", - image_name, + image_name_pull, ) image_found = False else: @@ -424,7 +438,7 @@ async def get(self, provider_prefix, _unescaped_spec): # Assume we're running in single-node mode or all binder pods are assigned to the same node! docker_client = docker.from_env(version="auto") try: - docker_client.images.get(image_name) + docker_client.images.get(image_name_pull) except docker.errors.ImageNotFound: # image doesn't exist, so do a build! image_found = False @@ -437,7 +451,7 @@ async def get(self, provider_prefix, _unescaped_spec): await self.emit( { "phase": "ready", - "imageName": image_name, + "imageName": image_name_push, "message": "Done! Found built image\n", } ) @@ -445,7 +459,7 @@ async def get(self, provider_prefix, _unescaped_spec): await self.emit( { "phase": "built", - "imageName": image_name, + "imageName": image_name_push, "message": "Found built image, launching...\n", } ) @@ -490,12 +504,12 @@ async def get(self, provider_prefix, _unescaped_spec): name=build_name, repo_url=repo_url, ref=ref, - image_name=image_name, + image_name=image_name_push, git_credentials=provider.git_credentials, ) if self.settings["use_registry"]: push_token = await self.registry.get_credentials( - image_without_tag, image_tag + image_push_without_tag, image_push_tag ) if push_token: build.registry_credentials = push_token @@ -555,7 +569,7 @@ def _check_result(future): event = { "phase": phase, "message": message, - "imageName": image_name, + "imageName": image_name_push, } BUILD_TIME.labels(status="success").observe( time.perf_counter() - build_starttime @@ -647,7 +661,7 @@ async def check_quota(self, provider): launch_quota = self.settings["launch_quota"] try: return await launch_quota.check_repo_quota( - self.image_name, repo_config, self.repo_url + self.image_name_pull, repo_config, self.repo_url ) except LaunchQuotaExceeded as e: LAUNCH_COUNT.labels( @@ -715,7 +729,7 @@ async def handle_progress_event(event): "binder_persistent_request": self.binder_persistent_request, } server_info = await launcher.launch( - image=self.image_name, + image=self.image_name_pull, username=username, server_name=server_name, repo_url=self.repo_url, diff --git a/binderhub/health.py b/binderhub/health.py index 1b65bf3e0..a7d182f84 100644 --- a/binderhub/health.py +++ b/binderhub/health.py @@ -153,7 +153,7 @@ async def check_docker_registry(self): registry = self.settings["registry"] # we are only interested in getting a response from the registry, we # don't care if the image actually exists or not - image_fullname = self.settings["image_prefix"] + "some-image-name:12345" + image_fullname = self.settings["image_prefix_pull"] + "some-image-name:12345" name, tag = _get_image_basename_and_tag(image_fullname) await registry.get_image_manifest(name, tag) return True