Skip to content

Commit 949c3c0

Browse files
Remove upload to docker registry code snippets (#1017)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 5ab8e4e commit 949c3c0

File tree

7 files changed

+9
-329
lines changed

7 files changed

+9
-329
lines changed

conda-store-server/conda_store_server/_internal/orm.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -395,18 +395,11 @@ def conda_env_export_key(self):
395395
def conda_pack_key(self):
396396
return f"archive/{self.build_key}.tar.gz"
397397

398-
@property
399-
def docker_manifest_key(self):
400-
return f"docker/manifest/{self.build_key}"
401-
402398
@property
403399
def constructor_installer_key(self):
404400
ext = "exe" if sys.platform == "win32" else "sh"
405401
return f"installer/{self.build_key}.{ext}"
406402

407-
def docker_blob_key(self, blob_hash):
408-
return f"docker/blobs/{blob_hash}"
409-
410403
@hybrid_property
411404
def has_lockfile(self):
412405
return any(

conda-store-server/conda_store_server/_internal/schema.py

Lines changed: 1 addition & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,9 @@ class BuildArtifactType(str, enum.Enum):
154154
LOGS = "LOGS"
155155
YAML = "YAML"
156156
CONDA_PACK = "CONDA_PACK"
157-
DOCKER_BLOB = "DOCKER_BLOB"
158157
DOCKER_MANIFEST = "DOCKER_MANIFEST"
159-
CONTAINER_REGISTRY = "CONTAINER_REGISTRY"
160158
CONSTRUCTOR_INSTALLER = "CONSTRUCTOR_INSTALLER"
159+
_ = "CONTAINER_REGISTRY"
161160

162161

163162
class BuildStatus(enum.Enum):
@@ -267,9 +266,6 @@ class Settings(BaseModel):
267266
BuildArtifactType.LOGS,
268267
BuildArtifactType.LOCKFILE,
269268
BuildArtifactType.YAML,
270-
# no possible way to delete these artifacts
271-
# in most container registries via api
272-
BuildArtifactType.CONTAINER_REGISTRY,
273269
],
274270
description="artifacts to keep on build deletion",
275271
metadata={"global": True},
@@ -446,80 +442,6 @@ def __str__(self):
446442
return str(self.dict())
447443

448444

449-
###############################
450-
# Docker Registry Schema
451-
###############################
452-
453-
454-
def _docker_datetime_factory():
455-
"""Utcnow datetime + timezone as string"""
456-
return datetime.datetime.utcnow().astimezone().isoformat()
457-
458-
459-
class DockerManifestLayer(BaseModel):
460-
mediaType: str = "application/vnd.docker.image.rootfs.diff.tar.gzip"
461-
size: int
462-
digest: str
463-
464-
465-
class DockerManifestConfig(BaseModel):
466-
mediaType: str = "application/vnd.docker.container.image.v1+json"
467-
size: int
468-
digest: str
469-
470-
471-
class DockerManifest(BaseModel):
472-
schemaVersion: int = 2
473-
mediaType: str = "application/vnd.docker.distribution.manifest.v2+json"
474-
config: DockerManifestConfig
475-
layers: List[DockerManifestLayer] = []
476-
477-
478-
class DockerConfigConfig(BaseModel):
479-
Hostname: str = ""
480-
Domainname: str = ""
481-
User: str = ""
482-
AttachStdin: bool = False
483-
AttachStdout: bool = False
484-
AttachStderr: bool = False
485-
Tty: bool = False
486-
OpenStdin: bool = False
487-
StdinOnce: bool = False
488-
Env: List[str] = [
489-
"PATH=/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
490-
]
491-
Cmd: List[str] = ["/bin/sh"]
492-
ArgsEscaped: bool = True
493-
Image: Optional[str] = None
494-
Volumes: Optional[List[str]] = None
495-
WorkingDir: str = ""
496-
Entrypoint: Optional[str] = None
497-
OnBuild: Optional[str] = None
498-
Labels: Optional[Dict[str, str]] = {"conda_store": "0.0.1"}
499-
500-
501-
class DockerConfigRootFS(BaseModel):
502-
type: str = "layers"
503-
diff_ids: List[str] = []
504-
505-
506-
class DockerConfigHistory(BaseModel):
507-
created: str = Field(default_factory=_docker_datetime_factory)
508-
created_by: str = ""
509-
510-
511-
class DockerConfig(BaseModel):
512-
architecture: str = "amd64"
513-
os: str = "linux"
514-
config: DockerConfigConfig
515-
container: str
516-
container_config: DockerConfigConfig
517-
created: str = Field(default_factory=_docker_datetime_factory)
518-
docker_version: str = "18.09.7"
519-
history: List[DockerConfigHistory] = []
520-
rootfs: DockerConfigRootFS
521-
522-
523445
# https://docs.docker.com/registry/spec/api/#errors-2
524446
class DockerRegistryError(enum.Enum):
525447
NAME_UNKNOWN = {

conda-store-server/conda_store_server/_internal/worker/tasks.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,6 @@ def delete_build_artifact(db: Session, conda_store, build_artifact):
274274
):
275275
shutil.rmtree(conda_prefix)
276276
db.delete(build_artifact)
277-
elif build_artifact.artifact_type == schema.BuildArtifactType.CONTAINER_REGISTRY:
278-
pass
279-
# # container registry tag deletion is not generally implemented
280-
# # the underlying library `python_docker` is already capable
281-
# conda_store.container_registry.delete_image(build_artifact.key)
282277
else:
283278
conda_store.log.info(f"deleting {build_artifact.key}")
284279
conda_store.storage.delete(db, build_artifact.build.id, build_artifact.key)

conda-store-server/conda_store_server/app.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
)
2626
from traitlets.config import LoggingConfigurable
2727

