Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reintroduce demisto-sdk to the new docker registry proxy #4655

Merged
merged 185 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 167 commits
Commits
Show all changes
185 commits
Select commit Hold shift + click to select a range
b463ad9
logger debug to info - debugging
samuelFain Aug 28, 2024
2e7fc8c
Use DockerHubClient registry from constants
samuelFain Sep 8, 2024
628a195
Fix url for DEFAULT_REGISTRY
samuelFain Sep 8, 2024
018ae53
add log
samuelFain Sep 8, 2024
a2a1850
add log
samuelFain Sep 8, 2024
1bcb17d
add log
samuelFain Sep 8, 2024
188acb3
Fix typo
samuelFain Sep 9, 2024
7d5ad8f
format
samuelFain Sep 9, 2024
8514fd2
add log
samuelFain Sep 9, 2024
e9b06b8
Add log
samuelFain Sep 9, 2024
b06b579
Merge branch 'master' into sf-move-sdk-to-new-docker-proxy
samuelFain Sep 9, 2024
e390199
test pull_docker_image_via_docker_sdk
samuelFain Sep 9, 2024
1c05c88
Add log
samuelFain Sep 9, 2024
7995417
Add log
samuelFain Sep 9, 2024
5a1ae24
Refactor pull_image_through_proxy func
samuelFain Sep 9, 2024
b683b4c
Test artifactregistry_v1
samuelFain Sep 9, 2024
ce3250b
Revert dockerhub_client artifactory changes
samuelFain Sep 10, 2024
51382aa
Add is_custom_registry() logs
samuelFain Sep 10, 2024
6c1eb25
Remove unsued artifactory lib import
samuelFain Sep 10, 2024
27efe25
Revert DEFAULT_REGISTRY value in dockerhub_client
samuelFain Sep 10, 2024
1fa8c1d
Revert DEFAULT_REGISTRY value in dockerhub_client
samuelFain Sep 10, 2024
01ef79e
Fix log
samuelFain Sep 10, 2024
00e1356
Fix log
samuelFain Sep 10, 2024
f634503
add DockerHub user in content CI case
samuelFain Sep 10, 2024
d7fe38b
Revert docker_login function logic
samuelFain Sep 10, 2024
0bfad61
switch deafult reg to DOCKER_REGISTRY_URL
samuelFain Sep 10, 2024
ef52edf
Uppdate do_registry_get_request
samuelFain Sep 10, 2024
546b9cb
Fix log typo
samuelFain Sep 10, 2024
71c55f5
Add log
samuelFain Sep 10, 2024
97244b4
Change response to json in do_registry_get_request
samuelFain Sep 11, 2024
8ac4336
test original get request with new proxy
samuelFain Sep 11, 2024
71efa1d
fix typo
samuelFain Sep 11, 2024
c988d04
Add logs
samuelFain Sep 11, 2024
65ec274
Add logs
samuelFain Sep 11, 2024
68a7c04
Add logs
samuelFain Sep 11, 2024
f44262c
Add logs
samuelFain Sep 11, 2024
ecfbc2c
Add logs; Better handle for docker_image object
samuelFain Sep 11, 2024
6bd7cab
Add logs
samuelFain Sep 11, 2024
df27ced
Add logs
samuelFain Sep 11, 2024
a2b5ff8
get_image_tag_metadata add call via registry
samuelFain Sep 11, 2024
165d6b1
Add condition to do_registry_get_request
samuelFain Sep 11, 2024
71be40a
Add logs
samuelFain Sep 11, 2024
6b9f4b2
Add logs
samuelFain Sep 11, 2024
3ceab13
Add logs
samuelFain Sep 11, 2024
8bceead
Add accept json header
samuelFain Sep 11, 2024
218c406
Update accept header
samuelFain Sep 11, 2024
c052380
Add logs
samuelFain Sep 11, 2024
8230ca1
Update logs
samuelFain Sep 11, 2024
977db59
Reomve token Authorization from header
samuelFain Sep 11, 2024
a5ff7c4
Test ArtifactRegistryClient
samuelFain Sep 11, 2024
daf1f8c
Fix docker name value
samuelFain Sep 12, 2024
af7cbc2
Remove redundant import; Fix logger typo
samuelFain Sep 12, 2024
11b19c0
Add logs
samuelFain Sep 12, 2024
b0d2a23
Run using original logic
samuelFain Sep 12, 2024
d2a3290
Revert to original logic; Add logs
samuelFain Sep 12, 2024
481afa0
Test init_global_docker_client in dockerhub_client
samuelFain Sep 12, 2024
4b10b72
Add init_global_docker_client, docker_login and is_custom_registry to…
samuelFain Sep 12, 2024
e5b3e92
Add CAN_MOUNT_FILES
samuelFain Sep 12, 2024
7acb031
Fix SyntaxError
samuelFain Sep 12, 2024
0348651
Add dockerhub proxy url; Add logs
samuelFain Sep 12, 2024
7fa3151
init_global_docker_client to do_registry-get-request
samuelFain Sep 12, 2024
288631b
Remove ssh from docker.from_env()
samuelFain Sep 12, 2024
33dc183
artifactory testing
samuelFain Sep 12, 2024
d0aade3
Senity check logs
samuelFain Sep 14, 2024
f340a2c
Move DockerHubRequestException from dockerhub_client to docker_helper
samuelFain Sep 15, 2024
9a82260
Update docker_image.py is_image_exist property
samuelFain Sep 15, 2024
5a65bd8
Solve circular import
samuelFain Sep 15, 2024
fe1f680
Update docker_image.py is_image_exist property
samuelFain Sep 15, 2024
d8fd1a8
Add full_image_name attribute; Add docstrings
samuelFain Sep 16, 2024
57283f0
Fix latest_tag attribute
samuelFain Sep 16, 2024
c4d4e64
Update latest_docker_image attribute
samuelFain Sep 16, 2024
40f5a0d
Fix typo
samuelFain Sep 16, 2024
92ea1be
Add logs
samuelFain Sep 16, 2024
1850f36
Test new is_custom_registry conditions
samuelFain Sep 16, 2024
a0a9c04
Test new is_custom_registry conditions
samuelFain Sep 16, 2024
b401e3e
Add logs
samuelFain Sep 16, 2024
7f63d85
test artifcatory client
samuelFain Sep 16, 2024
1fd7874
Revert to original code from master
samuelFain Sep 16, 2024
586dd7f
logger - debug to info
samuelFain Sep 16, 2024
490ccda
Merge branch 'master' into sf-move-sdk-to-new-docker-proxy
samuelFain Sep 16, 2024
5db3d69
Add logs
samuelFain Sep 16, 2024
7d23faa
Try fetching docker image via artifactory
samuelFain Sep 16, 2024
93cec8b
Remove demisto from request string
samuelFain Sep 16, 2024
0a0865e
try print images in artifactory
samuelFain Sep 16, 2024
ccbf80f
image request test
samuelFain Sep 16, 2024
0f357e4
Many more tries
samuelFain Sep 16, 2024
3a51601
more testing
samuelFain Sep 16, 2024
9d0ae6e
More logs
samuelFain Sep 16, 2024
fba3bbf
try tag
samuelFain Sep 16, 2024
d6a61ce
Try to list packages
samuelFain Sep 16, 2024
73c6d54
Move DockerImagesMetadata import inside function to prevent circualr …
samuelFain Sep 16, 2024
1099f4b
Import and init a DockerBase attr in docker_image.py
samuelFain Sep 16, 2024
e7ef85c
Test is_custom_registry if statement in docker_helper.py
samuelFain Sep 16, 2024
149b652
Update logs
samuelFain Sep 16, 2024
751fd78
Fix logs, add ping ping print in log
samuelFain Sep 16, 2024
4e017bf
revert is_custom_registry check back
samuelFain Sep 16, 2024
02ed3d2
Add missing not
samuelFain Sep 16, 2024
458a926
Fix logs
samuelFain Sep 16, 2024
a981855
Revert to origin
samuelFain Sep 17, 2024
1b0f65f
logger.debug to logger.info
samuelFain Sep 17, 2024
724b7ff
Add logs
samuelFain Sep 17, 2024
93f9d33
Test new DOCKER_CLIENT implementation
samuelFain Sep 17, 2024
4bbf40e
Print IS_CONTENT_GITLAB_CI
samuelFain Sep 17, 2024
2bbf352
Minor DOCKER_CLIENT logic fixes
samuelFain Sep 17, 2024
84c5db6
Comment IS_CONTENT_GITLAB_CI logic due to missing logs
samuelFain Sep 17, 2024
5d2f07c
Revert back to last known working logs
samuelFain Sep 17, 2024
82dd5b4
test pulling images from docker client via dockerhub proxy
samuelFain Sep 18, 2024
84571c4
Add CONTENT_GITLAB_CI usecase to init_global_docker_client
samuelFain Sep 18, 2024
3830e0c
Test docker_client get request using docker client in do_registry_get…
samuelFain Sep 18, 2024
d222ac0
dockerhub_client | add get via docker client in get_request
samuelFain Sep 18, 2024
05aa7b2
use _get_python_version_from_image_client when docker_client is avail…
samuelFain Sep 18, 2024
355486c
Add function logs
samuelFain Sep 18, 2024
f7b1299
Add docker_helper logs
samuelFain Sep 18, 2024
0c39cfa
Add docker_helper_client to docker_image.py
samuelFain Sep 18, 2024
63afd7f
start implementing google artifactory in dockerhub_client.py
samuelFain Sep 19, 2024
22a6ff4
Debug get_dockerhub_artifact_registry_url
samuelFain Sep 19, 2024
8baf131
Debug get_dockerhub_artifact_registry_url
samuelFain Sep 19, 2024
1b6b599
DockerHubClient sanity check
samuelFain Sep 19, 2024
50f01a4
Add debug logs
samuelFain Sep 19, 2024
ce0f1fe
Revert some logic changes
samuelFain Sep 19, 2024
13e3bed
logger.info to logger.debug
samuelFain Sep 19, 2024
d23b1a3
Added try-except in get_registry_api_url
samuelFain Sep 22, 2024
66babc6
Added test
samuelFain Sep 22, 2024
acc4d53
Comment redundent code
samuelFain Sep 22, 2024
732416e
Add test in DockerHub __init__
samuelFain Sep 22, 2024
b8e67ef
Remove sanity check in DockerClient __init__
samuelFain Sep 22, 2024
ca3f4bf
Add debug logs
samuelFain Sep 23, 2024
70fa62b
Fix debug logs
samuelFain Sep 23, 2024
344b079
Fix debug logs
samuelFain Sep 23, 2024
3b4962e
add logs
samuelFain Sep 23, 2024
1bf9cc7
Add logs in demisto-sdk __main__
samuelFain Sep 23, 2024
24f2fb6
Update logs
samuelFain Sep 23, 2024
9160191
validator_v2 logs
samuelFain Sep 23, 2024
f5bafd7
Test original dockerhub_client logic in Ci
samuelFain Sep 23, 2024
42aa941
Revert changes to original docker_helper
samuelFain Sep 23, 2024
2045283
Test original dockerhub_client logic in Ci
samuelFain Sep 23, 2024
02b882a
Test original dockerhub_client logic in Ci
samuelFain Sep 23, 2024
e90abfb
Comment out Google Artifactory functions
samuelFain Sep 23, 2024
e2c986b
Comment out Google Artifactory functions
samuelFain Sep 23, 2024
f74ba9f
Add artifactory logic to dockerhub_client
samuelFain Sep 24, 2024
0364348
Revert logs
samuelFain Sep 24, 2024
c9daa9c
Merge branch 'master' into sf-move-sdk-to-new-docker-proxy
samuelFain Sep 24, 2024
5362cc2
Un-comment CONTENT_GITLAB_CI usecase
samuelFain Sep 24, 2024
4581687
Update IS_CONTENT_GITLAB_CI usecase in docker_helper
samuelFain Sep 24, 2024
2c76f3c
Update docker_helper logs
samuelFain Sep 24, 2024
d520426
Update validate_manager.py
samuelFain Sep 24, 2024
12c2106
Update validate_manager.py
samuelFain Sep 24, 2024
1272c83
Update validate_manager.py
samuelFain Sep 24, 2024
7902e9e
Update validate_manager.py
samuelFain Sep 24, 2024
58120f7
Update dockerhub_client.py
samuelFain Sep 24, 2024
7abadee
Update docker_helper logs
samuelFain Sep 24, 2024
5c02fee
Update docker_image.py logs
samuelFain Sep 24, 2024
4361d5c
Update get_docker_image_tag_creation_date, get_image_tag_metadata
samuelFain Sep 24, 2024
79fbd0d
Update dockerhub_client logs
samuelFain Sep 24, 2024
5b5dcf0
Update docker_image.py
samuelFain Sep 24, 2024
7c4ac74
Update docker_helper logs
samuelFain Sep 24, 2024
ef99d69
Test docker_helper without IS_CONTENT_GITLAB_CI condition
samuelFain Sep 24, 2024
f1b4d17
Revert docker_helper without IS_CONTENT_GITLAB_CI condition
samuelFain Sep 24, 2024
6f3eaa1
Fix return statment to pass python 3.9 UTs
samuelFain Sep 25, 2024
a78b348
Merge branch 'master' into sf-move-sdk-to-new-docker-proxy
samuelFain Sep 25, 2024
f7583ce
Fix check-docstring-first pre-commit hook error
samuelFain Sep 26, 2024
f163417
Fix pre-commit ruff-format error
samuelFain Sep 26, 2024
df2451d
Merge branch 'master' into sf-move-sdk-to-new-docker-proxy
samuelFain Sep 26, 2024
0d33d1a
CR fixes
samuelFain Sep 26, 2024
cc839be
Added changlog
samuelFain Sep 26, 2024
49a436b
Merge branch 'sf-move-sdk-to-new-docker-proxy' into sf-reintroduce-do…
samuelFain Nov 11, 2024
e8fbb1d
Update changlog file
samuelFain Nov 11, 2024
24f4878
Merge branch 'master' into sf-reintroduce-docker-proxy
samuelFain Dec 8, 2024
0115b8f
Merge branch 'master' into sf-reintroduce-docker-proxy
samuelFain Dec 19, 2024
120d4e3
Merge branch 'master' into sf-reintroduce-docker-proxy
samuelFain Dec 22, 2024
8d4262e
Merge branch 'master' into sf-reintroduce-docker-proxy
samuelFain Dec 23, 2024
5a9d3c8
Merge branch 'master' into sf-reintroduce-docker-proxy
samuelFain Jan 7, 2025
955d792
Add debug logs to
samuelFain Jan 7, 2025
df15499
Add debug logs
samuelFain Jan 7, 2025
df1c024
Merge branch 'master' into sf-reintroduce-docker-proxy
samuelFain Jan 8, 2025
6df1493
add create incident logs
samuelFain Jan 8, 2025
4185289
debug to info
samuelFain Jan 8, 2025
6c3e981
add log
samuelFain Jan 8, 2025
8484af4
debug to info
samuelFain Jan 9, 2025
70a7c87
print json content in tools.py
samuelFain Jan 9, 2025
d72a3c2
comment json print
samuelFain Jan 9, 2025
c270c76
info to debug in docker modules in sdk
samuelFain Jan 9, 2025
effa4e3
Merge branch 'master' into sf-reintroduce-docker-proxy
samuelFain Jan 20, 2025
a6138a5
Revert debug logs to **original** info logs
samuelFain Jan 21, 2025
3cf8dae
Merge branch 'master' into sf-reintroduce-docker-proxy
samuelFain Jan 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changelog/4655.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- description: Reintroduce support for GAR DockerHub proxy when running in a Gitlab CI environment.
type: internal
pr_number: 4655
146 changes: 142 additions & 4 deletions demisto_sdk/commands/common/docker/dockerhub_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from typing import Any, Dict, List, Optional

