holoscan-cli 2.9.0__py3-none-any.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.
- holoscan_cli/__init__.py +35 -0
- holoscan_cli/__main__.py +164 -0
- holoscan_cli/common/argparse_types.py +156 -0
- holoscan_cli/common/artifact_sources.py +160 -0
- holoscan_cli/common/constants.py +119 -0
- holoscan_cli/common/dockerutils.py +521 -0
- holoscan_cli/common/enum_types.py +49 -0
- holoscan_cli/common/exceptions.py +126 -0
- holoscan_cli/common/sdk_utils.py +195 -0
- holoscan_cli/common/utils.py +137 -0
- holoscan_cli/logging.json +37 -0
- holoscan_cli/nics/__init__.py +15 -0
- holoscan_cli/nics/nics.py +33 -0
- holoscan_cli/package-source.json +32 -0
- holoscan_cli/packager/__init__.py +15 -0
- holoscan_cli/packager/arguments.py +148 -0
- holoscan_cli/packager/config_reader.py +180 -0
- holoscan_cli/packager/container_builder.py +426 -0
- holoscan_cli/packager/manifest_files.py +217 -0
- holoscan_cli/packager/models.py +90 -0
- holoscan_cli/packager/package_command.py +197 -0
- holoscan_cli/packager/packager.py +124 -0
- holoscan_cli/packager/parameters.py +603 -0
- holoscan_cli/packager/platforms.py +426 -0
- holoscan_cli/packager/templates/Dockerfile.jinja2 +479 -0
- holoscan_cli/packager/templates/dockerignore +92 -0
- holoscan_cli/packager/templates/tools.sh +414 -0
- holoscan_cli/py.typed +14 -0
- holoscan_cli/runner/__init__.py +15 -0
- holoscan_cli/runner/resources.py +185 -0
- holoscan_cli/runner/run_command.py +207 -0
- holoscan_cli/runner/runner.py +340 -0
- holoscan_cli/version/__init__.py +15 -0
- holoscan_cli/version/version.py +53 -0
- holoscan_cli-2.9.0.dist-info/LICENSE +201 -0
- holoscan_cli-2.9.0.dist-info/METADATA +102 -0
- holoscan_cli-2.9.0.dist-info/RECORD +39 -0
- holoscan_cli-2.9.0.dist-info/WHEEL +4 -0
- holoscan_cli-2.9.0.dist-info/entry_points.txt +4 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import importlib.metadata
|
|
16
|
+
import logging
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Optional
|
|
20
|
+
|
|
21
|
+
from packaging.version import Version
|
|
22
|
+
|
|
23
|
+
from .artifact_sources import ArtifactSources
|
|
24
|
+
from .enum_types import SdkType
|
|
25
|
+
from .exceptions import FailedToDetectSDKVersionError, InvalidSdkError
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger("common")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def validate_holoscan_sdk_version(
|
|
31
|
+
artifact_sources: ArtifactSources, version: str
|
|
32
|
+
) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Validates specified Holoscan version with supported versions.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
artifact_sources (ArtifactSources): ArtifactSources object to retrieve supported versions from
|
|
38
|
+
version (str): Holoscan SDK version from user input.
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
InvalidSdkError: If specified SDK version is not supported.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
str: SDK version
|
|
45
|
+
"""
|
|
46
|
+
sdk_version = Version(version)
|
|
47
|
+
if sdk_version.base_version not in artifact_sources.holoscan_versions:
|
|
48
|
+
raise InvalidSdkError(
|
|
49
|
+
f"Invalid SDK version specified ({version}): valid values are: "
|
|
50
|
+
f"{', '.join(artifact_sources.holoscan_versions)}"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def detect_sdk(sdk: Optional[SdkType] = None) -> SdkType:
|
|
55
|
+
"""
|
|
56
|
+
Use user specified SDK or detects the SDK to use based on the executing command name.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
sdk (Optional[SdkType]): User specified SDK.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
SDK (SdkType): SDK for building the application
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
InvalidSdkError: when failed to detect SDK version.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
if sdk is not None:
|
|
69
|
+
if not isinstance(sdk, SdkType):
|
|
70
|
+
raise ValueError("sdk must be of type SdkType")
|
|
71
|
+
return sdk
|
|
72
|
+
|
|
73
|
+
command = None
|
|
74
|
+
try:
|
|
75
|
+
# For Python 3.10+, this check is to support use of the holoscan cli bash script bundled
|
|
76
|
+
# with the Debian package.
|
|
77
|
+
# Since the Debian package bundles with 3.10, we don't need to handle 3.9 but
|
|
78
|
+
# we still need to check if `orig_argv` is supported to avoid breaking unit test.
|
|
79
|
+
if (
|
|
80
|
+
getattr(sys, "orig_argv", None)
|
|
81
|
+
and len(sys.orig_argv) >= 3
|
|
82
|
+
and sys.orig_argv[0] == "python3"
|
|
83
|
+
and sys.orig_argv[2] == "holoscan_cli"
|
|
84
|
+
):
|
|
85
|
+
command = "holoscan"
|
|
86
|
+
else:
|
|
87
|
+
command = Path(sys.argv[0]).name.lower()
|
|
88
|
+
return SdkType(command)
|
|
89
|
+
except Exception as ex:
|
|
90
|
+
raise InvalidSdkError(f"Invalid SDK value provided: {command}") from ex
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def detect_sdk_version(
|
|
94
|
+
sdk: SdkType,
|
|
95
|
+
sdk_version: Optional[Version] = None,
|
|
96
|
+
) -> tuple[str, Optional[str]]:
|
|
97
|
+
"""
|
|
98
|
+
Detects SDK version to use based on installed PyPI package or user input.
|
|
99
|
+
For Holoscan SDK(Type), detect only the Holoscan version with optional user-provided version.
|
|
100
|
+
For MONAI Deploy SDK(Type), detect both Holoscan and MONAI Deploy App SDK versions but assume
|
|
101
|
+
the sdk_version provided by the user is for MONAI Deploy App SDK.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
sdk (SdkType): SDK Type.
|
|
105
|
+
sdk_version (Optional[str]): SDK version to be used for building the package.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Tuple[str, Optional[str]]: Version of the Holoscan SDK and version of MONAI Deploy SDK to
|
|
109
|
+
use
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
FailedToDetectSDKVersionError: When unable to detect the installed Holoscan PyPI package.
|
|
113
|
+
"""
|
|
114
|
+
if sdk is SdkType.Holoscan:
|
|
115
|
+
return [detect_holoscan_version(sdk_version), None]
|
|
116
|
+
else:
|
|
117
|
+
return [
|
|
118
|
+
detect_holoscan_version(None),
|
|
119
|
+
detect_monaideploy_version(sdk_version),
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def detect_holoscan_version(sdk_version: Optional[Version] = None) -> str:
|
|
124
|
+
"""
|
|
125
|
+
Validates Holoscan version if specified. Otherwise, attempt to detect the Holoscan PyPI
|
|
126
|
+
package installed.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
sdk_version (Optional[str], optional): SDK version from user input. Defaults to None.
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
FailedToDetectSDKVersionError: When unable to detect the installed Holoscan PyPI package.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
str: SDK version
|
|
136
|
+
"""
|
|
137
|
+
if sdk_version is not None:
|
|
138
|
+
return sdk_version.base_version
|
|
139
|
+
else:
|
|
140
|
+
try:
|
|
141
|
+
ver_str = importlib.metadata.version("holoscan-cli").title()
|
|
142
|
+
ver = Version(ver_str)
|
|
143
|
+
ver_str = ".".join(str(i) for i in ver.release)
|
|
144
|
+
|
|
145
|
+
if len(ver.release) == 1 and ver.major == ver.release[0]:
|
|
146
|
+
ver_str = ver_str + ".0.0"
|
|
147
|
+
elif (
|
|
148
|
+
len(ver.release) == 2
|
|
149
|
+
and ver.major == ver.release[0]
|
|
150
|
+
and ver.minor == ver.release[1]
|
|
151
|
+
):
|
|
152
|
+
ver_str = ver_str + ".0"
|
|
153
|
+
elif (
|
|
154
|
+
len(ver.release) == 4
|
|
155
|
+
and ver.major == ver.release[0]
|
|
156
|
+
and ver.minor == ver.release[1]
|
|
157
|
+
and ver.micro == ver.release[2]
|
|
158
|
+
):
|
|
159
|
+
ver_str = f"{ver.release[0]}.{ver.release[1]}.{ver.release[2]}"
|
|
160
|
+
|
|
161
|
+
return ver_str
|
|
162
|
+
except Exception as ex:
|
|
163
|
+
raise FailedToDetectSDKVersionError(
|
|
164
|
+
"Failed to detect installed Holoscan PyPI version.", ex
|
|
165
|
+
) from ex
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def detect_monaideploy_version(sdk_version: Optional[Version] = None) -> str:
|
|
169
|
+
"""
|
|
170
|
+
Validates MONAI Deploy version if specified. Otherwise, attempt to detect the MONAI Deploy
|
|
171
|
+
PyPI package installed.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
sdk_version (Optional[str], optional): SDK version from user input. Defaults to None.
|
|
175
|
+
|
|
176
|
+
Raises:
|
|
177
|
+
FailedToDetectSDKVersionError: When unable to detect the installed MONAI Deploy PyPI
|
|
178
|
+
package.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
str: SDK version
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
if sdk_version is not None:
|
|
185
|
+
return sdk_version.base_version
|
|
186
|
+
else:
|
|
187
|
+
try:
|
|
188
|
+
ver_str = importlib.metadata.version("monai-deploy-app-sdk").title()
|
|
189
|
+
ver = Version(ver_str)
|
|
190
|
+
|
|
191
|
+
return ver.base_version
|
|
192
|
+
except Exception as ex:
|
|
193
|
+
raise FailedToDetectSDKVersionError(
|
|
194
|
+
"Failed to detect installed MONAI Deploy App SDK PyPI version.", ex
|
|
195
|
+
) from ex
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import json
|
|
16
|
+
import logging
|
|
17
|
+
import re
|
|
18
|
+
import socket
|
|
19
|
+
import subprocess
|
|
20
|
+
from typing import List, Optional
|
|
21
|
+
|
|
22
|
+
import psutil
|
|
23
|
+
from packaging import version
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger("common")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def print_manifest_json(manifest, filename):
|
|
29
|
+
logger.debug(
|
|
30
|
+
f"""
|
|
31
|
+
=============== Begin {filename} ===============
|
|
32
|
+
{json.dumps(manifest, indent=4)}
|
|
33
|
+
================ End {filename} ================
|
|
34
|
+
"""
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_requested_gpus(pkg_info: dict) -> int:
|
|
39
|
+
"""Gets requested number of gpus in the package manifest
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
pkg_info: package manifest as a python dict
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
int: requested number of gpus in the package manifest
|
|
46
|
+
"""
|
|
47
|
+
num_gpu: int = pkg_info.get("resources", {}).get("gpu", 0)
|
|
48
|
+
return num_gpu
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_gpu_count():
|
|
52
|
+
return len(run_cmd_output(["nvidia-smi", "-L"]).splitlines())
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def run_cmd(cmd: str) -> int:
|
|
56
|
+
"""
|
|
57
|
+
Executes command and return the returncode of the executed command.
|
|
58
|
+
|
|
59
|
+
Redirects stderr of the executed command to stdout.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
cmd: command to execute.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
output: child process returncode after the command has been executed.
|
|
66
|
+
"""
|
|
67
|
+
proc = subprocess.Popen(cmd, universal_newlines=True, shell=False)
|
|
68
|
+
return proc.wait()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def run_cmd_output(cmd: List[str], grep: Optional[str] = None) -> str:
|
|
72
|
+
"""
|
|
73
|
+
Executes command and returns the output.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
cmd: command to execute.
|
|
77
|
+
grep: string to search for matching line. The first match is returned.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
output: command output.
|
|
81
|
+
"""
|
|
82
|
+
proc = subprocess.run(cmd, capture_output=True, text=True, shell=False)
|
|
83
|
+
|
|
84
|
+
if grep:
|
|
85
|
+
lines = proc.stdout.splitlines()
|
|
86
|
+
for line in lines:
|
|
87
|
+
if re.search(grep, line):
|
|
88
|
+
return line
|
|
89
|
+
|
|
90
|
+
return proc.stdout
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def compare_versions(version1, version2):
|
|
94
|
+
"""
|
|
95
|
+
Compares two version strings.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
version1(str)
|
|
99
|
+
version2(str)
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
1: when version1 is greater than version2
|
|
103
|
+
-1: when version1 is less than version2
|
|
104
|
+
0: when two version strings are equal
|
|
105
|
+
"""
|
|
106
|
+
v1 = version.parse(version1)
|
|
107
|
+
v2 = version.parse(version2)
|
|
108
|
+
|
|
109
|
+
if v1 < v2:
|
|
110
|
+
return -1
|
|
111
|
+
elif v1 > v2:
|
|
112
|
+
return 1
|
|
113
|
+
else:
|
|
114
|
+
return 0
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def get_host_ip_addresses() -> tuple[list[tuple[str, str]], list[tuple[str, str]]]:
|
|
118
|
+
"""
|
|
119
|
+
Returns a tuple containing interface name and its IPv4 address as the first item
|
|
120
|
+
and another item with interface name and its IPv6 address.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
(Tuple[List[Tuple[str, str]], List[Tuple[str, str]]]): where the item contains a list of
|
|
124
|
+
tuples of network interface names and its IPv4 address. The second item is similar but
|
|
125
|
+
contains IPv6 addresses.
|
|
126
|
+
"""
|
|
127
|
+
ipv4 = []
|
|
128
|
+
ipv6 = []
|
|
129
|
+
|
|
130
|
+
for interface, snics in psutil.net_if_addrs().items():
|
|
131
|
+
for snic in snics:
|
|
132
|
+
if snic.family == socket.AF_INET:
|
|
133
|
+
ipv4.append((interface, snic.address))
|
|
134
|
+
elif snic.family == socket.AF_INET6:
|
|
135
|
+
ipv6.append((interface, snic.address))
|
|
136
|
+
|
|
137
|
+
return (ipv4, ipv6)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"disable_existing_loggers": false,
|
|
4
|
+
"formatters": {
|
|
5
|
+
"single": {
|
|
6
|
+
"format": "%(message)s"
|
|
7
|
+
},
|
|
8
|
+
"simple": {
|
|
9
|
+
"format": "[%(asctime)s] [%(levelname)s] (%(name)s) - %(message)s"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"handlers": {
|
|
13
|
+
"console": {
|
|
14
|
+
"class": "logging.StreamHandler",
|
|
15
|
+
"formatter": "simple"
|
|
16
|
+
},
|
|
17
|
+
"runner_console": {
|
|
18
|
+
"class": "logging.StreamHandler",
|
|
19
|
+
"formatter": "single"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"root": {
|
|
23
|
+
"level": "INFO",
|
|
24
|
+
"propagate": false,
|
|
25
|
+
"handlers": [
|
|
26
|
+
"console"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"loggers": {
|
|
30
|
+
"app_runner": {
|
|
31
|
+
"propagate": false,
|
|
32
|
+
"handlers": [
|
|
33
|
+
"runner_console"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
from .nics import execute_nics_command # noqa: F401
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import logging
|
|
16
|
+
import sys
|
|
17
|
+
from argparse import Namespace
|
|
18
|
+
|
|
19
|
+
from ..common.utils import get_host_ip_addresses
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger("nics")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def execute_nics_command(args: Namespace):
|
|
25
|
+
try:
|
|
26
|
+
ipv4, ipv6 = get_host_ip_addresses()
|
|
27
|
+
ip_addresses = ipv4 if ipv4 else ipv6
|
|
28
|
+
strs = [f"\n\t{item[0]:<15} : {item[1]}" for item in ip_addresses]
|
|
29
|
+
print(f"Available network interface cards/IP addresses: \n{''.join(strs)}")
|
|
30
|
+
except Exception as ex:
|
|
31
|
+
logging.error("Error executing nics command.")
|
|
32
|
+
logger.debug(ex)
|
|
33
|
+
sys.exit(4)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"2.6.0": {
|
|
3
|
+
"holoscan": {
|
|
4
|
+
"debian-version": "2.6.0.1-1",
|
|
5
|
+
"wheel-version": "2.6.0",
|
|
6
|
+
"base-images": {
|
|
7
|
+
"dgpu": "nvcr.io/nvidia/cuda:12.6.0-runtime-ubuntu22.04",
|
|
8
|
+
"igpu": "nvcr.io/nvidia/tensorrt:24.08-py3-igpu"
|
|
9
|
+
},
|
|
10
|
+
"build-images": {
|
|
11
|
+
"igpu": {
|
|
12
|
+
"jetson-agx-orin-devkit": "nvcr.io/nvidia/clara-holoscan/holoscan:v2.3.0-igpu",
|
|
13
|
+
"igx-orin-devkit": "nvcr.io/nvidia/clara-holoscan/holoscan:v2.3.0-igpu",
|
|
14
|
+
"sbsa": "nvcr.io/nvidia/clara-holoscan/holoscan:v2.3.0-igpu"
|
|
15
|
+
},
|
|
16
|
+
"dgpu": {
|
|
17
|
+
"x64-workstation": "nvcr.io/nvidia/clara-holoscan/holoscan:v2.3.0-dgpu",
|
|
18
|
+
"igx-orin-devkit": "nvcr.io/nvidia/clara-holoscan/holoscan:v2.3.0-dgpu",
|
|
19
|
+
"sbsa": "nvcr.io/nvidia/clara-holoscan/holoscan:v2.3.0-dgpu",
|
|
20
|
+
"clara-agx-devkit": "nvcr.io/nvidia/clara-holoscan/holoscan:v2.3.0-dgpu"
|
|
21
|
+
},
|
|
22
|
+
"cpu": {
|
|
23
|
+
"x64-workstation": "nvcr.io/nvidia/clara-holoscan/holoscan:v2.3.0-dgpu"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"health-probes": {
|
|
28
|
+
"linux/amd64": "https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.4.19/grpc_health_probe-linux-amd64",
|
|
29
|
+
"linux/arm64": "https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.4.19/grpc_health_probe-linux-arm64"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
from .packager import execute_package_command # noqa: F401
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import logging
|
|
16
|
+
from argparse import Namespace
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from ..common.artifact_sources import ArtifactSources
|
|
20
|
+
from ..common.constants import DefaultValues
|
|
21
|
+
from ..common.enum_types import SdkType
|
|
22
|
+
from .config_reader import ApplicationConfiguration
|
|
23
|
+
from .manifest_files import ApplicationManifest, PackageManifest
|
|
24
|
+
from .models import Models
|
|
25
|
+
from .parameters import PackageBuildParameters, PlatformParameters
|
|
26
|
+
from .platforms import Platform
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PackagingArguments:
|
|
30
|
+
"""Processes input arguments for packager"""
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def platforms(self) -> list[PlatformParameters]:
|
|
34
|
+
return self._platforms
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def build_parameters(self) -> PackageBuildParameters:
|
|
38
|
+
return self._build_parameters
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def application_manifest(self) -> ApplicationManifest:
|
|
42
|
+
return self._application_manifest
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def package_manifest(self) -> PackageManifest:
|
|
46
|
+
return self._package_manifest
|
|
47
|
+
|
|
48
|
+
def __init__(self, args: Namespace, temp_dir: str) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Args:
|
|
51
|
+
args (Namespace): Input arguments for Packager from CLI
|
|
52
|
+
"""
|
|
53
|
+
self._logger = logging.getLogger("packager")
|
|
54
|
+
|
|
55
|
+
self._platforms: list[PlatformParameters]
|
|
56
|
+
self._build_parameters = PackageBuildParameters()
|
|
57
|
+
self._artifact_sources = ArtifactSources()
|
|
58
|
+
|
|
59
|
+
if args.source is not None:
|
|
60
|
+
self._artifact_sources.load(args.source)
|
|
61
|
+
else:
|
|
62
|
+
self._artifact_sources.download_manifest()
|
|
63
|
+
|
|
64
|
+
self.build_parameters.username = args.username
|
|
65
|
+
self.build_parameters.uid = args.uid
|
|
66
|
+
self.build_parameters.gid = args.gid
|
|
67
|
+
self.build_parameters.build_cache = args.build_cache
|
|
68
|
+
self.build_parameters.app_config_file_path = args.config
|
|
69
|
+
self.build_parameters.timeout = (
|
|
70
|
+
args.timeout if args.timeout else DefaultValues.TIMEOUT
|
|
71
|
+
)
|
|
72
|
+
self.build_parameters.docs = args.docs if args.docs else None
|
|
73
|
+
self.build_parameters.application = args.application
|
|
74
|
+
self.build_parameters.no_cache = args.no_cache
|
|
75
|
+
self.build_parameters.tarball_output = args.output
|
|
76
|
+
self.build_parameters.cmake_args = args.cmake_args
|
|
77
|
+
self.build_parameters.includes = args.includes
|
|
78
|
+
self.build_parameters.additional_libs = args.additional_libs
|
|
79
|
+
|
|
80
|
+
models = Models()
|
|
81
|
+
platform = Platform(self._artifact_sources)
|
|
82
|
+
if args.models is not None:
|
|
83
|
+
self.build_parameters.models = models.build(args.models)
|
|
84
|
+
|
|
85
|
+
self._read_application_config_file(args.config)
|
|
86
|
+
self.build_parameters.version = (
|
|
87
|
+
args.version if args.version else self.application_manifest.version
|
|
88
|
+
)
|
|
89
|
+
(
|
|
90
|
+
self.build_parameters.sdk,
|
|
91
|
+
self.build_parameters.holoscan_sdk_version,
|
|
92
|
+
self.build_parameters.monai_deploy_app_sdk_version,
|
|
93
|
+
self._platforms,
|
|
94
|
+
) = platform.configure_platforms(
|
|
95
|
+
args,
|
|
96
|
+
temp_dir,
|
|
97
|
+
self.build_parameters.version,
|
|
98
|
+
self.build_parameters.application_type,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if self.build_parameters.sdk == SdkType.Holoscan:
|
|
102
|
+
self.application_manifest.readiness = {
|
|
103
|
+
"type": "command",
|
|
104
|
+
"command": ["/bin/grpc_health_probe", "-addr", ":8765"],
|
|
105
|
+
"initialDelaySeconds": 1,
|
|
106
|
+
"periodSeconds": 10,
|
|
107
|
+
"timeoutSeconds": 1,
|
|
108
|
+
"failureThreshold": 3,
|
|
109
|
+
}
|
|
110
|
+
self.application_manifest.liveness = {
|
|
111
|
+
"type": "command",
|
|
112
|
+
"command": ["/bin/grpc_health_probe", "-addr", ":8765"],
|
|
113
|
+
"initialDelaySeconds": 1,
|
|
114
|
+
"periodSeconds": 10,
|
|
115
|
+
"timeoutSeconds": 1,
|
|
116
|
+
"failureThreshold": 3,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
self.application_manifest.sdk = self.build_parameters.sdk.value
|
|
120
|
+
|
|
121
|
+
if self.build_parameters.sdk == SdkType.Holoscan:
|
|
122
|
+
self.application_manifest.sdk_version = (
|
|
123
|
+
self.build_parameters.holoscan_sdk_version
|
|
124
|
+
)
|
|
125
|
+
else:
|
|
126
|
+
self.application_manifest.sdk_version = (
|
|
127
|
+
self.build_parameters.monai_deploy_app_sdk_version
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
self._package_manifest.platform_config = args.platform_config.value
|
|
131
|
+
|
|
132
|
+
def _read_application_config_file(self, config_file_path: Path):
|
|
133
|
+
self._logger.info(
|
|
134
|
+
f"Reading application configuration from {config_file_path}..."
|
|
135
|
+
)
|
|
136
|
+
app_config = ApplicationConfiguration()
|
|
137
|
+
app_config.read(config_file_path)
|
|
138
|
+
self.build_parameters.title = app_config.title()
|
|
139
|
+
self.build_parameters.pip_packages = app_config.pip_packages()
|
|
140
|
+
|
|
141
|
+
self._logger.info("Generating app.json...")
|
|
142
|
+
self._application_manifest = app_config.populate_app_manifest(
|
|
143
|
+
self.build_parameters
|
|
144
|
+
)
|
|
145
|
+
self._logger.info("Generating pkg.json...")
|
|
146
|
+
self._package_manifest = app_config.populate_package_manifest(
|
|
147
|
+
self.build_parameters
|
|
148
|
+
)
|