iker-python-common 1.0.62__tar.gz → 1.0.63__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/PKG-INFO +1 -2
  2. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/pyproject.toml +0 -2
  3. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker_python_common.egg-info/PKG-INFO +1 -2
  4. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker_python_common.egg-info/SOURCES.txt +0 -3
  5. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker_python_common.egg-info/requires.txt +0 -1
  6. iker_python_common-1.0.62/src/iker/common/utils/dockerutils.py +0 -236
  7. iker_python_common-1.0.62/test/iker_tests/common/utils/dockerutils_test.py +0 -544
  8. iker_python_common-1.0.62/test/iker_tests/docker_fixtures.py +0 -79
  9. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/.editorconfig +0 -0
  10. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/.github/workflows/pr.yml +0 -0
  11. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/.github/workflows/push.yml +0 -0
  12. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/.gitignore +0 -0
  13. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/MANIFEST.in +0 -0
  14. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/README.md +0 -0
  15. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/VERSION +0 -0
  16. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/config/config.cfg +0 -0
  17. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/csv/data.csv +0 -0
  18. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/csv/data.tsv +0 -0
  19. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.baz/file.bar.baz +0 -0
  20. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.baz/file.foo.bar +0 -0
  21. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.baz/file.foo.baz +0 -0
  22. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
  23. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
  24. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
  25. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
  26. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.foo/file.bar +0 -0
  27. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.foo/file.baz +0 -0
  28. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/resources/unittest/shutils/dir.foo/file.foo +0 -0
  29. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/setup.cfg +0 -0
  30. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/setup.py +0 -0
  31. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/__init__.py +0 -0
  32. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/__init__.py +0 -0
  33. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/argutils.py +0 -0
  34. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/config.py +0 -0
  35. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/csv.py +0 -0
  36. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/dbutils.py +0 -0
  37. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/dtutils.py +0 -0
  38. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/funcutils.py +0 -0
  39. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/jsonutils.py +0 -0
  40. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/logger.py +0 -0
  41. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/numutils.py +0 -0
  42. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/randutils.py +0 -0
  43. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/retry.py +0 -0
  44. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/sequtils.py +0 -0
  45. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/shutils.py +0 -0
  46. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/span.py +0 -0
  47. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/strutils.py +0 -0
  48. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/testutils.py +0 -0
  49. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker/common/utils/typeutils.py +0 -0
  50. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker_python_common.egg-info/dependency_links.txt +0 -0
  51. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker_python_common.egg-info/not-zip-safe +0 -0
  52. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/src/iker_python_common.egg-info/top_level.txt +0 -0
  53. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_test.py +0 -0
  54. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/__init__.py +0 -0
  55. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/argutils_test.py +0 -0
  56. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/config_test.py +0 -0
  57. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/csv_test.py +0 -0
  58. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/dbutils_test.py +0 -0
  59. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/dtutils_test.py +0 -0
  60. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/funcutils_test.py +0 -0
  61. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/jsonutils_test.py +0 -0
  62. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/logger_test.py +0 -0
  63. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/numutils_test.py +0 -0
  64. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/randutils_test.py +0 -0
  65. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/retry_test.py +0 -0
  66. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/sequtils_test.py +0 -0
  67. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/shutils_test.py +0 -0
  68. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/span_test.py +0 -0
  69. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/strutils_test.py +0 -0
  70. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/testutils_test.py +0 -0
  71. {iker_python_common-1.0.62 → iker_python_common-1.0.63}/test/iker_tests/common/utils/typeutils_test.py +0 -0
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iker-python-common
3
- Version: 1.0.62
3
+ Version: 1.0.63
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
7
7
  Classifier: Programming Language :: Python :: 3.14
8
8
  Requires-Python: <3.15,>=3.12
9
9
  Requires-Dist: asyncpg>=0.30
10
- Requires-Dist: docker>=7.1
11
10
  Requires-Dist: numpy>=2.3
12
11
  Requires-Dist: psycopg>=3.2
13
12
  Requires-Dist: pymysql>=1.1
@@ -9,7 +9,6 @@ build-backend = "setuptools.build_meta"
9
9
  [dependency-groups]
