Skip to content

Commit 6f7cb72

Browse files
authored
Merge pull request #52 from SEKOIA-IO/feat/sync_library_registry
feat: Add registry info to docker images
2 parents fde1978 + dc14cdb commit 6f7cb72

File tree

4 files changed

+71
-133
lines changed

4 files changed

+71
-133
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- In `synchronize-lib` script:
13+
- Specify the registry in the image name
14+
- Improve checking the existence of the image in the registry
15+
1016
## [1.3.1] - 2023-06-06
1117

1218
### Changed

sekoia_automation/cli.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,24 +150,28 @@ def sync_library(
150150
check_image_on_registry: bool = typer.Option(
151151
False, help="Whether to check registry for existing image"
152152
),
153-
registry_pat: str = typer.Option(
154-
"", envvar="REGISTRY_PAT", help="Docker registry personal access token"
153+
registry: OptionalStr = typer.Option(
154+
None, envvar="REGISTRY", help="Docker registry"
155155
),
156-
registry_user: str = typer.Option(
157-
"", envvar="REGISTRY_USER", help="Docker registry username"
156+
namespace: OptionalStr = typer.Option(
157+
None, envvar="NAMESPACE", help="Docker namespace use by the images"
158+
),
159+
registry_pat: OptionalStr = typer.Option(
160+
None, envvar="REGISTRY_PAT", help="Docker registry personal access token"
158161
),
159162
):
160163
"""
161164
Synchronize the module library to Sekoia.io
162165
"""
163166
SyncLibrary(
164-
playbook_url,
165-
api_key,
166-
modules_path,
167-
registry_pat,
168-
registry_user,
169-
module,
170-
check_image_on_registry,
167+
playbook_url=playbook_url,
168+
api_key=api_key,
169+
modules_path=modules_path,
170+
module=module,
171+
registry_check=check_image_on_registry,
172+
registry=registry,
173+
namespace=namespace,
174+
registry_pat=registry_pat,
171175
).execute()
172176

173177

sekoia_automation/scripts/sync_library.py

Lines changed: 22 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
Load module library into database via the API
55
"""
6+
import base64
67
import json
78
import re
89
from base64 import b64encode
@@ -12,25 +13,25 @@
1213

1314
import requests
1415
import typer
15-
from requests.auth import HTTPBasicAuth
1616
from rich import print
1717

1818

1919
class SyncLibrary:
20-
DOCKER_PREFIX = "automation-module-"
20+
DOCKER_REGISTRY = "ghcr.io"
21+
DOCKER_NAMESPACE = "sekoia-io"
22+
DOCKER_PREFIX = "automation-module"
2123

2224
def __init__(
2325
self,
2426
playbook_url: str,
2527
api_key: str,
2628
modules_path: Path,
27-
registry_pat: str | None = None,
28-
registry_user: str | None = None,
2929
module: str = "",
3030
registry_check: bool = False,
31+
registry: str | None = None,
32+
namespace: str | None = None,
33+
registry_pat: str | None = None,
3134
):
32-
self.registry_pat = registry_pat
33-
self.registry_user = registry_user
3435
self.playbook_url = playbook_url
3536
self.api_key = api_key
3637
self.headers = {
@@ -39,7 +40,12 @@ def __init__(
3940
}
4041
self.modules_path = modules_path
4142
self.module = module
43+
4244
self.registry_check = registry_check
45+
self.registry = registry or self.DOCKER_REGISTRY
46+
self.namespace = namespace or self.DOCKER_NAMESPACE
47+
# In case of a public image any base64 encoded token works
48+
self.registry_pat = registry_pat or "none"
4349

4450
def pprint(
4551
self, created: list, updated: list, up_to_date: list, errors: list, nb_tabs: int
@@ -263,60 +269,37 @@ def get_module_logo(self, module_path: Path) -> str | None:
263269
with path_to_use.open("rb") as f:
264270
return f"{prefix}{b64encode(f.read()).decode('utf-8')}"
265271

266-
def check_image_on_registry(
267-
self, docker_image: str, docker_image_version: str
268-
) -> bool:
272+
def check_image_on_registry(self, docker_image: str, version: str) -> bool:
269273
"""Checks if a Docker image exists on a registry
270274
271275
If no registry is specified in the Module's manifest, we use a default value
272276
If the docker image name in the Module's manifest begins with a registry,
273277
this custom registry is used for the verification instead
274278
An image is considered to contain the registry path if it contains at least 2 /
275279
They delimit the path and the pathinfo fields
276-
e.g. my_registry.com/v2/my_docker_image
280+
e.g. my_registry.com/sekoia-io/my_docker_image
277281
278282
Args:
279283
docker_image (str): Docker image name as specified in the manifest
280-
docker_image_version (str): Docker image version
284+
version (str): Docker image version
281285
282286
Returns:
283287
bool: True if the image exists on the registry or if we don't have access
284288
to a registry
285289
False otherwise
286290
"""
287-
assert self.registry_user and self.registry_pat
288-
auth = HTTPBasicAuth(self.registry_user, self.registry_pat)
289-
290291
if match := re.match(r"(.*?)/(.*)/(.*)", docker_image):
291-
registry_path = match[1]
292-
registry_pathinfo = match[2]
292+
registry = match[1]
293+
namespace = match[2]
293294
image_name = match[3]
294295
else:
295-
registry_path = "ghcr.io"
296-
registry_pathinfo = "v2/sekoialab"
296+
registry = self.registry
297+
namespace = self.namespace
297298
image_name = docker_image
298299

300+
token = base64.b64encode(self.registry_pat.encode()).decode()
299301
response = requests.get(
300-
f"https://{registry_path}/token",
301-
params={
302-
"service": registry_path,
303-
"scope": "repository:<repo>:pull",
304-
"client_id": "symphony-docker-image",
305-
},
306-
auth=auth,
307-
)
308-
if not response.ok:
309-
print(
310-
f"[bold red][!] Authentication against the docker registry "
311-
f"failed with status {response.status_code}"
312-
)
313-
raise typer.Exit(code=1)
314-
315-
token = response.json()["token"]
316-
317-
response = requests.get(
318-
f"https://{registry_path}/{registry_pathinfo}/{image_name}/manifests/\
319-
{docker_image_version}",
302+
f"https://{registry}/v2/{namespace}/{image_name}/manifests/{version}",
320303
headers={
321304
"Authorization": f"Bearer {token}",
322305
"Accept": "application/vnd.docker.distribution.manifest.v2+json",
@@ -404,12 +387,6 @@ def execute(self):
404387
Otherwise, it will attempt to load all modules present in the library path
405388
specified
406389
"""
407-
if self.registry_check and not (self.registry_pat and self.registry_user):
408-
print(
409-
"[bold red][!] Credentials must be provided to check image in registry"
410-
)
411-
raise typer.Exit(code=1)
412-
413390
if not self.module:
414391
library_path = self.modules_path.absolute()
415392
print("Library path: ", library_path)
@@ -425,5 +402,5 @@ def _get_module_docker_name(self, manifest: dict) -> str:
425402
if docker := manifest.get("docker"):
426403
return docker
427404
if slug := manifest.get("slug"):
428-
return f"{self.DOCKER_PREFIX}{slug}"
405+
return f"{self.registry}/{self.namespace}/{self.DOCKER_PREFIX}-{slug}"
429406
raise ValueError("Impossible to generate image name")

0 commit comments

Comments
 (0)