28-
from conda_store_server import CONDA_STORE_DIR, BuildKey, api, registry, storage
28+
from conda_store_server import CONDA_STORE_DIR, BuildKey, api, storage
2929
from conda_store_server._internal import conda_utils, environment, orm, schema, utils
3030
from conda_store_server.plugins import hookspec, plugin_manager
3131
from conda_store_server.plugins.types import lock
@@ -78,12 +78,7 @@ class CondaStore(LoggingConfigurable):
7878
config=True,
7979
)
8080

81-
container_registry_class = Type(
82-
default_value=registry.ContainerRegistry,
83-
klass=registry.ContainerRegistry,
84-
allow_none=False,
85-
config=True,
86-
)
81+
container_registry_class = Type(allow_none=True, help="(deprecated)")
8782

8883
store_directory = Unicode(
8984
str(CONDA_STORE_DIR / "state"),
@@ -282,9 +277,6 @@ def _check_redis(self, proposal):
282277
schema.BuildArtifactType.LOGS,
283278
schema.BuildArtifactType.LOCKFILE,
284279
schema.BuildArtifactType.YAML,
285-
# no possible way to delete these artifacts
286-
# in most container registries via api
287-
schema.BuildArtifactType.CONTAINER_REGISTRY,
288280
],
289281
help="artifacts to keep on build deletion",
290282
config=True,
@@ -410,15 +402,6 @@ def storage(self):
410402

411403
return self._storage
412404