10
10
  dev = [
11
11
  "asyncpg>=0.30",
12
- "docker>=7.1",
13
12
  "numpy>=2.3",
14
13
  "psycopg>=3.2",
15
14
  "pymysql>=1.1",
@@ -37,7 +36,6 @@ classifiers = [
37
36
  ]
38
37
  dependencies = [
39
38
  "asyncpg>=0.30",
40
- "docker>=7.1",
41
39
  "numpy>=2.3",
42
40
  "psycopg>=3.2",
43
41
  "pymysql>=1.1",
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iker-python-common
3
- Version: 1.0.62
3
+ Version: 1.0.63
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Programming Language :: Python :: 3.13
7
7
  Classifier: Programming Language :: Python :: 3.14
8
8
  Requires-Python: <3.15,>=3.12
9
9
  Requires-Dist: asyncpg>=0.30
10
- Requires-Dist: docker>=7.1
11
10
  Requires-Dist: numpy>=2.3
12
11
  Requires-Dist: psycopg>=3.2
13
12
  Requires-Dist: pymysql>=1.1
@@ -26,7 +26,6 @@ src/iker/common/utils/argutils.py
26
26
  src/iker/common/utils/config.py
27
27
  src/iker/common/utils/csv.py
28
28
  src/iker/common/utils/dbutils.py
29
- src/iker/common/utils/dockerutils.py
30
29
  src/iker/common/utils/dtutils.py
31
30
  src/iker/common/utils/funcutils.py
32
31
  src/iker/common/utils/jsonutils.py
@@ -48,12 +47,10 @@ src/iker_python_common.egg-info/requires.txt
48
47
  src/iker_python_common.egg-info/top_level.txt
49
48
  test/iker_test.py
50
49
  test/iker_tests/__init__.py
51
- test/iker_tests/docker_fixtures.py
52
50
  test/iker_tests/common/utils/argutils_test.py
53
51
  test/iker_tests/common/utils/config_test.py
54
52
  test/iker_tests/common/utils/csv_test.py
55
53
  test/iker_tests/common/utils/dbutils_test.py
56
- test/iker_tests/common/utils/dockerutils_test.py
57
54
  test/iker_tests/common/utils/dtutils_test.py
58
55
  test/iker_tests/common/utils/funcutils_test.py
59
56
  test/iker_tests/common/utils/jsonutils_test.py
@@ -1,5 +1,4 @@
1
1
  asyncpg>=0.30
2
- docker>=7.1
3
2
  numpy>=2.3
4
3
  psycopg>=3.2
5
4
  pymysql>=1.1
@@ -1,236 +0,0 @@
1
- import contextlib
2
- import dataclasses
3
- import re
4
- from collections.abc import Generator, Iterator
5
- from typing import Any
6
-
7
- import docker
8
- import docker.errors
9
- import docker.models.containers
10
- import docker.models.images
11
- import requests.exceptions
12
-
13
- from iker.common.utils import logger
14
- from iker.common.utils.strutils import parse_int_or, trim_to_empty
15
-
16
- __all__ = [
17
- "ImageName",
18
- "docker_create_client",
19
- "docker_build_image",
20
- "docker_get_image",
21
- "docker_pull_image",
22
- "docker_fetch_image",
23
- "docker_run_detached",
24
- ]
25
-
26
-
27
- @dataclasses.dataclass
28
- class ImageName(object):
29
- registry_host: str | None
30
- registry_port: int | None
31
- components: list[str]
32
- tag: str | None
33
-
34
- @property
35
- def registry(self) -> str:
36
- if self.registry_host is None and self.registry_port is None:
37
- return ""
38
- if self.registry_port is None:
39
- return self.registry_host
40
- return f"{self.registry_host}:{self.registry_port}"
41
-
42
- @property
43
- def repository(self) -> str:
44
- return "/".join(self.components)
45
-
46
- @staticmethod
47
- def parse(s: str):
48
-
49
- # Registry absent version
50
- matcher = re.compile(
51
- r"^(?P<components>[a-z0-9]+((__?|-+)[a-z0-9]+)*(/[a-z0-9]+((__?|-+)[a-z0-9]+)*)*)(:(?P<tag>\w[\w.-]{0,127}))?$")
52
- match = matcher.match(s)
53
- if match:
54
- return ImageName(registry_host=None,
55
- registry_port=None,
56
- components=trim_to_empty(match.group("components")).split("/"),
57
- tag=match.group("tag"))
58
-
59
- # Registry present version
60
- matcher = re.compile(
61
- r"^((?P<host>[a-zA-Z0-9.-]+)(:(?P<port>\d+))?/)?(?P<components>[a-z0-9]+((__?|-+)[a-z0-9]+)*(/[a-z0-9]+((__?|-+)[a-z0-9]+)*)*)(:(?P<tag>\w[\w.-]{0,127}))?$")
62
- match = matcher.match(s)
63
- if match:
64
- return ImageName(registry_host=match.group("host"),
65
- registry_port=parse_int_or(match.group("port"), None),
66
- components=trim_to_empty(match.group("components")).split("/"),
67
- tag=match.group("tag"))
68
-
69
- return None
70
-
71
-
72
- def docker_create_client(
73
- registry: str,
74
- username: str,
75
- password: str,
76
- ) -> contextlib.AbstractContextManager[docker.DockerClient]:
77
- try:
78
- client = docker.DockerClient()
79
- client.login(registry=registry, username=username, password=password, reauth=True)
80
- return contextlib.closing(client)
81
- except docker.errors.APIError:
82
- logger.exception("Failed to login Docker server <%s>", registry)
83
- raise
84
-
85
-
86
- def docker_build_image(
87
- client: docker.DockerClient,
88
- tag: str,
89
- path: str,
90
- dockerfile: str,
91
- build_args: dict[str, str],
92
- ) -> tuple[docker.models.images.Image, Iterator[dict[str, str]]]:
93
- try:
94
- return client.images.build(tag=tag,
95
- path=path,
96
- dockerfile=dockerfile,
97
- buildargs=build_args,
98
- rm=True,
99
- forcerm=True,
100
- nocache=True)
101
-
102
- except docker.errors.BuildError:
103
- logger.exception("Failed to build image <%s>", tag)
104
- raise
105
- except docker.errors.APIError:
106
- logger.exception("Docker server returns an error while building image <%s>", tag)
107
- raise
108
- except Exception:
109
- logger.exception("Unexpected error occurred while building image <%s>", tag)
110
- raise
111
-
112
-
113
- def docker_get_image(
114
- client: docker.DockerClient,
115
- image: str,
116
- ) -> docker.models.images.Image:
117
- try:
118
- return client.images.get(image)
119
- except docker.errors.ImageNotFound:
120
- logger.exception("Image <%s> is not found from local repository", image)
121
- raise
122
- except docker.errors.APIError:
123
- logger.exception("Docker server returns an error while getting image <%s>", image)
124
- raise
125
- except Exception:
126
- logger.exception("Unexpected error occurred while getting image <%s>", image)
127
- raise
128
-
129
-
130
- def docker_pull_image(
131
- client: docker.DockerClient,
132
- image: str,
133
- fallback_local: bool = False,
134
- ) -> docker.models.images.Image:
135
- try:
136
- return client.images.pull(image)
137
- except docker.errors.ImageNotFound:
138
- if not fallback_local:
139
- logger.exception("Image <%s> is not found from remote repository", image)
140
- raise
141
- logger.warning("Image <%s> is not found from remote repository, try local repository instead", image)
142
- except docker.errors.APIError:
143
- if not fallback_local:
144
- logger.exception("Docker server returns an error while pulling image <%s>", image)
145
- raise
146
- logger.warning("Docker server returns an error while pulling image <%s>, try local repository instead", image)
147
- except Exception:
148
- logger.exception("Unexpected error occurred while pulling image <%s>", image)
149
- raise
150
-
151
- return docker_get_image(client, image)
152
-
153
-
154
- def docker_fetch_image(
155
- client: docker.DockerClient,
156
- image: str,
157
- force_pull: bool = False,
158
- ) -> docker.models.images.Image:
159
- if force_pull:
160
- return docker_pull_image(client, image, fallback_local=True)
161
- else:
162
- try:
163
- return docker_get_image(client, image)
164
- except Exception:
165
- return docker_pull_image(client, image, fallback_local=False)
166
-
167
-
168
- def docker_run_detached(
169
- client: docker.DockerClient,
170
- image: str,
171
- name: str,
172
- command: str | list[str],
173
- volumes: dict[str, dict[str, str]],
174
- environment: dict[str, str],
175
- extra_hosts: dict[str, str],
176
- timeout: int,
177
- **kwargs,
178
- ) -> tuple[dict[str, Any], Any]:
179
- @contextlib.contextmanager
180
- def managed_docker_run(
181
- client: docker.DockerClient,
182
- **kwargs,
183
- ) -> Generator[docker.models.containers.Container, None, None]:
184
- container_model = None
185
- try:
186
- container_model = client.containers.run(**kwargs)
187
- yield container_model
188
- except docker.errors.DockerException:
189
- raise
190
- finally:
191
- if container_model is not None:
192
- try:
193
- if container_model.status != "exited":
194
- try:
195
- container_model.stop()
196
- except docker.errors.DockerException:
197
- pass
198
- container_model.wait()
199
- try:
200
- container_model.remove()
201
- except docker.errors.DockerException:
202
- pass
203
- except Exception:
204
- raise
205
-
206
- try:
207
- run_args = kwargs.copy()
208
- run_args.update(dict(image=image,
209
- name=name,
210
- command=command,
211
- volumes=volumes,
212
- environment=environment,
213
- extra_hosts=extra_hosts,
214
- detach=True))
215
-
216
- with managed_docker_run(client, **run_args) as container_model:
217
- result = container_model.wait(timeout=timeout)
218
- logs = container_model.logs()
219
-
220
- return result, logs
221
-
222
- except requests.exceptions.ReadTimeout:
223
- logger.exception("Running container <%s> of image <%s> exceed the timeout", name, image)
224
- raise
225
- except docker.errors.ImageNotFound:
226
- logger.exception("Image <%s> is not found", image)
227
- raise
228
- except docker.errors.ContainerError:
229
- logger.exception("Failed to run container <%s> of image <%s>", name, image)
230
- raise
231
- except docker.errors.APIError:
232
- logger.exception("Docker server returns an error while running container <%s> of image <%s>", name, image)
233
- raise
234
- except Exception:
235
- logger.exception("Unexpected error occurred while running container <%s> of image <%s>", image)
236
- raise
@@ -1,544 +0,0 @@
1
- import unittest
2
- import unittest.mock
3
-
4
- import ddt
5
- import docker.errors
6
- import docker.models.containers
7
- import docker.models.images
8
- import requests.exceptions
9
-
10
- from iker.common.utils.dockerutils import *
11
- from iker.common.utils.testutils import return_callee
12
- from iker_tests.docker_fixtures import MockedDockerContainer, MockedDockerImage
13
-
14
-
15
- @ddt.ddt
16
- class DockerUtilsTest(unittest.TestCase):
17
- data_image_name = [
18
- (
19
- "ubuntu",
20
- ImageName(None, None, ["ubuntu"], None),
21
- "",
22
- "ubuntu",
23
- ),
24
- (
25
- "ubuntu:latest",
26
- ImageName(None, None, ["ubuntu"], "latest"),
27
- "",
28
- "ubuntu",
29
- ),
30
- (
31
- "ubuntu:22.04",
32
- ImageName(None, None, ["ubuntu"], "22.04"),
33
- "",
34
- "ubuntu",
35
- ),
36
- (
37
- "canonical/ubuntu",
38
- ImageName(None, None, ["canonical", "ubuntu"], None),
39
- "",
40
- "canonical/ubuntu",
41
- ),
42
- (
43
- "canonical/ubuntu:latest",
44
- ImageName(None, None, ["canonical", "ubuntu"], "latest"),
45
- "",
46
- "canonical/ubuntu",
47
- ),
48
- (
49
- "canonical/ubuntu:22.04",
50
- ImageName(None, None, ["canonical", "ubuntu"], "22.04"),
51
- "",
52
- "canonical/ubuntu",
53
- ),
54
- (
55
- "hub.docker.com/canonical/ubuntu",
56
- ImageName("hub.docker.com", None, ["canonical", "ubuntu"], None),
57
- "hub.docker.com",
58
- "canonical/ubuntu",
59
- ),
60
- (
61
- "hub.docker.com/canonical/ubuntu:latest",
62
- ImageName("hub.docker.com", None, ["canonical", "ubuntu"], "latest"),
63
- "hub.docker.com",
64
- "canonical/ubuntu",
65
- ),
66
- (
67
- "hub.docker.com/canonical/ubuntu:22.04",
68
- ImageName("hub.docker.com", None, ["canonical", "ubuntu"], "22.04"),
69
- "hub.docker.com",
70
- "canonical/ubuntu",
71
- ),
72
- (
73
- "hub.docker.com:8080/canonical/ubuntu",
74
- ImageName("hub.docker.com", 8080, ["canonical", "ubuntu"], None),
75
- "hub.docker.com:8080",
76
- "canonical/ubuntu",
77
- ),
78
- (
79
- "hub.docker.com:8080/canonical/ubuntu:latest",
80
- ImageName("hub.docker.com", 8080, ["canonical", "ubuntu"], "latest"),
81
- "hub.docker.com:8080",
82
- "canonical/ubuntu",
83
- ),
84
- (
85
- "hub.docker.com:8080/canonical/ubuntu:22.04",
86
- ImageName("hub.docker.com", 8080, ["canonical", "ubuntu"], "22.04"),
87
- "hub.docker.com:8080",
88
- "canonical/ubuntu",
89
- ),
90
- (
91
- "hub.docker.com:8080/ubuntu",
92
- ImageName("hub.docker.com", 8080, ["ubuntu"], None),
93
- "hub.docker.com:8080",
94
- "ubuntu",
95
- ),
96
- (
97
- "hub.docker.com:8080/ubuntu:latest",
98
- ImageName("hub.docker.com", 8080, ["ubuntu"], "latest"),
99
- "hub.docker.com:8080",
100
- "ubuntu",
101
- ),
102
- (
103
- "hub.docker.com:8080/ubuntu:22.04",
104
- ImageName("hub.docker.com", 8080, ["ubuntu"], "22.04"),
105
- "hub.docker.com:8080",
106
- "ubuntu",
107
- ),
108
- (
109
- "hub.docker.com:8080/docker-hub/canonical/ubuntu",
110
- ImageName("hub.docker.com", 8080, ["docker-hub", "canonical", "ubuntu"], None),
111
- "hub.docker.com:8080",
112
- "docker-hub/canonical/ubuntu",
113
- ),
114
- (
115
- "hub.docker.com:8080/docker-hub/canonical/ubuntu:latest",
116
- ImageName("hub.docker.com", 8080, ["docker-hub", "canonical", "ubuntu"], "latest"),
117
- "hub.docker.com:8080",
118
- "docker-hub/canonical/ubuntu",
119
- ),
120
- (
121
- "hub.docker.com:8080/docker-hub/canonical/ubuntu:22.04",
122
- ImageName("hub.docker.com", 8080, ["docker-hub", "canonical", "ubuntu"], "22.04"),
123
- "hub.docker.com:8080",
124
- "docker-hub/canonical/ubuntu",
125
- ),
126
- ]
127
-
128
- @ddt.idata(data_image_name)
129
- @ddt.unpack
130
- def test_image_name(self, image_name_str, image_name, registry, repository):
131
- actual = ImageName.parse(image_name_str)
132
-
133
- self.assertEqual(image_name.registry_host, actual.registry_host)
134
- self.assertEqual(image_name.registry_port, actual.registry_port)
135
- self.assertEqual(image_name.components, actual.components)
136
- self.assertEqual(image_name.tag, actual.tag)
137
- self.assertEqual(image_name.registry, actual.registry)
138
- self.assertEqual(image_name.repository, actual.repository)
139
-
140
- self.assertEqual(registry, actual.registry)
141
- self.assertEqual(repository, actual.repository)
142
-
143
- data_image_name__bad_names = [
144
- ("Ubuntu",),
145
- ("UBUNTU",),
146
- ("ubuntu.",),
147
- ("ubuntu__",),
148
- ("ubuntu-",),
149
- ("ubuntu..ubuntu",),
150
- ("ubuntu___ubuntu",),
151
- ("ubuntu._ubuntu",),
152
- ("ubuntu//ubuntu",),
153
- ("underscore_hostname.dummy.io:12345/ubuntu",),
154
- ("hostname.dummy.io:bad_port/ubuntu",),
155
- (
156
- "ubuntu:tag_is_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_too_long",
157
- ),
158
- ]
159
-
160
- @ddt.idata(data_image_name__bad_names)
161
- @ddt.unpack
162
- def test_image_name__bad_names(self, image_name_str):
163
- self.assertIsNone(ImageName.parse(image_name_str))
164
-
165
- def test_docker_create_client(self):
166
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
167
- with docker_create_client("dummy-registry", "dummy_username", "dummy_password"):
168
- pass
169
-
170
- mock_docker_client.return_value.login.assert_called_with(registry="dummy-registry",
171
- username="dummy_username",
172
- password="dummy_password",
173
- reauth=True)
174
-
175
- def test_docker_create_client__with_exception(self):
176
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
177
- mock_docker_client.return_value.login.side_effect = docker.errors.APIError("")
178
-
179
- with self.assertRaises(docker.errors.APIError):
180
- with docker_create_client("dummy-registry", "dummy_username", "dummy_password"):
181
- pass
182
-
183
- mock_docker_client.return_value.login.assert_called_with(registry="dummy-registry",
184
- username="dummy_username",
185
- password="dummy_password",
186
- reauth=True)
187
-
188
- def test_docker_build_image(self):
189
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
190
- mock_docker_image = MockedDockerImage("dummy_image",
191
- tags_callee=return_callee("dummy_tags"),
192
- labels_callee=return_callee("dummy_labels"))
193
- mock_docker_client.return_value.images.build.return_value = (
194
- mock_docker_image,
195
- [{"dummy-log-key": "dummy-log-value"}],
196
- )
197
-
198
- image_model, build_logs = docker_build_image(mock_docker_client.return_value,
199
- "dummy_tag",
200
- "dummy_path",
201
- "dummy_dockerfile",
202
- {"dummy_arg": "dummy_value"})
203
-
204
- self.assertEqual(image_model.id, "dummy_image")
205
- self.assertEqual(image_model.tags, "dummy_tags")
206
- self.assertEqual(image_model.labels, "dummy_labels")
207
- self.assertEqual(build_logs, [{"dummy-log-key": "dummy-log-value"}])
208
-
209
- mock_docker_client.return_value.images.build.assert_called_with(tag="dummy_tag",
210
- path="dummy_path",
211
- dockerfile="dummy_dockerfile",
212
- buildargs={"dummy_arg": "dummy_value"},
213
- rm=True,
214
- forcerm=True,
215
- nocache=True)
216
-
217
- data_docker_build_image__with_exception = [
218
- (docker.errors.BuildError("dummy reason", iter([{"dummy-log-key": "dummy-log-value"}])),),
219
- (docker.errors.APIError("dummy message"),),
220
- (Exception(),),
221
- ]
222
-
223
- @ddt.idata(data_docker_build_image__with_exception)
224
- @ddt.unpack
225
- def test_docker_build_image__with_exception(self, exception):
226
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
227
- mock_docker_client.return_value.images.build.side_effect = exception
228
-
229
- with self.assertRaises(type(exception)):
230
- docker_build_image(mock_docker_client.return_value,
231
- "dummy_tag",
232
- "dummy_path",
233
- "dummy_dockerfile",
234
- {"dummy_arg": "dummy_value"})
235
-
236
- mock_docker_client.return_value.images.build.assert_called_with(tag="dummy_tag",
237
- path="dummy_path",
238
- dockerfile="dummy_dockerfile",
239
- buildargs={"dummy_arg": "dummy_value"},
240
- rm=True,
241
- forcerm=True,
242
- nocache=True)
243
-
244
- def test_docker_get_image(self):
245
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
246
- mock_docker_image = MockedDockerImage("dummy_image",
247
- tags_callee=return_callee("dummy_tags"),
248
- labels_callee=return_callee("dummy_labels"))
249
- mock_docker_client.return_value.images.get.return_value = mock_docker_image
250
-
251
- image_model = docker_get_image(mock_docker_client.return_value, "dummy_image")
252
-
253
- self.assertEqual(image_model.id, "dummy_image")
254
- self.assertEqual(image_model.tags, "dummy_tags")
255
- self.assertEqual(image_model.labels, "dummy_labels")
256
-
257
- mock_docker_client.return_value.images.get.assert_called_with("dummy_image")
258
-
259
- data_docker_get_image__with_exception = [
260
- (docker.errors.ImageNotFound("dummy message"),),
261
- (docker.errors.APIError("dummy message"),),
262
- (Exception(),),
263
- ]
264
-
265
- @ddt.idata(data_docker_get_image__with_exception)
266
- @ddt.unpack
267
- def test_docker_get_image__with_exception(self, exception):
268
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
269
- mock_docker_client.return_value.images.get.side_effect = exception
270
-
271
- with self.assertRaises(type(exception)):
272
- docker_get_image(mock_docker_client.return_value, "dummy_image")
273
-
274
- mock_docker_client.return_value.images.get.assert_called_with("dummy_image")
275
-
276
- def test_docker_pull_image(self):
277
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
278
- mock_get_docker_image = MockedDockerImage("dummy_get_image",
279
- tags_callee=return_callee("dummy_get_tags"),
280
- labels_callee=return_callee("dummy_get_labels"))
281
- mock_docker_client.return_value.images.get.return_value = mock_get_docker_image
282
- mock_pull_docker_image = MockedDockerImage("dummy_pull_image",
283
- tags_callee=return_callee("dummy_pull_tags"),
284
- labels_callee=return_callee("dummy_pull_labels"))
285
- mock_docker_client.return_value.images.pull.return_value = mock_pull_docker_image
286
-
287
- image_model = docker_pull_image(mock_docker_client.return_value, "dummy_image", fallback_local=True)
288
-
289
- self.assertEqual(image_model.id, "dummy_pull_image")
290
- self.assertEqual(image_model.tags, "dummy_pull_tags")
291
- self.assertEqual(image_model.labels, "dummy_pull_labels")
292
-
293
- mock_docker_client.return_value.images.get.assert_not_called()
294
- mock_docker_client.return_value.images.pull.assert_called_with("dummy_image")
295
-
296
- def test_docker_pull_image__fallback(self):
297
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
298
- mock_docker_image = MockedDockerImage("dummy_get_image",
299
- tags_callee=return_callee("dummy_get_tags"),
300
- labels_callee=return_callee("dummy_get_labels"))
301
- mock_docker_client.return_value.images.get.return_value = mock_docker_image
302
- mock_docker_client.return_value.images.pull.side_effect = docker.errors.APIError("dummy message")
303
-
304
- image_model = docker_pull_image(mock_docker_client.return_value, "dummy_image", fallback_local=True)
305
-
306
- self.assertEqual(image_model.id, "dummy_get_image")
307
- self.assertEqual(image_model.tags, "dummy_get_tags")
308
- self.assertEqual(image_model.labels, "dummy_get_labels")
309
-
310
- mock_docker_client.return_value.images.get.assert_called_with("dummy_image")
311
- mock_docker_client.return_value.images.pull.assert_called_with("dummy_image")
312
-
313
- data_docker_pull_image__with_exception = [
314
- (docker.errors.ImageNotFound("dummy message"),),
315
- (docker.errors.APIError("dummy message"),),
316
- (Exception(),),
317
- ]
318
-
319
- @ddt.idata(data_docker_pull_image__with_exception)
320
- @ddt.unpack
321
- def test_docker_pull_image__with_exception(self, exception):
322
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
323
- mock_docker_client.return_value.images.get.side_effect = docker.errors.APIError("dummy message")
324
-
325
- mock_docker_client.return_value.images.pull.side_effect = exception
326
-
327
- with self.assertRaises(type(exception)):
328
- docker_pull_image(mock_docker_client.return_value, "dummy_image", fallback_local=False)
329
-
330
- mock_docker_client.return_value.images.get.assert_not_called()
331
- mock_docker_client.return_value.images.pull.assert_called_with("dummy_image")
332
-
333
- data_docker_pull_image__fallback_with_exception = [
334
- (docker.errors.ImageNotFound("dummy message"),),
335
- (docker.errors.APIError("dummy message"),),
336
- (Exception(),),
337
- ]
338
-
339
- @ddt.idata(data_docker_pull_image__fallback_with_exception)
340
- @ddt.unpack
341
- def test_docker_pull_image__fallback_with_exception(self, exception):
342
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
343
- mock_docker_client.return_value.images.get.side_effect = exception
344
- mock_docker_client.return_value.images.pull.side_effect = docker.errors.APIError("dummy message")
345
-
346
- with self.assertRaises(type(exception)):
347
- docker_pull_image(mock_docker_client.return_value, "dummy_image", fallback_local=True)
348
-
349
- mock_docker_client.return_value.images.get.assert_called_with("dummy_image")
350
- mock_docker_client.return_value.images.pull.assert_called_with("dummy_image")
351
-
352
- def test_docker_fetch_image(self):
353
- with (
354
- unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client,
355
- unittest.mock.patch("iker.common.utils.dockerutils.docker_get_image") as mock_docker_get_image,
356
- unittest.mock.patch("iker.common.utils.dockerutils.docker_pull_image") as mock_docker_pull_image,
357
- ):
358
- docker_fetch_image(mock_docker_client.return_value, "dummy_image")
359
-
360
- mock_docker_get_image.assert_called_with(mock_docker_client.return_value, "dummy_image")
361
- mock_docker_pull_image.assert_not_called()
362
-
363
- def test_docker_fetch_image__force_pull(self):
364
- with (
365
- unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client,
366
- unittest.mock.patch("iker.common.utils.dockerutils.docker_get_image") as mock_docker_get_image,
367
- unittest.mock.patch("iker.common.utils.dockerutils.docker_pull_image") as mock_docker_pull_image,
368
- ):
369
- docker_fetch_image(mock_docker_client.return_value, "dummy_image", force_pull=True)
370
-
371
- mock_docker_get_image.assert_not_called()
372
- mock_docker_pull_image.assert_called_with(mock_docker_client.return_value,
373
- "dummy_image",
374
- fallback_local=True)
375
-
376
- def test_docker_fetch_image__get_image_failed(self):
377
- with (
378
- unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client,
379
- unittest.mock.patch("iker.common.utils.dockerutils.docker_get_image") as mock_docker_get_image,
380
- unittest.mock.patch("iker.common.utils.dockerutils.docker_pull_image") as mock_docker_pull_image,
381
- ):
382
- mock_docker_get_image.side_effect = docker.errors.APIError("dummy message")
383
-
384
- docker_fetch_image(mock_docker_client.return_value, "dummy_image")
385
-
386
- mock_docker_get_image.assert_called_with(mock_docker_client.return_value, "dummy_image")
387
- mock_docker_pull_image.assert_called_with(mock_docker_client.return_value,
388
- "dummy_image",
389
- fallback_local=False)
390
-
391
- def test_docker_run_detached(self):
392
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
393
- mock_docker_container = MockedDockerContainer("dummy_container",
394
- status_callee=return_callee("dummy_status"),
395
- wait_callee=return_callee({"dummy_key": "dummy_value"}),
396
- logs_callee=return_callee("dummy log"),
397
- stop_callee=return_callee(),
398
- remove_callee=return_callee())
399
- mock_docker_client.return_value.containers.run.return_value = mock_docker_container
400
-
401
- result, log = docker_run_detached(mock_docker_client.return_value,
402
- "dummy_image",
403
- "dummy_container",
404
- "dummy_command",
405
- {"/dummy/src/path": {"bind": "/dummy/dst/path", "mode": "rw"}},
406
- {"DUMMY_ENV_KEY": "DUMMY_ENV_VALUE"},
407
- {"dummy.ip.address": "127.0.0.1"},
408
- 1000,
409
- dummy_kwarg="dummy_value")
410
-
411
- self.assertEqual(result, {"dummy_key": "dummy_value"})
412
- self.assertEqual(log, "dummy log")
413
-
414
- mock_docker_client.return_value.containers.run.assert_called_with(
415
- image="dummy_image",
416
- name="dummy_container",
417
- command="dummy_command",
418
- volumes={"/dummy/src/path": {"bind": "/dummy/dst/path", "mode": "rw"}},
419
- environment={"DUMMY_ENV_KEY": "DUMMY_ENV_VALUE"},
420
- extra_hosts={"dummy.ip.address": "127.0.0.1"},
421
- detach=True,
422
- dummy_kwarg="dummy_value",
423
- )
424
- mock_docker_container.status_callee.assert_called_once()
425
- mock_docker_container.wait_callee.assert_called_once_with()(timeout=1000)
426
- mock_docker_container.wait_callee.assert_called_once_with()()
427
- mock_docker_container.logs_callee.assert_called_once()
428
- mock_docker_container.stop_callee.assert_called_once()
429
- mock_docker_container.remove_callee.assert_called_once()
430
-
431
- data_docker_run_detached__with_exception_on_wait = [
432
- (requests.exceptions.ReadTimeout(),),
433
- (docker.errors.ImageNotFound("dummy message"),),
434
- (
435
- docker.errors.ContainerError("dummy container",
436
- "dummy exit status",
437
- "dummy command",
438
- "dummy image",
439
- "dummy stderr"),
440
- ),
441
- (docker.errors.APIError("dummy message"),),
442
- (Exception(),),
443
- ]
444
-
445
- @ddt.idata(data_docker_run_detached__with_exception_on_wait)
446
- @ddt.unpack
447
- def test_docker_run_detached__with_exception_on_wait(self, exception):
448
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
449
- def mock_containers_run_wait_valuer(*args, **kwargs):
450
- if kwargs == dict(timeout=1000):
451
- raise exception
452
-
453
- mock_docker_container = MockedDockerContainer("dummy_container",
454
- status_callee=return_callee("dummy_status"),
455
- wait_callee=return_callee(mock_containers_run_wait_valuer),
456
- logs_callee=return_callee("dummy log"),
457
- stop_callee=return_callee(),
458
- remove_callee=return_callee())
459
- mock_docker_client.return_value.containers.run.return_value = mock_docker_container
460
-
461
- with self.assertRaises(type(exception)):
462
- docker_run_detached(mock_docker_client.return_value,
463
- "dummy_image",
464
- "dummy_container",
465
- "dummy_command",
466
- {"/dummy/src/path": {"bind": "/dummy/dst/path", "mode": "rw"}},
467
- {"DUMMY_ENV_KEY": "DUMMY_ENV_VALUE"},
468
- {"dummy.ip.address": "127.0.0.1"},
469
- 1000,
470
- dummy_kwarg="dummy_value")
471
-
472
- mock_docker_client.return_value.containers.run.assert_called_with(
473
- image="dummy_image",
474
- name="dummy_container",
475
- command="dummy_command",
476
- volumes={"/dummy/src/path": {"bind": "/dummy/dst/path", "mode": "rw"}},
477
- environment={"DUMMY_ENV_KEY": "DUMMY_ENV_VALUE"},
478
- extra_hosts={"dummy.ip.address": "127.0.0.1"},
479
- detach=True,
480
- dummy_kwarg="dummy_value",
481
- )
482
- mock_docker_container.status_callee.assert_called_once()
483
- mock_docker_container.wait_callee.assert_called_once_with()(timeout=1000)
484
- mock_docker_container.wait_callee.assert_called_once_with()()
485
- mock_docker_container.logs_callee.assert_not_called()
486
- mock_docker_container.stop_callee.assert_called_once()
487
- mock_docker_container.remove_callee.assert_called_once()
488
-
489
- data_docker_run_detached__with_exception_on_stop = [
490
- (docker.errors.ImageNotFound("dummy message"),),
491
- (
492
- docker.errors.ContainerError("dummy container",
493
- "dummy exit status",
494
- "dummy command",
495
- "dummy image",
496
- "dummy stderr"),
497
- ),
498
- (docker.errors.APIError("dummy message"),),
499
- ]
500
-
501
- @ddt.idata(data_docker_run_detached__with_exception_on_stop)
502
- @ddt.unpack
503
- def test_docker_run_detached__with_exception_on_stop(self, exception):
504
- with unittest.mock.patch("iker.common.utils.dockerutils.docker.DockerClient") as mock_docker_client:
505
- def mock_containers_run_stop_valuer(*args, **kwargs):
506
- raise exception
507
-
508
- mock_docker_container = MockedDockerContainer("dummy_container",
509
- status_callee=return_callee("dummy_status"),
510
- wait_callee=return_callee({"dummy_key": "dummy_value"}),
511
- logs_callee=return_callee("dummy log"),
512
- stop_callee=return_callee(mock_containers_run_stop_valuer),
513
- remove_callee=return_callee())
514
- mock_docker_client.return_value.containers.run.return_value = mock_docker_container
515
-
516
- result, log = docker_run_detached(mock_docker_client.return_value,
517
- "dummy_image",
518
- "dummy_container",
519
- "dummy_command",
520
- {"/dummy/src/path": {"bind": "/dummy/dst/path", "mode": "rw"}},
521
- {"DUMMY_ENV_KEY": "DUMMY_ENV_VALUE"},
522
- {"dummy.ip.address": "127.0.0.1"},
523
- 1000,
524
- dummy_kwarg="dummy_value")
525
-
526
- self.assertEqual(result, {"dummy_key": "dummy_value"})
527
- self.assertEqual(log, "dummy log")
528
-
529
- mock_docker_client.return_value.containers.run.assert_called_with(
530
- image="dummy_image",
531
- name="dummy_container",
532
- command="dummy_command",
533
- volumes={"/dummy/src/path": {"bind": "/dummy/dst/path", "mode": "rw"}},
534
- environment={"DUMMY_ENV_KEY": "DUMMY_ENV_VALUE"},
535
- extra_hosts={"dummy.ip.address": "127.0.0.1"},
536
- detach=True,
537
- dummy_kwarg="dummy_value",
538
- )
539
- mock_docker_container.status_callee.assert_called_once()
540
- mock_docker_container.wait_callee.assert_called_once_with()(timeout=1000)
541
- mock_docker_container.wait_callee.assert_called_once_with()()
542
- mock_docker_container.logs_callee.assert_called_once()
543
- mock_docker_container.stop_callee.assert_called_once()
544
- mock_docker_container.remove_callee.assert_called_once()
@@ -1,79 +0,0 @@
1
- import docker
2
- import docker.errors
3
- import docker.models.containers
4
- import docker.models.images
5
- import docker.models.resource
6
-
7
- from iker.common.utils.testutils import CalleeMock
8
- from iker.common.utils.testutils import return_callee
9
-
10
- __all__ = [
11
- "MockedDockerClient",
12
- "MockedDockerImage",
13
- "MockedDockerContainer",
14
- ]
15
-
16
-
17
- class MockedDockerClient(docker.DockerClient):
18
- def __init__(self):
19
- # Do not call superclass init to avoid underlying API client being initialized
20
- pass
21
-
22
- def close(self):
23
- pass
24
-
25
-
26
- class MockedDockerImage(docker.models.resource.Model):
27
- def __init__(
28
- self,
29
- model_id: str,
30
- *,
31
- tags_callee: CalleeMock = return_callee(),
32
- labels_callee: CalleeMock = return_callee(),
33
- ):
34
- super(MockedDockerImage, self).__init__({docker.models.resource.Model.id_attribute: model_id})
35
- self.tags_callee = tags_callee
36
- self.labels_callee = labels_callee
37
-
38
- @property
39
- def tags(self):
40
- return self.tags_callee()
41
-
42
- @property
43
- def labels(self):
44
- return self.labels_callee()
45
-
46
-
47
- class MockedDockerContainer(docker.models.resource.Model):
48
- def __init__(
49
- self,
50
- model_id: str,
51
- *,
52
- status_callee: CalleeMock = return_callee(),
53
- wait_callee: CalleeMock = return_callee(),
54
- logs_callee: CalleeMock = return_callee(),
55
- stop_callee: CalleeMock = return_callee(),
56
- remove_callee: CalleeMock = return_callee(),
57
- ):
58
- super(MockedDockerContainer, self).__init__({docker.models.resource.Model.id_attribute: model_id})
59
- self.status_callee = status_callee
60
- self.wait_callee = wait_callee
61
- self.logs_callee = logs_callee
62
- self.stop_callee = stop_callee
63
- self.remove_callee = remove_callee
64
-
65
- @property
66
- def status(self):
67
- return self.status_callee()
68
-
69
- def wait(self, **kwargs):
70
- return self.wait_callee(**kwargs)
71
-
72
- def logs(self, **kwargs):
73
- return self.logs_callee(**kwargs)
74
-
75
- def stop(self, **kwargs):
76
- return self.stop_callee(**kwargs)
77
-
78
- def remove(self, **kwargs):
79
- return self.remove_callee(**kwargs)