import dateparser
import google.auth
import requests
from google.auth.transport.requests import Request
from packaging.version import InvalidVersion, Version
from requests.exceptions import ConnectionError, RequestException, Timeout

Expand All @@ -16,6 +18,8 @@
DOCKERHUB_USER = "DOCKERHUB_USER"
DOCKERHUB_PASSWORD = "DOCKERHUB_PASSWORD"
DEFAULT_REPOSITORY = "demisto"
IS_CONTENT_GITLAB_CI = os.getenv("CONTENT_GITLAB_CI")
DOCKER_IO = os.getenv("DOCKER_IO", "")


class DockerHubAuthScope(StrEnum):
Expand Down Expand Up @@ -49,7 +53,7 @@ def __init__(
password: str = "",
verify_ssl: bool = False,
):
self.registry_api_url = registry or self.DEFAULT_REGISTRY
self.registry_api_url = get_registry_api_url(registry, self.DEFAULT_REGISTRY)
self.docker_hub_api_url = docker_hub_api_url or self.DOCKER_HUB_API_BASE_URL
self.username = username or os.getenv(DOCKERHUB_USER, "")
self.password = password or os.getenv(DOCKERHUB_PASSWORD, "")
Expand Down Expand Up @@ -77,6 +81,18 @@ def get_token(
repo: the repository to retrieve the token for.
scope: the scope needed for the repository
"""
if IS_CONTENT_GITLAB_CI:
# If running in a Gitlab CI environment, try using the Google Cloud access token
logger.debug(
"Attempting to use Google Cloud access token for Docker Hub proxy authentication"
)
try:
if gcloud_access_token := get_gcloud_access_token():
logger.debug("returning gcloud_access_token")
return gcloud_access_token
except Exception as e:
logger.error(f"Failed to get gcloud access token: {e}")

if token_metadata := self._docker_hub_auth_tokens.get(f"{repo}:{scope}"):
now = datetime.now()
if expiration_time := dateparser.parse(token_metadata.get("issued_at")):
Expand Down Expand Up @@ -371,6 +387,10 @@ def get_image_tag_metadata(self, docker_image: str, tag: str) -> Dict[str, Any]:
tag: The tag of the docker image
"""
try:
if IS_CONTENT_GITLAB_CI:
image_digest = self.get_image_digest(docker_image, tag=tag)
response = self.get_image_blobs(docker_image, image_digest=image_digest)
return response
return self.do_docker_hub_get_request(
f"/repositories/{docker_image}/tags/{tag}"
)
Expand Down Expand Up @@ -416,9 +436,12 @@ def get_docker_image_tag_creation_date(
tag: The tag of the docker image
"""
response = self.get_image_tag_metadata(docker_image, tag=tag)
return datetime.strptime(
response.get("last_updated", ""), "%Y-%m-%dT%H:%M:%S.%fZ"
)
if creation_date := response.get("created"):
return datetime.strptime(creation_date, "%Y-%m-%dT%H:%M:%S.%fZ")
else:
return datetime.strptime(
response.get("last_updated", ""), "%Y-%m-%dT%H:%M:%S.%fZ"
samuelFain marked this conversation as resolved.
Show resolved Hide resolved
)

def get_latest_docker_image_tag(self, docker_image: str) -> Version:
"""
Expand Down Expand Up @@ -490,3 +513,118 @@ def get_repository_images_names(self, repo: str = DEFAULT_REPOSITORY) -> List[st
for image_metadata in self.get_repository_images(repo)
if image_metadata.get("name")
]


### Google Artifactory functions ###


def get_dockerhub_artifact_registry_url(base_path: str) -> str:
"""
Parses a DockerHub Google Artifact Registry internal base path into a base url for DockerHub proxy API calls.
See Confluence page: Shared-Services GCP Services - GAR.

Args:
base_path (str): The base path of the Google Artifact Registry in the format 'region-domain/project/repository'.

Returns:
str: The base URL for the DockerHub proxy API calls based on the provided Artifact Registry path.
Example: For base_path 'us-docker.pkg.dev/my-project/my-repo',
the returned URL would be 'https://region-domain-docker.pkg.dev/v2/my-project/my-repo'

Raises:
ValueError: If the input base_path is not in the expected format.
"""
logger.debug(
f"Trying to parse a DockerHub Google Artifact Registry internal base path {base_path=}"
)
# Split base path into region-domain, project, and repository
try:
region_domain, project, repository = base_path.split("/")
except ValueError:
raise ValueError(
"Invalid Artifact Registry path format. Expected format: 'region-domain/project/repository'"
)

# Construct and return the base URL for DockerHub proxy API calls
parsed_dockerhub_proxy_api_url = (
f"https://{region_domain}/v2/{project}/{repository}"
)
logger.debug(
f"Returning parsed DockerHub Google Artifact Registry API: {parsed_dockerhub_proxy_api_url=}"
)
return parsed_dockerhub_proxy_api_url


def get_registry_api_url(registry: str, default_registry: str) -> str:
"""
Determine the appropriate registry API URL based on the environment and provided parameters.

This function checks if the code is running in a GitLab CI environment and if a custom Docker.io URL is set.
If both conditions are true, it uses the custom Docker.io URL. Otherwise, it falls back to the provided
registry or the default registry.

Args:
registry (str): The registry URL provided by the user.
default_registry (str): The default registry URL to use if no custom URL is provided.

Returns:
str: The determined registry API URL to use for Docker operations.
"""
logger.debug(f"dockerhub_client | {IS_CONTENT_GITLAB_CI=}, {DOCKER_IO=}")
if IS_CONTENT_GITLAB_CI and DOCKER_IO:
try:
logger.info(
"Running in a GitLab CI environment with custom DOCKER_IO environment variable, Trying to prase a DockerHub Google Artifact Registry from DOCKER_IO environment variable."
)
if parsed_dockerhub_proxy_api_url := get_dockerhub_artifact_registry_url(
DOCKER_IO
):
return parsed_dockerhub_proxy_api_url
else:
logger.info(
"Could not parse a valid API URL from the DOCKER_IO environment variable."
)
except Exception as e:
logger.info(
f"Could not parse a valid API URL from the DOCKER_IO environment variable, Error: {str(e)} "
)

logger.info(f"using provided or default registry, {default_registry=}")
return registry or default_registry
samuelFain marked this conversation as resolved.
Show resolved Hide resolved


def get_gcloud_access_token() -> Optional[str]:
"""
Retrieves a Google Cloud access token using environment credentials.

This method attempts to obtain credentials from the environment and use them
to retrieve a valid Google Cloud access token. If successful, it returns the
token as a string. If unsuccessful, it returns None.

Returns:
str | None: The Google Cloud access token if successful, None otherwise.

Raises:
Exception: Any exception that occurs during the token retrieval process
is caught and logged, but not re-raised.
"""
try:
logger.debug("Trying to retrieve a Google Cloud access token.")
# Automatically obtain credentials from the environment
credentials, project_id = google.auth.default()

# Refresh the token if needed (ensures the token is valid)
credentials.refresh(Request())
# Extract the access token
access_token = credentials.token
if access_token:
logger.debug(
f"Successfully obtained Google Cloud access token, {project_id=}."
)
return access_token
else:
logger.debug("Failed to obtain Google Cloud access token.")
return None
except Exception as e:
logger.debug(f"Failed to get access token: {str(e)}")
return None
99 changes: 94 additions & 5 deletions demisto_sdk/commands/common/docker_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
from demisto_sdk.commands.common.logger import logger
from demisto_sdk.commands.common.tools import retry

IS_CONTENT_GITLAB_CI = os.getenv("CONTENT_GITLAB_CI")
DOCKER_IO = os.getenv("DOCKER_IO")
DOCKER_CLIENT = None
FILES_SRC_TARGET = List[Tuple[os.PathLike, str]]
# this will be used to determine if the system supports mounts
Expand All @@ -54,6 +56,34 @@ class DockerException(Exception):


def init_global_docker_client(timeout: int = 60, log_prompt: str = ""):
"""
Initialize and return a global Docker client to access and use a local Docker Daemon.

This function initializes a global Docker client if it doesn't exist, or returns the existing one.
It handles different environments, including GitLab CI, and attempts to log in to the Docker registry
if credentials are available.

Args:
timeout (int, optional): The timeout for Docker client operations in seconds. Defaults to 60.
log_prompt (str, optional): A prefix for log messages. Defaults to an empty string.

Returns:
docker.client.DockerClient: An initialized Docker client.

Raises:
docker.errors.DockerException: If initialization fails, likely due to Docker daemon not running.

Behavior:
1. Checks if a global Docker client already exists.
2. If in GitLab CI environment, attempts to create a client using the job environment.
3. If not in GitLab CI or if connecting via Gitlab CI environment fails,
attempts to log in to the Docker registry if credentials are available.
5. Logs various steps and outcomes of the initialization process.

Note:
- The function uses environment variables for Docker credentials.
- It handles both standard and SSH-based Docker connections.
"""
global DOCKER_CLIENT
if DOCKER_CLIENT is None:
if log_prompt:
Expand All @@ -63,6 +93,28 @@ def init_global_docker_client(timeout: int = 60, log_prompt: str = ""):
if ssh_client := os.getenv("DOCKER_SSH_CLIENT") is not None:
logger.debug(f"{log_prompt} - Using ssh client setting: {ssh_client}")
logger.debug(f"{log_prompt} - Using docker mounting: {CAN_MOUNT_FILES}")
try:
if IS_CONTENT_GITLAB_CI:
samuelFain marked this conversation as resolved.
Show resolved Hide resolved
"""In the case of running in Gitlab CI environment, try to init a docker client from the
job environment to utilize DockerHub API proxy requests (DOCKER_IO)"""
logger.info(
"Gitlab CI use case detected, trying to create docker client from Gitlab CI job environment."
)
DOCKER_CLIENT = docker.from_env()
if DOCKER_CLIENT.ping():
# see https://docker-py.readthedocs.io/en/stable/client.html#docker.client.DockerClient.ping for more information about ping().
logger.info(
"Successfully initialized docker client from Gitlab CI job environment."
)
return DOCKER_CLIENT
else:
logger.warning(
f"{log_prompt} - Failed to init docker client in Gitlab CI use case."
)
except docker.errors.DockerException:
logger.warning(
f"{log_prompt} - Failed to init docker client in CONTENT_GITLAB_CI use case. "
)
try:
DOCKER_CLIENT = docker.from_env(timeout=timeout, use_ssh_client=ssh_client) # type: ignore
except docker.errors.DockerException:
Expand Down Expand Up @@ -90,8 +142,7 @@ def init_global_docker_client(timeout: int = 60, log_prompt: str = ""):

def is_custom_registry():
return (
not os.getenv("CONTENT_GITLAB_CI")
and DOCKER_REGISTRY_URL != DEFAULT_DOCKER_REGISTRY_URL
not IS_CONTENT_GITLAB_CI and DOCKER_REGISTRY_URL != DEFAULT_DOCKER_REGISTRY_URL
)


Expand Down Expand Up @@ -153,6 +204,33 @@ def get_pip_requirements_from_file(requirements_file: Path) -> List[str]:


class DockerBase:
"""
Base class for Docker-related operations in the Demisto SDK.

This class utilizes any environment where a Docker Daemon is initialized,
and provides core functionality for working with Docker containers and images.

Attributes:
tmp_dir_name (tempfile.TemporaryDirectory): Temporary directory for Docker operations.
tmp_dir (Path): Path object for the temporary directory.
installation_scripts (dict): Mapping of container types to installation script paths.
changes (dict): Docker image changes for different container types.
requirements (Path): Path to the requirements.txt file.
_files_to_push_on_installation (List[Tuple[os.PathLike, str]]): Files to be pushed during installation.

Methods:
version(): Get the Docker version.
installation_files(container_type): Get installation files for a specific container type.
pull_image(image): Pull a Docker image.
is_image_available(image): Check if a Docker image is available.
copy_files_container(container, files): Copy files to a Docker container.
create_container(image, command, files_to_push, environment, **kwargs): Create a Docker container.
push_image(image, log_prompt): Push a Docker image to the repository.
create_image(base_image, image, container_type, install_packages, push, log_prompt): Create a new Docker image.
get_image_registry(image): Get the full image name with registry.
get_or_create_test_image(base_image, container_type, python_version, additional_requirements, push, should_pull, log_prompt): Get or create a test Docker image.
"""

def __init__(self):
self.tmp_dir_name = tempfile.TemporaryDirectory(
prefix=os.path.join(os.getcwd(), "tmp")
Expand Down Expand Up @@ -382,13 +460,13 @@ def create_image(
container.commit(
repository=repository, tag=tag, changes=self.changes[container_type]
)
if os.getenv("CONTENT_GITLAB_CI"):
if IS_CONTENT_GITLAB_CI:
container.commit(
repository=repository.replace(f"{DOCKER_REGISTRY_URL}/", ""),
tag=tag,
changes=self.changes[container_type],
)
if push and os.getenv("CONTENT_GITLAB_CI"):
if push and IS_CONTENT_GITLAB_CI:
self.push_image(image, log_prompt=log_prompt)
return image

Expand Down Expand Up @@ -659,6 +737,17 @@ def get_python_version(image: Optional[str]) -> Optional[Version]:
return python_version
logger.debug(f"Could not get python version for {image=} from regex")

if IS_CONTENT_GITLAB_CI:
try:
logger.debug(
f"get python version for {image=} from available docker client"
)
return _get_python_version_from_image_client(image)
except Exception:
logger.debug(
f"Could not get python version for {image=} from available docker client"
)

try:
logger.debug(f"get python version for {image=} from dockerhub api")
return _get_python_version_from_dockerhub_api(image)
Expand Down Expand Up @@ -710,7 +799,7 @@ def _get_python_version_from_dockerhub_api(image: str) -> Version:
raise ValueError(f"Invalid docker image: {image}")
else:
repo, tag = image.split(":")
if os.getenv("CONTENT_GITLAB_CI"):
if IS_CONTENT_GITLAB_CI:
# we need to remove the gitlab prefix, as we query the API
repo = repo.replace(f"{DOCKER_REGISTRY_URL}/", "")
try:
Expand Down