holoscan 2.6.0__cp312-cp312-manylinux_2_35_aarch64.whl

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 (126) hide show
  1. holoscan-2.6.0.data/purelib/holoscan/__init__.py +133 -0
  2. holoscan-2.6.0.data/purelib/holoscan/cli/__init__.py +32 -0
  3. holoscan-2.6.0.data/purelib/holoscan/cli/__main__.py +159 -0
  4. holoscan-2.6.0.data/purelib/holoscan/cli/common/argparse_types.py +153 -0
  5. holoscan-2.6.0.data/purelib/holoscan/cli/common/artifact_sources.py +149 -0
  6. holoscan-2.6.0.data/purelib/holoscan/cli/common/constants.py +119 -0
  7. holoscan-2.6.0.data/purelib/holoscan/cli/common/dockerutils.py +509 -0
  8. holoscan-2.6.0.data/purelib/holoscan/cli/common/enum_types.py +52 -0
  9. holoscan-2.6.0.data/purelib/holoscan/cli/common/exceptions.py +130 -0
  10. holoscan-2.6.0.data/purelib/holoscan/cli/common/sdk_utils.py +180 -0
  11. holoscan-2.6.0.data/purelib/holoscan/cli/common/utils.py +130 -0
  12. holoscan-2.6.0.data/purelib/holoscan/cli/logging.json +37 -0
  13. holoscan-2.6.0.data/purelib/holoscan/cli/nics/__init__.py +18 -0
  14. holoscan-2.6.0.data/purelib/holoscan/cli/nics/nics.py +34 -0
  15. holoscan-2.6.0.data/purelib/holoscan/cli/packager/__init__.py +18 -0
  16. holoscan-2.6.0.data/purelib/holoscan/cli/packager/arguments.py +137 -0
  17. holoscan-2.6.0.data/purelib/holoscan/cli/packager/config_reader.py +181 -0
  18. holoscan-2.6.0.data/purelib/holoscan/cli/packager/container_builder.py +368 -0
  19. holoscan-2.6.0.data/purelib/holoscan/cli/packager/manifest_files.py +220 -0
  20. holoscan-2.6.0.data/purelib/holoscan/cli/packager/models.py +93 -0
  21. holoscan-2.6.0.data/purelib/holoscan/cli/packager/package_command.py +189 -0
  22. holoscan-2.6.0.data/purelib/holoscan/cli/packager/packager.py +122 -0
  23. holoscan-2.6.0.data/purelib/holoscan/cli/packager/parameters.py +558 -0
  24. holoscan-2.6.0.data/purelib/holoscan/cli/packager/platforms.py +402 -0
  25. holoscan-2.6.0.data/purelib/holoscan/cli/packager/templates/Dockerfile.jinja2 +470 -0
  26. holoscan-2.6.0.data/purelib/holoscan/cli/packager/templates/dockerignore +93 -0
  27. holoscan-2.6.0.data/purelib/holoscan/cli/packager/templates/tools.sh +416 -0
  28. holoscan-2.6.0.data/purelib/holoscan/cli/py.typed +0 -0
  29. holoscan-2.6.0.data/purelib/holoscan/cli/runner/__init__.py +18 -0
  30. holoscan-2.6.0.data/purelib/holoscan/cli/runner/resources.py +174 -0
  31. holoscan-2.6.0.data/purelib/holoscan/cli/runner/run_command.py +203 -0
  32. holoscan-2.6.0.data/purelib/holoscan/cli/runner/runner.py +306 -0
  33. holoscan-2.6.0.data/purelib/holoscan/cli/version/__init__.py +18 -0
  34. holoscan-2.6.0.data/purelib/holoscan/cli/version/version.py +50 -0
  35. holoscan-2.6.0.data/purelib/holoscan/conditions/__init__.py +57 -0
  36. holoscan-2.6.0.data/purelib/holoscan/core/__init__.py +430 -0
  37. holoscan-2.6.0.data/purelib/holoscan/decorator.py +592 -0
  38. holoscan-2.6.0.data/purelib/holoscan/executors/__init__.py +26 -0
  39. holoscan-2.6.0.data/purelib/holoscan/graphs/__init__.py +32 -0
  40. holoscan-2.6.0.data/purelib/holoscan/gxf/__init__.py +57 -0
  41. holoscan-2.6.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper.so +0 -0
  42. holoscan-2.6.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper_lib.so +0 -0
  43. holoscan-2.6.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan.so +0 -0
  44. holoscan-2.6.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan_lib.so +0 -0
  45. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_app.so +0 -0
  46. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_core.so +0 -0
  47. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_cuda.so +0 -0
  48. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_logger.so +0 -0
  49. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_multimedia.so +0 -0
  50. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_rmm.so +0 -0
  51. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_sample.so +0 -0
  52. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_serialization.so +0 -0
  53. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_std.so +0 -0
  54. holoscan-2.6.0.data/purelib/holoscan/lib/libgxf_ucx.so +0 -0
  55. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_core.so.2.6.0 +0 -0
  56. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_infer.so.2.6.0 +0 -0
  57. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_infer_onnx_runtime.so.2.6.0 +0 -0
  58. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_infer_torch.so.2.6.0 +0 -0
  59. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_infer_utils.so.2.6.0 +0 -0
  60. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_logger.so.2.6.0 +0 -0
  61. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_aja.so.2.6.0 +0 -0
  62. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_rx.so.2.6.0 +0 -0
  63. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_tx.so.2.6.0 +0 -0
  64. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_bayer_demosaic.so.2.6.0 +0 -0
  65. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_format_converter.so.2.6.0 +0 -0
  66. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_gxf_codelet.so.2.6.0 +0 -0
  67. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_holoviz.so.2.6.0 +0 -0
  68. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_inference.so.2.6.0 +0 -0
  69. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_inference_processor.so.2.6.0 +0 -0
  70. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_ping_rx.so.2.6.0 +0 -0
  71. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_ping_tensor_rx.so.2.6.0 +0 -0
  72. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_ping_tensor_tx.so.2.6.0 +0 -0
  73. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_ping_tx.so.2.6.0 +0 -0
  74. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_segmentation_postprocessor.so.2.6.0 +0 -0
  75. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_v4l2.so.2.6.0 +0 -0
  76. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_recorder.so.2.6.0 +0 -0
  77. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_replayer.so.2.6.0 +0 -0
  78. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_profiler.so.2.6.0 +0 -0
  79. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_spdlog_logger.so.2.6.0 +0 -0
  80. holoscan-2.6.0.data/purelib/holoscan/lib/libholoscan_viz.so.2.6.0 +0 -0
  81. holoscan-2.6.0.data/purelib/holoscan/lib/libucm.so.0.0.0 +0 -0
  82. holoscan-2.6.0.data/purelib/holoscan/lib/libucp.so.0.0.0 +0 -0
  83. holoscan-2.6.0.data/purelib/holoscan/lib/libucs.so.0.0.0 +0 -0
  84. holoscan-2.6.0.data/purelib/holoscan/lib/libucs_signal.so.0.0.0 +0 -0
  85. holoscan-2.6.0.data/purelib/holoscan/lib/libuct.so.0.0.0 +0 -0
  86. holoscan-2.6.0.data/purelib/holoscan/lib/libyaml-cpp.so.0.7.0 +0 -0
  87. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libucm_cuda.so.0.0.0 +0 -0
  88. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libucs_fuse.so.0.0.0 +0 -0
  89. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_cma.so.0.0.0 +0 -0
  90. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_cuda.so.0.0.0 +0 -0
  91. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_cuda_gdrcopy.so.0.0.0 +0 -0
  92. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_ib.so.0.0.0 +0 -0
  93. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_rdmacm.so.0.0.0 +0 -0
  94. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libuct_xpmem.so.0.0.0 +0 -0
  95. holoscan-2.6.0.data/purelib/holoscan/lib/ucx/libucx_perftest_cuda.so.0.0.0 +0 -0
  96. holoscan-2.6.0.data/purelib/holoscan/logger/__init__.py +37 -0
  97. holoscan-2.6.0.data/purelib/holoscan/network_contexts/__init__.py +28 -0
  98. holoscan-2.6.0.data/purelib/holoscan/operators/__init__.py +97 -0
  99. holoscan-2.6.0.data/purelib/holoscan/operators/aja_source/__init__.py +22 -0
  100. holoscan-2.6.0.data/purelib/holoscan/operators/bayer_demosaic/__init__.py +24 -0
  101. holoscan-2.6.0.data/purelib/holoscan/operators/format_converter/__init__.py +23 -0
  102. holoscan-2.6.0.data/purelib/holoscan/operators/gxf_codelet/__init__.py +67 -0
  103. holoscan-2.6.0.data/purelib/holoscan/operators/holoviz/__init__.py +424 -0
  104. holoscan-2.6.0.data/purelib/holoscan/operators/inference/__init__.py +23 -0
  105. holoscan-2.6.0.data/purelib/holoscan/operators/inference_processor/__init__.py +23 -0
  106. holoscan-2.6.0.data/purelib/holoscan/operators/ping_rx/__init__.py +45 -0
  107. holoscan-2.6.0.data/purelib/holoscan/operators/ping_tensor_rx/__init__.py +22 -0
  108. holoscan-2.6.0.data/purelib/holoscan/operators/ping_tensor_tx/__init__.py +22 -0
  109. holoscan-2.6.0.data/purelib/holoscan/operators/ping_tx/__init__.py +46 -0
  110. holoscan-2.6.0.data/purelib/holoscan/operators/segmentation_postprocessor/__init__.py +23 -0
  111. holoscan-2.6.0.data/purelib/holoscan/operators/v4l2_video_capture/__init__.py +23 -0
  112. holoscan-2.6.0.data/purelib/holoscan/operators/video_stream_recorder/__init__.py +22 -0
  113. holoscan-2.6.0.data/purelib/holoscan/operators/video_stream_replayer/__init__.py +22 -0
  114. holoscan-2.6.0.data/purelib/holoscan/resources/__init__.py +147 -0
  115. holoscan-2.6.0.data/purelib/holoscan/schedulers/__init__.py +32 -0
  116. holoscan-2.6.0.data/purelib/holoscan-2.6.0.pth +1 -0
  117. holoscan-2.6.0.dist-info/LICENSE.txt +202 -0
  118. holoscan-2.6.0.dist-info/METADATA +125 -0
  119. holoscan-2.6.0.dist-info/NOTICE.txt +174 -0
  120. holoscan-2.6.0.dist-info/NVIDIA-AI-PRODUCT-EULA.txt +243 -0
  121. holoscan-2.6.0.dist-info/RECORD +126 -0
  122. holoscan-2.6.0.dist-info/WHEEL +5 -0
  123. holoscan-2.6.0.dist-info/axle.lck +0 -0
  124. holoscan-2.6.0.dist-info/entry_points.txt +3 -0
  125. holoscan-2.6.0.dist-info/symlinks.txt +82 -0
  126. holoscan-2.6.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,119 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ from pathlib import Path
