1
1
from __future__ import annotations
2
2
3
+ import dataclasses
3
4
import logging
4
5
import os
5
6
import platform
13
14
import testcontainers .core .container
14
15
import testcontainers .core .docker_client
15
16
16
- from tests .containers import docker_utils , utils
17
+ from tests .containers import docker_utils , skopeo_utils , utils
17
18
18
19
if TYPE_CHECKING :
19
20
from collections .abc import Callable
38
39
testcontainers .core .config .testcontainers_config .ryuk_privileged = True
39
40
40
41
42
+ @dataclasses .dataclass
43
+ class Image :
44
+ # only pulled images have an id
45
+ id : str | None
46
+ name : str
47
+ labels : dict [str , str ]
48
+
49
+ @classmethod
50
+ def from_docker (cls , image : docker .models .images .Image , name : str ):
51
+ return Image (id = image .id , name = name , labels = image .labels )
52
+
53
+
41
54
# https://docs.pytest.org/en/latest/reference/reference.html#pytest.hookspec.pytest_addoption
42
55
def pytest_addoption (parser : Parser ) -> None :
43
56
parser .addoption ("--image" , action = "append" , default = [], help = "Image to use, can be specified multiple times" )
@@ -49,20 +62,24 @@ def pytest_generate_tests(metafunc: Metafunc) -> None:
49
62
metafunc .parametrize (image .__name__ , metafunc .config .getoption ("--image" ))
50
63
51
64
52
- def get_image_metadata (image : str ) -> docker . models . images . Image :
65
+ def get_image_metadata (image : str ) -> Image :
53
66
client = testcontainers .core .container .DockerClient ()
54
67
try :
68
+ # docker inspect
55
69
image_metadata = client .client .images .get (image )
56
70
except docker .errors .ImageNotFound :
57
- # todo(jdanek): this means that even when image is to be run remotely (on openshift),
58
- # it has to be pulled locally first so that we can check its metadata
71
+ # skopeo inspect
72
+ labels = skopeo_utils .get_image_labels (image )
73
+ if labels is not None :
74
+ return Image (id = None , name = image , labels = labels )
75
+ # pull & docker inspect
59
76
image_metadata = client .client .images .pull (image )
60
77
assert isinstance (image_metadata , docker .models .images .Image )
61
78
62
- return image_metadata
79
+ return Image . from_docker ( image_metadata , name = image )
63
80
64
81
65
- def skip_if_not_workbench_image (image : str ) -> docker . models . images . Image :
82
+ def skip_if_not_workbench_image (image : str ) -> Image :
66
83
image_metadata = get_image_metadata (image )
67
84
68
85
ide_server_label_fragments = ("-code-server-" , "-jupyter-" , "-rstudio-" )
@@ -74,7 +91,7 @@ def skip_if_not_workbench_image(image: str) -> docker.models.images.Image:
74
91
return image_metadata
75
92
76
93
77
- def skip_if_not_cuda_image (image : str ) -> docker . models . images . Image :
94
+ def skip_if_not_cuda_image (image : str ) -> Image :
78
95
image_metadata = get_image_metadata (image )
79
96
80
97
if "-cuda-" not in image_metadata .labels ["name" ]:
@@ -83,7 +100,7 @@ def skip_if_not_cuda_image(image: str) -> docker.models.images.Image:
83
100
return image_metadata
84
101
85
102
86
- def skip_if_not_rocm_image (image : str ) -> docker . models . images . Image :
103
+ def skip_if_not_rocm_image (image : str ) -> Image :
87
104
image_metadata = get_image_metadata (image )
88
105
if "-rocm-" not in image_metadata .labels ["name" ]:
89
106
pytest .skip (f"Image { image } does not have any of '-rocm-' in { image_metadata .labels ['name' ]= } " )
@@ -117,7 +134,7 @@ def rocm_workbench_image(workbench_image: str):
117
134
118
135
119
136
@pytest .fixture (scope = "function" )
120
- def jupyterlab_image (image : str ) -> docker . models . images . Image :
137
+ def jupyterlab_image (image : str ) -> Image :
121
138
image_metadata = skip_if_not_workbench_image (image )
122
139
if "-jupyter-" not in image_metadata .labels ["name" ]:
123
140
pytest .skip (f"Image { image } does not have '-jupyter-' in { image_metadata .labels ['name' ]= } '" )
@@ -126,7 +143,7 @@ def jupyterlab_image(image: str) -> docker.models.images.Image:
126
143
127
144
128
145
@pytest .fixture (scope = "function" )
129
- def rstudio_image (image : str ) -> docker . models . images . Image :
146
+ def rstudio_image (image : str ) -> Image :
130
147
image_metadata = skip_if_not_workbench_image (image )
131
148
if not utils .is_rstudio_image (image ):
132
149
pytest .skip (f"Image { image } does not have '-rstudio-' in { image_metadata .labels ['name' ]= } '" )
@@ -135,7 +152,7 @@ def rstudio_image(image: str) -> docker.models.images.Image:
135
152
136
153
137
154
@pytest .fixture (scope = "function" )
138
- def codeserver_image (image : str ) -> docker . models . images . Image :
155
+ def codeserver_image (image : str ) -> Image :
139
156
image_metadata = skip_if_not_workbench_image (image )
140
157
if "-code-server-" not in image_metadata .labels ["name" ]:
141
158
pytest .skip (f"Image { image } does not have '-code-server-' in { image_metadata .labels ['name' ]= } '" )
0 commit comments