413-
@property
414-
def container_registry(self):
415-
if hasattr(self, "_container_registry"):
416-
return self._container_registry
417-
self._container_registry = self.container_registry_class(
418-
parent=self, log=self.log
419-
)
420-
return self._container_registry
421-
422405
@property
423406
def celery_config(self):
424407
return {

conda-store-server/conda_store_server/registry.py

Lines changed: 4 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -2,192 +2,23 @@
22
# Use of this source code is governed by a BSD-style
33
# license that can be found in the LICENSE file.
44

5-
import gzip
6-
import hashlib
7-
import urllib.parse
8-
9-
from python_docker.registry import Image, Registry
10-
from sqlalchemy.orm import Session
11-
from traitlets import Callable, Dict, default
5+
from traitlets import Callable, Dict
126
from traitlets.config import LoggingConfigurable
137

14-
from conda_store_server._internal import orm, schema, utils
15-
168

179
class ContainerRegistry(LoggingConfigurable):
1810
container_registries = Dict(
1911
{},
20-
help="Registries url to upload built container images with callable function to configure registry instance with credentials",
12+
help="(deprecated) Registries url to upload built container images with callable function to configure registry instance with credentials",
2113
config=True,
2214
)
2315

2416
container_registry_image_name = Callable(
25-
help="Image name to assign to docker image pushed for particular registry",
17+
help="(deprecated) Image name to assign to docker image pushed for particular registry",
2618
config=True,
2719
)
2820

29-
@default("container_registry_image_name")
30-
def _default_container_registry_image_name(self):
31-
def _container_registry_image_name(registry: Registry, build: orm.Build):
32-
return f"{registry.username}/{build.environment.namespace.name}-{build.environment.name}"
33-
34-
return _container_registry_image_name
35-
3621
container_registry_image_tag = Callable(
37-
help="Image name and tag to assign to docker image pushed for particular registry",
22+
help="(deprecated) Image name and tag to assign to docker image pushed for particular registry",
3823
config=True,
3924
)
40-
41-
@default("container_registry_image_tag")
42-
def _default_container_registry_image_tag(self):
43-
def _container_registry_image_tag(registry: Registry, build: orm.Build):
44-
return build.key
45-
46-
return _container_registry_image_tag
47-
48-
def store_image(self, db: Session, conda_store, build: orm.Build, image: Image):
49-
self.log.info("storing container image locally")
50-
with utils.timer(self.log, "storing container image locally"):
51-
# https://docs.docker.com/registry/spec/manifest-v2-2/#example-image-manifest
52-
docker_manifest = schema.DockerManifest.construct()
53-
docker_config = schema.DockerConfig.construct(
54-
config=schema.DockerConfigConfig(),
55-
container_config=schema.DockerConfigConfig(),
56-
rootfs=schema.DockerConfigRootFS(),
57-
)
58-
59-
for layer in image.layers:
60-
# https://github.com/google/nixery/pull/64#issuecomment-541019077
61-
# docker manifest expects compressed hash while configuration file
62-
# expects uncompressed hash -- good luck finding this detail in docs :)
63-
content_uncompressed_hash = hashlib.sha256(layer.content).hexdigest()
64-
content_compressed = gzip.compress(layer.content)
65-
content_compressed_hash = hashlib.sha256(content_compressed).hexdigest()
66-
conda_store.storage.set(
67-
db,
68-
build.id,
69-
build.docker_blob_key(content_compressed_hash),
70-
content_compressed,
71-
content_type="application/gzip",
72-
artifact_type=schema.BuildArtifactType.DOCKER_BLOB,
73-
)
74-
75-
docker_layer = schema.DockerManifestLayer(
76-
size=len(content_compressed),
77-
digest=f"sha256:{content_compressed_hash}",
78-
)
79-
docker_manifest.layers.append(docker_layer)
80-
81-
docker_config_history = schema.DockerConfigHistory()
82-
docker_config.history.append(docker_config_history)
83-
84-
docker_config.rootfs.diff_ids.append(
85-
f"sha256:{content_uncompressed_hash}"
86-
)
87-
88-
docker_config_content = docker_config.json().encode("utf-8")
89-
docker_config_hash = hashlib.sha256(docker_config_content).hexdigest()
90-
docker_manifest.config = schema.DockerManifestConfig(
91-
size=len(docker_config_content), digest=f"sha256:{docker_config_hash}"
92-
)
93-
docker_manifest_content = docker_manifest.json().encode("utf-8")
94-
docker_manifest_hash = hashlib.sha256(docker_manifest_content).hexdigest()
95-
96-
conda_store.storage.set(
97-
db,
98-
build.id,
99-
build.docker_blob_key(docker_config_hash),
100-
docker_config_content,
101-
content_type="application/vnd.docker.container.image.v1+json",
102-
artifact_type=schema.BuildArtifactType.DOCKER_BLOB,
103-
)
104-
105-
# docker likes to have a sha256 key version of the manifest this
106-
# is sort of hack to avoid having to figure out which sha256
107-
# refers to which manifest.
108-
conda_store.storage.set(
109-
db,
110-
build.id,
111-
f"docker/manifest/sha256:{docker_manifest_hash}",
112-
docker_manifest_content,
113-
content_type="application/vnd.docker.distribution.manifest.v2+json",
114-
artifact_type=schema.BuildArtifactType.DOCKER_BLOB,
115-
)
116-
117-
conda_store.storage.set(
118-
db,
119-
build.id,
120-
build.docker_manifest_key,
121-
docker_manifest_content,
122-
content_type="application/vnd.docker.distribution.manifest.v2+json",
123-
artifact_type=schema.BuildArtifactType.DOCKER_MANIFEST,
124-
)
125-
126-
conda_store.log.info(
127-
f"built docker image: {image.name}:{image.tag} layers={len(image.layers)}"
128-
)
129-
130-
@staticmethod
131-
def parse_image_uri(image_name: str):
132-
"""Must be in fully specified format [<scheme>://]<registry_url>/<image_name>:<tag_name>"""
133-
if not image_name.startswith("http"):
134-
image_name = f"https://{image_name}"
135-
136-
parsed_url = urllib.parse.urlparse(image_name)
137-
registry_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
138-
image_name, tag_name = parsed_url.path.split(":", 1)
139-
image_name = image_name[1:] # remove beginning "/"
140-
return registry_url, image_name, tag_name
141-
142-
def pull_image(self, image_name: str) -> Image:
143-
"""Must be in fully specified format [<scheme>://]<registry_url>/<image_name>:<tag_name>
144-
145-
Docker is the only weird registry where you must use:
146-
- `https://registry-1.docker.io`
147-
"""
148-
registry_url, name, tag = self.parse_image_uri(image_name)
149-
150-
for url in self.container_registries:
151-
if registry_url in url:
152-
registry = self.container_registries[registry_url](url)
153-
break
154-
else:
155-
self.log.warning(
156-
f"registry {registry_url} not configured using registry without authentication"
157-
)
158-
registry = Registry(hostname=registry_url)
159-
160-
return registry.pull_image(name, tag)
161-
162-
def push_image(self, db, build, image: Image):
163-
for registry_url, configure_registry in self.container_registries.items():
164-
self.log.info(f"beginning upload of image to registry {registry_url}")
165-
with utils.timer(self.log, f"uploading image to registry {registry_url}"):
166-
registry = configure_registry(registry_url)
167-
image.name = self.container_registry_image_name(registry, build)
168-
image.tag = self.container_registry_image_tag(registry, build)
169-
registry.push_image(image)
170-
171-
registry_build_artifact = orm.BuildArtifact(
172-
build_id=build.id,
173-
artifact_type=schema.BuildArtifactType.CONTAINER_REGISTRY,
174-
key=f"{registry_url}/{image.name}:{image.tag}",
175-
)
176-
db.add(registry_build_artifact)
177-
db.commit()
178-
179-
def delete_image(self, image_name: str):
180-
registry_url, name, tag = self.parse_image_uri(image_name)
181-
182-
for url in self.container_registries:
183-
if registry_url in url:
184-
registry = self.container_registries[registry_url](url)
185-
break
186-
else:
187-
self.log.warning(
188-
f"registry {registry_url} not configured using registry without authentication"
189-
)
190-
registry = Registry(hostname=registry_url)
191-
192-
self.log.info(f"deleting container image {image_name}")
193-
registry.delete_image(name, tag)

0 commit comments

Comments
 (0)