19
+
20
+ from .enum_types import Arch, Platform, PlatformConfiguration, SdkType
21
+
22
+
23
+ class DefaultValues:
24
+ """
25
+ This class contains default values for various parameters.
26
+ """
27
+
28
+ API_VERSION = "1.0.0" # MAP/HAP version number
29
+ DOCKER_FILE_NAME = "Dockerfile" # Filename of the generated Dockerfile
30
+ TIMEOUT = 0 # Default application timeout
31
+ USERNAME = "holoscan" # Default user to be created in the container
32
+ BUILD_CACHE_DIR = Path(
33
+ "~/.holoscan_build_cache"
34
+ ) # A local directory used for storing Docker build cache
35
+
36
+ HOLOSCAN_APP_DIR = Path("/opt/holoscan/app") # Path to user's application
37
+ HOLOSCAN_CONFIG_PATH = Path("/var/holoscan/app.yaml") # Path to the application config file
38
+ HOLOSCAN_DOCS_DIR = Path("/opt/holoscan/docs") # Path to documentation
39
+ HOLOSCAN_LOGS_DIR = Path("/var/holoscan/logs") # Path to application logs
40
+ INPUT_DIR = "input/" # Relative path to application input data
41
+ MODELS_DIR = Path("/opt/holoscan/models/") # Path to user provided model(s)
42
+ OUTPUT_DIR = "output/" # Relative path to application generated results
43
+ WORK_DIR = Path("/var/holoscan/") # Default working directory
44
+ APP_MANIFEST_PATH = "/etc/holoscan/app.json" # Path to app.json manifest file
45
+ PKG_MANIFEST_PATH = "/etc/holoscan/pkg.json" # Path to pkg.json manifest file
46
+
47
+ DEFAULT_SHM_SIZE = 1073741824
48
+
49
+
50
+ class Constants:
51
+ CPP_CMAKELIST_FILE = "CMakeLists.txt"
52
+ PYTHON_EXECUTABLE = "python3"
53
+ PYTHON_MAIN_FILE = "__main__.py"
54
+
55
+ TARBALL_FILE_EXTENSION = ".tar"
56
+
57
+ DEBIAN_FILE_EXTENSION = ".deb"
58
+ PYPI_WHEEL_FILE_EXTENSION = ".whl"
59
+ PYPI_TARGZ_FILE_EXTENSION = ".gz"
60
+ PYTHON_FILE_EXTENSION = ".py"
61
+
62
+ PYPI_FILE_EXTENSIONS = [PYPI_WHEEL_FILE_EXTENSION, PYPI_TARGZ_FILE_EXTENSION]
63
+
64
+ LOCAL_BUILDX_BUILDER_NAME = "holoscan_app_builder"
65
+ LOCAL_DOCKER_REGISTRY_NAME = "holoscan_build_registry"
66
+ LOCAL_REGISTRY_IMAGE_NAME = "registry:2"
67
+ LOCAL_REGISTRY_HOST = "localhost"
68
+ LOCAL_REGISTRY_INTERNAL_PORT = "5000/tcp"
69
+
70
+ RESOURCE_SHARED_MEMORY_KEY = "sharedMemory"
71
+
72
+
73
+ class SDK:
74
+ """
75
+ This class contains lookup tables for various platform and SDK settings.
76
+
77
+ """
78
+
79
+ # Platform to architecture mappings
80
+ PLATFORM_MAPPINGS = {
81
+ Platform.IGXOrinDevIt: Arch.arm64,
82
+ Platform.JetsonAgxOrinDevKit: Arch.arm64,
83
+ Platform.SBSA: Arch.arm64,
84
+ Platform.X64Workstation: Arch.amd64,
85
+ }
86
+
87
+ # Values of all platforms supported by the Packager
88
+ PLATFORMS = [
89
+ Platform.IGXOrinDevIt.value,
90
+ Platform.JetsonAgxOrinDevKit.value,
91
+ Platform.SBSA.value,
92
+ Platform.X64Workstation.value,
93
+ ]
94
+
95
+ # Values of all platform configurations supported by the Packager
96
+ PLATFORM_CONFIGS = [
97
+ PlatformConfiguration.iGPU.value,
98
+ PlatformConfiguration.dGPU.value,
99
+ ]
100
+
101
+ # Values of SDKs supported by the Packager
102
+ SDKS = [SdkType.Holoscan.value, SdkType.MonaiDeploy.value]
103
+
104
+
105
+ class EnvironmentVariables:
106
+ """
107
+ This class includes all environment variables set in
108
+ the container and in the app.json manifest file."""
109
+
110
+ HOLOSCAN_APPLICATION = "HOLOSCAN_APPLICATION"
111
+ HOLOSCAN_INPUT_PATH = "HOLOSCAN_INPUT_PATH"
112
+ HOLOSCAN_OUTPUT_PATH = "HOLOSCAN_OUTPUT_PATH"
113
+ HOLOSCAN_WORKDIR = "HOLOSCAN_WORKDIR"
114
+ HOLOSCAN_MODEL_PATH = "HOLOSCAN_MODEL_PATH"
115
+ HOLOSCAN_CONFIG_PATH = "HOLOSCAN_CONFIG_PATH"
116
+ HOLOSCAN_APP_MANIFEST_PATH = "HOLOSCAN_APP_MANIFEST_PATH"
117
+ HOLOSCAN_PKG_MANIFEST_PATH = "HOLOSCAN_PKG_MANIFEST_PATH"
118
+ HOLOSCAN_DOCS_PATH = "HOLOSCAN_DOCS_PATH"
119
+ HOLOSCAN_LOGS_PATH = "HOLOSCAN_LOGS_PATH"
@@ -0,0 +1,509 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ import json
19
+ import logging
20
+ import os
21
+ import posixpath
22
+ import re
23
+ import subprocess
24
+ from pathlib import Path
25
+ from typing import Optional
26
+
27
+ from python_on_whales import docker
28
+
29
+ from ..common.utils import run_cmd_output
30
+ from .constants import DefaultValues, EnvironmentVariables
31
+ from .enum_types import PlatformConfiguration, SdkType
32
+ from .exceptions import GpuResourceError, InvalidManifestError, RunContainerError
33
+ from .utils import get_gpu_count, get_requested_gpus
34
+
35
+ logger = logging.getLogger("common")
36
+
37
+
38
+ def parse_docker_image_name_and_tag(image_name: str) -> tuple[Optional[str], Optional[str]]:
39
+ """Parse a given Docker image name and tag.
40
+
41
+ Args:
42
+ image_name (str): Docker image name and optionally a tag
43
+
44
+ Returns:
45
+ Tuple[Optional[str], Optional[str]]: a tuple with first item as the name of the image
46
+ and tag as the second item
47
+ """
48
+ match = re.search(
49
+ r"^(?P<name>([\w.\-_]+((:\d+|)(?=/[a-z0-9._-]+/[a-z0-9._-]+))|)(/?)([a-z0-9.\-_/]+(/[a-z0-9.\-_]+|)))(:(?P<tag>[\w.\-_]{1,127})|)$",
50
+ image_name,
51
+ )
52
+
53
+ if match is None or match.group("name") is None:
54
+ return None, None
55
+
56
+ name = match.group("name")
57
+ tag = match.group("tag") if match.group("tag") else None
58
+
59
+ return (name, tag)
60
+
61
+
62
+ def create_or_use_network(network: Optional[str], image_name: Optional[str]) -> str:
63
+ """Create a Docker network by the given name if not already exists.
64
+
65
+ Args:
66
+ network (Optional[str]): name of the network to create
67
+ image_name (Optional[str]): name of the image used to generate a network name from
68
+
69
+ Raises:
70
+ RunContainerError: when unable to retrieve the specified network or failed to create one.
71
+
72
+ Returns:
73
+ str: network name
74
+ """
75
+ if network is None and image_name is not None:
76
+ network = image_name.split(":")[0]
77
+ network += "-network"
78
+
79
+ assert network is not None
80
+
81
+ try:
82
+ networks = docker.network.list(filters={"name": f"^{network}$"})
83
+ if len(networks) > 0:
84
+ return networks[0].name
85
+ except Exception as ex:
86
+ raise RunContainerError(f"error retrieving network information: {ex}") from ex
87
+
88
+ try:
89
+ return docker.network.create(network, driver="bridge").name
90
+ except Exception as ex:
91
+ raise RunContainerError(f"error creating Docker network: {ex}") from ex
92
+
93
+
94
+ def image_exists(image_name: str) -> bool:
95
+ """Checks if the Docker image exists.
96
+
97
+ Args:
98
+ image_name (str): name of the Docker image
99
+
100
+ Returns:
101
+ bool: whether the image exists or not.
102
+ """
103
+ if image_name is None:
104
+ return False
105
+ try:
106
+ if not docker.image.exists(image_name):
107
+ logger.info(f"Attempting to pull image {image_name}..")
108
+ docker.image.pull(image_name)
109
+ return docker.image.exists(image_name)
110
+ except Exception as e:
111
+ logger.error(str(e))
112
+ return False
113
+
114
+
115
+ def docker_export_tarball(file: str, tag: str):
116
+ """Exports the docker image to a file
117
+
118
+ Args:
119
+ file (str): name of the exported file
120
+ tag (str): source Docker image tag
121
+ """
122
+ docker.image.save(tag, file)
123
+
124
+
125
+ def create_and_get_builder(builder_name: str):
126
+ """Creates a Docker BuildX builder
127
+
128
+ Args:
129
+ builder_name (str): name of the builder to create
130
+
131
+ Returns:
132
+ _type_: name of the builder created
133
+ """
134
+ builders = docker.buildx.list()
135
+ for builder in builders:
136
+ if builder.name == builder_name:
137
+ logger.info(f"Using existing Docker BuildKit builder `{builder_name}`")
138
+ return builder_name
139
+
140
+ logger.info(f"Creating Docker BuildKit builder `{builder_name}` using `docker-container`")
141
+ builder = docker.buildx.create(
142
+ name=builder_name, driver="docker-container", driver_options={"network": "host"}
143
+ )
144
+ return builder.name
145
+
146
+
147
+ def build_docker_image(**kwargs):
148
+ """Builds a Docker image"""
149
+ _ = docker.buildx.build(**kwargs)
150
+
151
+
152
+ def docker_run(
153
+ name: str,
154
+ image_name: str,
155
+ input_path: Optional[Path],
156
+ output_path: Optional[Path],
157
+ app_info: dict,
158
+ pkg_info: dict,
159
+ quiet: bool,
160
+ commands: list[str],
161
+ network: str,
162
+ network_interface: Optional[str],
163
+ use_all_nics: bool,
164
+ gpu_enum: Optional[str],
165
+ config: Optional[Path],
166
+ render: bool,
167
+ user: str,
168
+ terminal: bool,
169
+ devices: list[str],
170
+ platform_config: str,
171
+ shared_memory_size: str = "1GB",
172
+ is_root: bool = False,
173
+ ):
174
+ """Creates and runs a Docker container
175
+
176
+ `HOLOSCAN_HOSTING_SERVICE` environment variable is used for hiding the help message
177
+ inside the tools.sh when the users run the container using holoscan run.
178
+
179
+ Args:
180
+ image_name (str): Docker image name
181
+ input_path (Optional[Path]): input data path
182
+ output_path (Optional[Path]): output data path
183
+ app_info (dict): app manifest
184
+ pkg_info (dict): package manifest
185
+ quiet (bool): prints only stderr when True, otherwise, prints all logs
186
+ commands (List[str]): list of arguments to provide to the container
187
+ network (str): Docker network to associate the container with
188
+ network_interface (Optional[str]): Name of the network interface for setting
189
+ UCX_NET_DEVICES
190
+ use_all_nics (bool): Sets UCX_CM_USE_ALL_DEVICES to 'y' if True
191
+ config (Optional[Path]): optional configuration file for overriding the embedded one
192
+ render (bool): whether or not to enable graphic rendering
193
+ user (str): UID and GID to associate with the container
194
+ terminal (bool): whether or not to enter bash terminal
195
+ devices (List[str]): list of devices to be mapped into the container
196
+ platformConfig (str): platform configuration value used when packaging the application,
197
+ shared_memory_size (str): size of /dev/shm,
198
+ is_root (bool): whether the user is root (UID = 0) or not
199
+ """
200
+ volumes = []
201
+ environment_variables = {
202
+ "NVIDIA_DRIVER_CAPABILITIES": "all",
203
+ "HOLOSCAN_HOSTING_SERVICE": "HOLOSCAN_RUN",
204
+ "UCX_CM_USE_ALL_DEVICES": "y" if use_all_nics else "n",
205
+ }
206
+
207
+ if network_interface is not None:
208
+ environment_variables["UCX_NET_DEVICES"] = network_interface
209
+
210
+ if logger.root.level == logging.DEBUG:
211
+ environment_variables["UCX_LOG_LEVEL"] = "DEBUG"
212
+ environment_variables["VK_LOADER_DEBUG"] = "all"
213
+
214
+ if render:
215
+ volumes.append(("/tmp/.X11-unix", "/tmp/.X11-unix"))
216
+ display = os.environ.get("DISPLAY", None)
217
+ if display is not None:
218
+ environment_variables["DISPLAY"] = display
219
+ xdg_session_type = os.environ.get("XDG_SESSION_TYPE", None)
220
+ if xdg_session_type is not None:
221
+ environment_variables["XDG_SESSION_TYPE"] = xdg_session_type
222
+ xdg_runtime_dir = os.environ.get("XDG_RUNTIME_DIR", None)
223
+ if xdg_runtime_dir is not None:
224
+ volumes.append((xdg_runtime_dir, xdg_runtime_dir))
225
+ environment_variables["XDG_RUNTIME_DIR"] = xdg_runtime_dir
226
+ wayland_display = os.environ.get("WAYLAND_DISPLAY", None)
227
+ if wayland_display is not None:
228
+ environment_variables["WAYLAND_DISPLAY"] = wayland_display
229
+
230
+ # Use user-specified --gpu values
231
+ if gpu_enum is not None:
232
+ environment_variables["NVIDIA_VISIBLE_DEVICES"] = gpu_enum
233
+ # If the image was built for iGPU but the system is configured for dGPU, attempt
234
+ # targeting the system's iGPU using the CDI spec
235
+ elif platform_config == PlatformConfiguration.iGPU.value and not _host_is_native_igpu():
236
+ environment_variables["NVIDIA_VISIBLE_DEVICES"] = "nvidia.com/igpu=0"
237
+ logger.info(
238
+ "Attempting to run an image for iGPU (integrated GPU) on a system configured "
239
+ "with a dGPU (discrete GPU). If this is correct (ex: IGX Orin developer kit), "
240
+ "make sure to enable iGPU on dGPU support as described in your developer kit "
241
+ "user guide. If not, either rebuild the image for dGPU or run this image on a "
242
+ "system configured for iGPU only (ex: Jetson AGX, Nano...)."
243
+ )
244
+ # Otherwise, read specs from package manifest
245
+ else:
246
+ requested_gpus = get_requested_gpus(pkg_info)
247
+ available_gpus = get_gpu_count()
248
+
249
+ if available_gpus < requested_gpus:
250
+ raise GpuResourceError(
251
+ f"Available GPUs ({available_gpus}) are less than required ({requested_gpus}). "
252
+ )
253
+
254
+ if requested_gpus == 0:
255
+ environment_variables["NVIDIA_VISIBLE_DEVICES"] = "all"
256
+ else:
257
+ environment_variables["NVIDIA_VISIBLE_DEVICES"] = ",".join(
258
+ map(str, range(0, requested_gpus))
259
+ )
260
+
261
+ if "path" in app_info["input"]:
262
+ mapped_input = Path(app_info["input"]["path"]).as_posix()
263
+ else:
264
+ mapped_input = DefaultValues.INPUT_DIR
265
+
266
+ if not posixpath.isabs(mapped_input):
267
+ mapped_input = posixpath.join(app_info["workingDirectory"], mapped_input)
268
+ if input_path is not None:
269
+ volumes.append((str(input_path), mapped_input))
270
+
271
+ if "path" in app_info["output"]:
272
+ mapped_output = Path(app_info["output"]["path"]).as_posix()
273
+ else:
274
+ mapped_output = DefaultValues.INPUT_DIR
275
+
276
+ if not posixpath.isabs(mapped_output):
277
+ mapped_output = posixpath.join(app_info["workingDirectory"], mapped_output)
278
+ if output_path is not None:
279
+ volumes.append((str(output_path), mapped_output))
280
+
281
+ for env in app_info["environment"]:
282
+ if env == EnvironmentVariables.HOLOSCAN_INPUT_PATH:
283
+ environment_variables[env] = mapped_input
284
+ elif env == EnvironmentVariables.HOLOSCAN_OUTPUT_PATH:
285
+ environment_variables[env] = mapped_output
286
+ else:
287
+ environment_variables[env] = app_info["environment"][env]
288
+
289
+ # always pass path to config file for Holoscan apps
290
+ if (
291
+ "sdk" in app_info
292
+ and app_info["sdk"] == SdkType.Holoscan.value
293
+ and env == EnvironmentVariables.HOLOSCAN_CONFIG_PATH
294
+ ):
295
+ commands.append("--config")
296
+ commands.append(environment_variables[env])
297
+
298
+ if config is not None:
299
+ if EnvironmentVariables.HOLOSCAN_CONFIG_PATH not in app_info["environment"]:
300
+ raise InvalidManifestError(
301
+ "The application manifest does not contain a required "
302
+ f"environment variable: '{EnvironmentVariables.HOLOSCAN_CONFIG_PATH}'"
303
+ )
304
+ volumes.append(
305
+ (
306
+ str(config),
307
+ app_info["environment"][EnvironmentVariables.HOLOSCAN_CONFIG_PATH],
308
+ )
309
+ )
310
+ logger.info(f"Using user provided configuration file: {config}")
311
+
312
+ logger.debug(
313
+ f"Environment variables: {json.dumps(environment_variables, indent=4, sort_keys=True)}"
314
+ )
315
+ logger.debug(f"Volumes: {json.dumps(volumes, indent=4, sort_keys=True)}")
316
+ logger.debug(f"Shared memory size: {shared_memory_size}")
317
+
318
+ ipc_mode = "host" if shared_memory_size is None else None
319
+ ulimits = [
320
+ "memlock=-1",
321
+ "stack=67108864",
322
+ ]
323
+ additional_devices, group_adds = _additional_devices_to_mount(is_root)
324
+ devices.extend(additional_devices)
325
+
326
+ video_group = run_cmd_output('/usr/bin/cat /etc/group | grep "video" | cut -d: -f3').strip()
327
+ if not is_root and video_group not in group_adds:
328
+ group_adds.append(video_group)
329
+
330
+ if terminal:
331
+ _enter_terminal(
332
+ name,
333
+ image_name,
334
+ app_info,
335
+ network,
336
+ user,
337
+ volumes,
338
+ environment_variables,
339
+ shared_memory_size,
340
+ ipc_mode,
341
+ ulimits,
342
+ devices,
343
+ group_adds,
344
+ )
345
+ else:
346
+ _start_container(
347
+ name,
348
+ image_name,
349
+ app_info,
350
+ quiet,
351
+ commands,
352
+ network,
353
+ user,
354
+ volumes,
355
+ environment_variables,
356
+ shared_memory_size,
357
+ ipc_mode,
358
+ ulimits,
359
+ devices,
360
+ group_adds,
361
+ )
362
+
363
+
364
+ def _start_container(
365
+ name,
366
+ image_name,
367
+ app_info,
368
+ quiet,
369
+ commands,
370
+ network,
371
+ user,
372
+ volumes,
373
+ environment_variables,
374
+ shared_memory_size,
375
+ ipc_mode,
376
+ ulimits,
377
+ devices,
378
+ group_adds,
379
+ ):
380
+ container = docker.container.create(
381
+ image_name,
382
+ command=commands,
383
+ envs=environment_variables,
384
+ hostname=name,
385
+ name=name,
386
+ networks=[network],
387
+ remove=True,
388
+ shm_size=shared_memory_size,
389
+ user=user,
390
+ volumes=volumes,
391
+ workdir=app_info["workingDirectory"],
392
+ ipc=ipc_mode,
393
+ cap_add=["CAP_SYS_PTRACE"],
394
+ ulimit=ulimits,
395
+ devices=devices,
396
+ groups_add=group_adds,
397
+ runtime="nvidia",
398
+ )
399
+ container_name = container.name
400
+ container_id = container.id[:12]
401
+
402
+ ulimit_str = ", ".join(
403
+ f"{ulimit.name}={ulimit.soft}:{ulimit.hard}" for ulimit in container.host_config.ulimits
404
+ )
405
+ logger.info(
406
+ f"Launching container ({container_id}) using image '{image_name}'..."
407
+ f"\n container name: {container_name}"
408
+ f"\n host name: {container.config.hostname}"
409
+ f"\n network: {network}"
410
+ f"\n user: {container.config.user}"
411
+ f"\n ulimits: {ulimit_str}"
412
+ f"\n cap_add: {', '.join(container.host_config.cap_add)}"
413
+ f"\n ipc mode: {container.host_config.ipc_mode}"
414
+ f"\n shared memory size: {container.host_config.shm_size}"
415
+ f"\n devices: {', '.join(devices)}"
416
+ f"\n group_add: {', '.join(group_adds)}"
417
+ )
418
+ logs = container.start(
419
+ attach=True,
420
+ stream=True,
421
+ )
422
+
423
+ for log in logs:
424
+ if log[0] == "stdout":
425
+ if not quiet:
426
+ print(log[1].decode("utf-8"))
427
+ elif log[0] == "stderr":
428
+ try:
429
+ print(str(log[1].decode("utf-8")))
430
+ except Exception:
431
+ print(str(log[1]))
432
+
433
+ logger.info(f"Container '{container_name}'({container_id}) exited.")
434
+
435
+
436
+ def _enter_terminal(
437
+ name,
438
+ image_name,
439
+ app_info,
440
+ network,
441
+ user,
442
+ volumes,
443
+ environment_variables,
444
+ shared_memory_size,
445
+ ipc_mode,
446
+ ulimits,
447
+ devices,
448
+ group_adds,
449
+ ):
450
+ print("\n\nEntering terminal...")
451
+ print(
452
+ "\n".join(
453
+ f"\t{k:25s}\t{v}"
454
+ for k, v in sorted(environment_variables.items(), key=lambda t: str(t[0]))
455
+ )
456
+ )
457
+ print("\n\n")
458
+ docker.container.run(
459
+ image_name,
460
+ detach=False,
461
+ entrypoint="/bin/bash",
462
+ envs=environment_variables,
463
+ hostname=name,
464
+ interactive=True,
465
+ name=name,
466
+ networks=[network],
467
+ remove=True,
468
+ shm_size=shared_memory_size,
469
+ tty=True,
470
+ user=user,
471
+ volumes=volumes,
472
+ workdir=app_info["workingDirectory"],
473
+ ipc=ipc_mode,
474
+ cap_add=["CAP_SYS_PTRACE"],
475
+ ulimit=ulimits,
476
+ devices=devices,
477
+ groups_add=group_adds,
478
+ runtime="nvidia",
479
+ )
480
+ logger.info("Container exited.")
481
+
482
+
483
+ def _additional_devices_to_mount(is_root: bool):
484
+ """Mounts additional devices"""
485
+ devices = []
486
+ group_adds = []
487
+
488
+ # On iGPU, the /dev/dri/* devices (mounted by the NV container runtime) permissions require root
489
+ # privilege or to be part of the `video` and `render` groups. The ID for these group names might
490
+ # differ on the host system and in the container, so we need to pass the group ID instead of the
491
+ # group name when running docker.
492
+ if (
493
+ os.path.exists("/sys/devices/platform/gpu.0/load")
494
+ and os.path.exists("/usr/bin/tegrastats")
495
+ and not is_root
496
+ ):
497
+ group = run_cmd_output('/usr/bin/cat /etc/group | grep "video" | cut -d: -f3').strip()
498
+ group_adds.append(group)
499
+ group = run_cmd_output('/usr/bin/cat /etc/group | grep "render" | cut -d: -f3').strip()
500
+ group_adds.append(group)
501
+ return (devices, group_adds)
502
+
503
+
504
+ def _host_is_native_igpu() -> bool:
505
+ proc = subprocess.run(
506
+ ["nvidia-smi --query-gpu name --format=csv,noheader | grep nvgpu -q"], shell=True
507
+ )
508
+ result = proc.returncode
509
+ return result == 0
@@ -0,0 +1,52 @@
1
+ """
2
+ SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ SPDX-License-Identifier: Apache-2.0
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ """ # noqa: E501
17
+
18
+ from enum import Enum
19
+
20
+
21
+ class ApplicationType(Enum):
22
+ PythonModule = "Python Module"
23
+ PythonFile = "Python File"
24
+ CppCMake = "C++"
25
+ Binary = "Binary"
26
+
27
+
28
+ class SdkType(Enum):
29
+ """
30
+ Note the values assigned are used as entry_points in setup.py for detecting the SDK to use.
31
+ """
32
+
33
+ Holoscan = "holoscan"
34
+ MonaiDeploy = "monai-deploy"
35
+
36
+
37
+ class Arch(Enum):
38
+ amd64 = "linux/amd64"
39
+ arm64 = "linux/arm64"
40
+
41
+
42
+ class Platform(Enum):
43
+ IGXOrinDevIt = "igx-orin-devkit"
44
+ JetsonAgxOrinDevKit = "jetson-agx-orin-devkit"
45
+ X64Workstation = "x64-workstation"
46
+ SBSA = "sbsa"
47
+
48
+
49
+ class PlatformConfiguration(Enum):
50
+ iGPU = "igpu" # noqa: N815
51
+ dGPU = "dgpu" # noqa: N815
52
+ CPU = "cpu"