mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2025-06-26 18:18:24 +00:00
Compare commits
168 Commits
v1.13.0
...
v1.14.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a25b1c1048 | ||
|
|
99859e461d | ||
|
|
d52dbeaa7a | ||
|
|
c11c7695cb | ||
|
|
c4d3b13ae2 | ||
|
|
bcf3a70174 | ||
|
|
743d290577 | ||
|
|
82347eb9bc | ||
|
|
84c7bf8b18 | ||
|
|
d92300506c | ||
|
|
2da32970b9 | ||
|
|
1d0a733487 | ||
|
|
9464953924 | ||
|
|
c9b05d8fed | ||
|
|
a02bc27c3e | ||
|
|
6a04e97bca | ||
|
|
0780621024 | ||
|
|
2bc0f45a52 | ||
|
|
178eb5c5a8 | ||
|
|
761fc29567 | ||
|
|
9f5c82420a | ||
|
|
23041be511 | ||
|
|
dcbf4b4f2a | ||
|
|
652345bc4d | ||
|
|
69a1a9ef7a | ||
|
|
2464181d2b | ||
|
|
c3c1d19a5c | ||
|
|
75f288a6e4 | ||
|
|
94259baea1 | ||
|
|
9e8ff003b6 | ||
|
|
3dee9d9a4c | ||
|
|
3f03a71afd | ||
|
|
093e93cfbf | ||
|
|
78f619b1e7 | ||
|
|
43c44a0f48 | ||
|
|
6b1e8171c8 | ||
|
|
2e50b3da7c | ||
|
|
eca13e72bf | ||
|
|
b64ba6ac2d | ||
|
|
7b801a0ce0 | ||
|
|
528cbbb636 | ||
|
|
fd48233c13 | ||
|
|
b72764af5a | ||
|
|
7e7c45fb0f | ||
|
|
61f515b3dd | ||
|
|
e05686cbe8 | ||
|
|
1fc8ae32bd | ||
|
|
e80d43f4c4 | ||
|
|
a6b0f45d2c | ||
|
|
39263ea365 | ||
|
|
9ea214d0b3 | ||
|
|
5371ff039b | ||
|
|
315f4adb8f | ||
|
|
05632c0a40 | ||
|
|
8df4a98d7b | ||
|
|
02656b624d | ||
|
|
61af2aee8e | ||
|
|
ddebd69128 | ||
|
|
ac11727ec5 | ||
|
|
5748d220ba | ||
|
|
3b86683843 | ||
|
|
3bd5baa3c5 | ||
|
|
330aa16687 | ||
|
|
8a4d6b5bcf | ||
|
|
40d0a88cf9 | ||
|
|
dc6a895db8 | ||
|
|
3b1b89e6c0 | ||
|
|
013a1b413b | ||
|
|
3be16d8077 | ||
|
|
927ec78b6e | ||
|
|
8ca606f7ac | ||
|
|
e7d2a9c212 | ||
|
|
fcb4e379e3 | ||
|
|
cda96f2f9e | ||
|
|
e11f65e51e | ||
|
|
3ea02d13fc | ||
|
|
e30fd0f4ad | ||
|
|
418e4014e6 | ||
|
|
e78a4f5eac | ||
|
|
540dbcbc03 | ||
|
|
a8265f8846 | ||
|
|
c120c511d5 | ||
|
|
424b8c9d46 | ||
|
|
5bc72b70b8 | ||
|
|
fe37196788 | ||
|
|
ba44c50f4e | ||
|
|
729ca941be | ||
|
|
0ee947dba6 | ||
|
|
d1fd0a7384 | ||
|
|
ae2c582138 | ||
|
|
b7e5cef934 | ||
|
|
9378d0cd0f | ||
|
|
f9df36c473 | ||
|
|
8bb0235c92 | ||
|
|
fc310e429e | ||
|
|
8d0ffb2fa5 | ||
|
|
9f07cc9ab2 | ||
|
|
1fff80e10d | ||
|
|
0a57cdc6e8 | ||
|
|
1a86b20f7c | ||
|
|
0068750a5c | ||
|
|
ee47f26d1c | ||
|
|
3945abb2f2 | ||
|
|
9de4f7f4b9 | ||
|
|
3610b5073b | ||
|
|
1991138185 | ||
|
|
8ebc21cd1f | ||
|
|
1c1ce2c6f7 | ||
|
|
39b0830a66 | ||
|
|
6b367445a3 | ||
|
|
37c66fc33c | ||
|
|
1bd5798a99 | ||
|
|
90c4c4811a | ||
|
|
49de170652 | ||
|
|
07c89fa975 | ||
|
|
7a1f23e2e4 | ||
|
|
25165b0771 | ||
|
|
3e7acec0b4 | ||
|
|
4165961d31 | ||
|
|
2e3a12438a | ||
|
|
731c99b52c | ||
|
|
470b4eebd8 | ||
|
|
6750df8e01 | ||
|
|
8736d1e78f | ||
|
|
140b1e33ef | ||
|
|
3056428eda | ||
|
|
367a30827f | ||
|
|
fe8ef9e0bd | ||
|
|
d77f46aa09 | ||
|
|
043e283db3 | ||
|
|
2019f1e7ea | ||
|
|
22c7178561 | ||
|
|
525aeb102f | ||
|
|
9fb5ac36ed | ||
|
|
c30764b7cc | ||
|
|
8a2de90c28 | ||
|
|
243c439bb8 | ||
|
|
060ac46bd8 | ||
|
|
ae2a683929 | ||
|
|
2b5eeb8d24 | ||
|
|
bbb94be213 | ||
|
|
e1c75aec6c | ||
|
|
3030d281d9 | ||
|
|
81d8b94cdc | ||
|
|
276e1960b1 | ||
|
|
70920d7a04 | ||
|
|
f1e201d368 | ||
|
|
ef863f5fd4 | ||
|
|
ce65df7d17 | ||
|
|
fa9c6116a4 | ||
|
|
28b70663f1 | ||
|
|
c0fe8f27eb | ||
|
|
926ac77bc0 | ||
|
|
fc7c8f7520 | ||
|
|
46c1c45d85 | ||
|
|
f99e863649 | ||
|
|
dcc21ece97 | ||
|
|
a53e3604a6 | ||
|
|
cfea6c1179 | ||
|
|
4d1daa0b6c | ||
|
|
df925bc7fd | ||
|
|
df22e37dfd | ||
|
|
2136266d1d | ||
|
|
a95232dd33 | ||
|
|
29c6288128 | ||
|
|
cd6fcb5297 | ||
|
|
36989deff7 | ||
|
|
7f6c9851fe |
@@ -74,60 +74,29 @@ trigger-pipeline:
|
||||
- when: always
|
||||
|
||||
# Define the distribution targets
|
||||
.dist-amazonlinux2:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: amazonlinux2
|
||||
PACKAGE_REPO_TYPE: rpm
|
||||
|
||||
.dist-centos7:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: centos7
|
||||
CVE_UPDATES: "cyrus-sasl-lib"
|
||||
PACKAGE_REPO_TYPE: rpm
|
||||
|
||||
.dist-centos8:
|
||||
variables:
|
||||
DIST: centos8
|
||||
CVE_UPDATES: "cyrus-sasl-lib"
|
||||
PACKAGE_REPO_TYPE: rpm
|
||||
|
||||
.dist-debian10:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: debian10
|
||||
PACKAGE_REPO_TYPE: debian
|
||||
|
||||
.dist-opensuse-leap15.1:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: opensuse-leap15.1
|
||||
PACKAGE_REPO_TYPE: rpm
|
||||
|
||||
.dist-ubi8:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: ubi8
|
||||
CVE_UPDATES: "cyrus-sasl-lib"
|
||||
PACKAGE_REPO_TYPE: rpm
|
||||
|
||||
.dist-ubuntu18.04:
|
||||
variables:
|
||||
DIST: ubuntu18.04
|
||||
CVE_UPDATES: "libsasl2-2 libsasl2-modules-db"
|
||||
PACKAGE_REPO_TYPE: debian
|
||||
|
||||
.dist-ubuntu20.04:
|
||||
variables:
|
||||
DIST: ubuntu20.04
|
||||
CVE_UPDATES: "libsasl2-2 libsasl2-modules-db"
|
||||
PACKAGE_REPO_TYPE: debian
|
||||
|
||||
.dist-packaging:
|
||||
variables:
|
||||
@@ -245,6 +214,8 @@ test-packaging:
|
||||
.release:external:
|
||||
extends:
|
||||
- .release
|
||||
variables:
|
||||
FORCE_PUBLISH_IMAGES: "yes"
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG
|
||||
variables:
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
if: |
|
||||
contains( '\
|
||||
anstockatnv,\
|
||||
rohitrajani2018,\
|
||||
rorajani,\
|
||||
cdesiniotis,\
|
||||
shivamerla,\
|
||||
ArangoGutierrez,\
|
||||
22
.github/workflows/pre-sanity.yml
vendored
Normal file
22
.github/workflows/pre-sanity.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Run pre sanity
|
||||
|
||||
# run this workflow for each commit
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Build dev image
|
||||
run: make .build-image
|
||||
|
||||
- name: Build
|
||||
run: make docker-build
|
||||
|
||||
- name: Tests
|
||||
run: make docker-coverage
|
||||
|
||||
- name: Checks
|
||||
run: make docker-check
|
||||
@@ -102,19 +102,35 @@ unit-tests:
|
||||
name: ${ARTIFACTS_NAME}
|
||||
paths:
|
||||
- ${ARTIFACTS_ROOT}
|
||||
needs:
|
||||
- job: package-meta-packages
|
||||
artifacts: true
|
||||
|
||||
# Define the package build targets
|
||||
package-amazonlinux2-aarch64:
|
||||
package-meta-packages:
|
||||
extends:
|
||||
- .package-build
|
||||
- .dist-amazonlinux2
|
||||
- .arch-aarch64
|
||||
- .package-artifacts
|
||||
stage: package-build
|
||||
variables:
|
||||
SKIP_LIBNVIDIA_CONTAINER: "yes"
|
||||
SKIP_NVIDIA_CONTAINER_TOOLKIT: "yes"
|
||||
parallel:
|
||||
matrix:
|
||||
- PACKAGING: [deb, rpm]
|
||||
before_script:
|
||||
- apk add --no-cache coreutils build-base sed git bash make
|
||||
script:
|
||||
- ./scripts/build-packages.sh ${PACKAGING}
|
||||
artifacts:
|
||||
name: ${ARTIFACTS_NAME}
|
||||
paths:
|
||||
- ${ARTIFACTS_ROOT}
|
||||
|
||||
package-amazonlinux2-x86_64:
|
||||
package-centos7-aarch64:
|
||||
extends:
|
||||
- .package-build
|
||||
- .dist-amazonlinux2
|
||||
- .arch-x86_64
|
||||
- .dist-centos7
|
||||
- .arch-aarch64
|
||||
|
||||
package-centos7-x86_64:
|
||||
extends:
|
||||
@@ -140,18 +156,6 @@ package-centos8-x86_64:
|
||||
- .dist-centos8
|
||||
- .arch-x86_64
|
||||
|
||||
package-debian10-amd64:
|
||||
extends:
|
||||
- .package-build
|
||||
- .dist-debian10
|
||||
- .arch-amd64
|
||||
|
||||
package-opensuse-leap15.1-x86_64:
|
||||
extends:
|
||||
- .package-build
|
||||
- .dist-opensuse-leap15.1
|
||||
- .arch-x86_64
|
||||
|
||||
package-ubuntu18.04-amd64:
|
||||
extends:
|
||||
- .package-build
|
||||
@@ -212,10 +216,9 @@ image-ubi8:
|
||||
- .package-artifacts
|
||||
- .dist-ubi8
|
||||
needs:
|
||||
# Note: The ubi8 image uses the centos8 packages
|
||||
- package-centos8-aarch64
|
||||
- package-centos8-x86_64
|
||||
- package-centos8-ppc64le
|
||||
# Note: The ubi8 image uses the centos7 packages
|
||||
- package-centos7-aarch64
|
||||
- package-centos7-x86_64
|
||||
|
||||
image-ubuntu20.04:
|
||||
extends:
|
||||
@@ -243,6 +246,8 @@ image-packaging:
|
||||
optional: true
|
||||
- job: package-amazonlinux2-x86_64
|
||||
optional: true
|
||||
- job: package-centos7-aarch64
|
||||
optional: true
|
||||
- job: package-centos7-x86_64
|
||||
optional: true
|
||||
- job: package-centos8-ppc64le
|
||||
|
||||
8
.gitmodules
vendored
8
.gitmodules
vendored
@@ -2,11 +2,3 @@
|
||||
path = third_party/libnvidia-container
|
||||
url = https://gitlab.com/nvidia/container-toolkit/libnvidia-container.git
|
||||
branch = main
|
||||
[submodule "third_party/nvidia-container-runtime"]
|
||||
path = third_party/nvidia-container-runtime
|
||||
url = https://gitlab.com/nvidia/container-toolkit/container-runtime.git
|
||||
branch = main
|
||||
[submodule "third_party/nvidia-docker"]
|
||||
path = third_party/nvidia-docker
|
||||
url = https://gitlab.com/nvidia/container-toolkit/nvidia-docker.git
|
||||
branch = main
|
||||
|
||||
@@ -37,6 +37,7 @@ variables:
|
||||
STAGING_VERSION: ${CI_COMMIT_SHORT_SHA}
|
||||
ARTIFACTORY_REPO_BASE: "https://urm.nvidia.com/artifactory/sw-gpu-cloudnative"
|
||||
KITMAKER_RELEASE_FOLDER: "kitmaker"
|
||||
PACKAGE_ARCHIVE_RELEASE_FOLDER: "releases"
|
||||
|
||||
.image-pull:
|
||||
stage: image-build
|
||||
@@ -119,6 +120,7 @@ image-packaging:
|
||||
- if [ -z "$SSA_TOKEN" ]; then exit 1; else echo "SSA_TOKEN set!"; fi
|
||||
script:
|
||||
- pulse-cli -n $NSPECT_ID --ssa $SSA_TOKEN scan -i $IMAGE_ARCHIVE -p $CONTAINER_POLICY -o
|
||||
- rm -f "${IMAGE_ARCHIVE}"
|
||||
artifacts:
|
||||
when: always
|
||||
expire_in: 1 week
|
||||
@@ -181,6 +183,13 @@ scan-ubi8-arm64:
|
||||
- image-ubi8
|
||||
- scan-ubi8-amd64
|
||||
|
||||
scan-packaging:
|
||||
extends:
|
||||
- .dist-packaging
|
||||
- .scan
|
||||
needs:
|
||||
- image-packaging
|
||||
|
||||
# Define external release helpers
|
||||
.release:ngc:
|
||||
extends:
|
||||
@@ -203,19 +212,37 @@ scan-ubi8-arm64:
|
||||
PACKAGE_IMAGE_NAME: "${CI_REGISTRY_IMAGE}/container-toolkit"
|
||||
PACKAGE_IMAGE_TAG: "${CI_COMMIT_SHORT_SHA}-packaging"
|
||||
KITMAKER_ARTIFACTORY_REPO: "${ARTIFACTORY_REPO_BASE}-generic-local/${KITMAKER_RELEASE_FOLDER}"
|
||||
ARTIFACTS_DIR: "${CI_PROJECT_DIR}/artifacts"
|
||||
script:
|
||||
- !reference [.regctl-setup, before_script]
|
||||
- apk add --no-cache bash git
|
||||
- regctl registry login "${PACKAGE_REGISTRY}" -u "${PACKAGE_REGISTRY_USER}" -p "${PACKAGE_REGISTRY_TOKEN}"
|
||||
- ./scripts/extract-packages.sh "${PACKAGE_IMAGE_NAME}:${PACKAGE_IMAGE_TAG}"
|
||||
# TODO: ./scripts/release-packages-artifactory.sh "${DIST}-${ARCH}" "${PACKAGE_ARTIFACTORY_REPO}"
|
||||
- ./scripts/release-kitmaker-artifactory.sh "${KITMAKER_ARTIFACTORY_REPO}"
|
||||
- rm -rf ${ARTIFACTS_DIR}
|
||||
|
||||
# Define the package release targets
|
||||
release:packages:kitmaker:
|
||||
extends:
|
||||
- .release:packages
|
||||
|
||||
release:archive:
|
||||
extends:
|
||||
- .release:external
|
||||
needs:
|
||||
- image-packaging
|
||||
variables:
|
||||
VERSION: "${CI_COMMIT_SHORT_SHA}"
|
||||
PACKAGE_REGISTRY: "${CI_REGISTRY}"
|
||||
PACKAGE_REGISTRY_USER: "${CI_REGISTRY_USER}"
|
||||
PACKAGE_REGISTRY_TOKEN: "${CI_REGISTRY_PASSWORD}"
|
||||
PACKAGE_IMAGE_NAME: "${CI_REGISTRY_IMAGE}/container-toolkit"
|
||||
PACKAGE_IMAGE_TAG: "${CI_COMMIT_SHORT_SHA}-packaging"
|
||||
PACKAGE_ARCHIVE_ARTIFACTORY_REPO: "${ARTIFACTORY_REPO_BASE}-generic-local/${PACKAGE_ARCHIVE_RELEASE_FOLDER}"
|
||||
script:
|
||||
- apk add --no-cache bash git
|
||||
- ./scripts/archive-packages.sh "${PACKAGE_ARCHIVE_ARTIFACTORY_REPO}"
|
||||
|
||||
release:staging-ubuntu20.04:
|
||||
extends:
|
||||
- .release:staging
|
||||
@@ -239,3 +266,8 @@ release:ngc-ubi8:
|
||||
extends:
|
||||
- .dist-ubi8
|
||||
- .release:ngc
|
||||
|
||||
release:ngc-packaging:
|
||||
extends:
|
||||
- .dist-packaging
|
||||
- .release:ngc
|
||||
|
||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,5 +1,29 @@
|
||||
# NVIDIA Container Toolkit Changelog
|
||||
|
||||
## v1.14.0-rc.1
|
||||
|
||||
* Add support for updating containerd configs to the `nvidia-ctk runtime configure` command.
|
||||
* Create file in `etc/ld.so.conf.d` with permissions `644` to support non-root containers.
|
||||
* Generate CDI specification files with `644` permissions to allow rootless applications (e.g. podman)
|
||||
* Add `nvidia-ctk cdi list` command to show the known CDI devices.
|
||||
* Add support for generating merged devices (e.g. `all` device) to the nvcdi API.
|
||||
* Use *.* pattern to locate libcuda.so when generating a CDI specification to support platforms where a patch version is not specified.
|
||||
* Update go-nvlib to skip devices that are not MIG capable when generating CDI specifications.
|
||||
* Add `nvidia-container-runtime-hook.path` config option to specify NVIDIA Container Runtime Hook path explicitly.
|
||||
* Fix bug in creation of `/dev/char` symlinks by failing operation if kernel modules are not loaded.
|
||||
* Add option to load kernel modules when creating device nodes
|
||||
* Add option to create device nodes when creating `/dev/char` symlinks
|
||||
* Bump CUDA base image version to 12.1.1.
|
||||
|
||||
* [libnvidia-container] Support OpenSSL 3 with the Encrypt/Decrypt library
|
||||
|
||||
## v1.13.1
|
||||
|
||||
* Update `update-ldcache` hook to only update ldcache if it exists.
|
||||
* Update `update-ldcache` hook to create `/etc/ld.so.conf.d` folder if it doesn't exist.
|
||||
* Fix failure when libcuda cannot be located during XOrg library discovery.
|
||||
* Fix CDI spec generation on systems that use `/etc/alternatives` (e.g. Debian)
|
||||
|
||||
## v1.13.0
|
||||
|
||||
* Promote 1.13.0-rc.3 to 1.13.0
|
||||
|
||||
@@ -87,11 +87,4 @@ LABEL description="See summary"
|
||||
|
||||
RUN mkdir /licenses && mv /NGC-DL-CONTAINER-LICENSE /licenses/NGC-DL-CONTAINER-LICENSE
|
||||
|
||||
# Install / upgrade packages here that are required to resolve CVEs
|
||||
ARG CVE_UPDATES
|
||||
RUN if [ -n "${CVE_UPDATES}" ]; then \
|
||||
yum update -y ${CVE_UPDATES} && \
|
||||
rm -rf /var/cache/yum/*; \
|
||||
fi
|
||||
|
||||
ENTRYPOINT ["/work/nvidia-toolkit"]
|
||||
|
||||
@@ -95,11 +95,4 @@ LABEL description="See summary"
|
||||
|
||||
RUN mkdir /licenses && mv /NGC-DL-CONTAINER-LICENSE /licenses/NGC-DL-CONTAINER-LICENSE
|
||||
|
||||
# Install / upgrade packages here that are required to resolve CVEs
|
||||
ARG CVE_UPDATES
|
||||
RUN if [ -n "${CVE_UPDATES}" ]; then \
|
||||
apt-get update && apt-get upgrade -y ${CVE_UPDATES} && \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
fi
|
||||
|
||||
ENTRYPOINT ["/work/nvidia-toolkit"]
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
BUILD_MULTI_ARCH_IMAGES ?= false
|
||||
DOCKER ?= docker
|
||||
REGCTL ?= regctl
|
||||
|
||||
BUILDX =
|
||||
ifeq ($(BUILD_MULTI_ARCH_IMAGES),true)
|
||||
@@ -74,6 +75,14 @@ endif
|
||||
push-%: DIST = $(*)
|
||||
push-short: DIST = $(DEFAULT_PUSH_TARGET)
|
||||
|
||||
# Define the push targets
|
||||
$(PUSH_TARGETS): push-%:
|
||||
$(CURDIR)/scripts/publish-image.sh $(IMAGE) $(OUT_IMAGE)
|
||||
|
||||
push-short:
|
||||
$(CURDIR)/scripts/publish-image.sh $(IMAGE) $(OUT_IMAGE)
|
||||
|
||||
|
||||
build-%: DIST = $(*)
|
||||
build-%: DOCKERFILE = $(CURDIR)/build/container/Dockerfile.$(DOCKERFILE_SUFFIX)
|
||||
|
||||
@@ -98,7 +107,6 @@ $(BUILD_TARGETS): build-%: $(ARTIFACTS_ROOT)
|
||||
--build-arg GIT_COMMIT_SHORT="$(GIT_COMMIT_SHORT)" \
|
||||
--build-arg GIT_BRANCH="$(GIT_BRANCH)" \
|
||||
--build-arg SOURCE_DATE_EPOCH="$(SOURCE_DATE_EPOCH)" \
|
||||
--build-arg CVE_UPDATES="$(CVE_UPDATES)" \
|
||||
-f $(DOCKERFILE) \
|
||||
$(CURDIR)
|
||||
|
||||
@@ -110,7 +118,7 @@ build-ubuntu%: LIBNVIDIA_CONTAINER0_DEPENDENCY=$(LIBNVIDIA_CONTAINER0_VERSION)
|
||||
|
||||
build-ubi8: BASE_DIST := ubi8
|
||||
build-ubi8: DOCKERFILE_SUFFIX := centos
|
||||
build-ubi8: PACKAGE_DIST = centos8
|
||||
build-ubi8: PACKAGE_DIST = centos7
|
||||
|
||||
build-centos7: BASE_DIST = $(*)
|
||||
build-centos7: DOCKERFILE_SUFFIX := centos
|
||||
@@ -135,15 +143,11 @@ $(TEST_TARGETS): test-%:
|
||||
test-packaging: DIST = packaging
|
||||
test-packaging:
|
||||
@echo "Testing package image contents"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/amazonlinux2/aarch64" || echo "Missing amazonlinux2/aarch64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/amazonlinux2/x86_64" || echo "Missing amazonlinux2/x86_64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/centos7/ppc64le" || echo "Missing centos7/ppc64le"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/centos7/aarch64" || echo "Missing centos7/aarch64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/centos7/x86_64" || echo "Missing centos7/x86_64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/centos8/aarch64" || echo "Missing centos8/aarch64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/centos8/ppc64le" || echo "Missing centos8/ppc64le"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/centos8/x86_64" || echo "Missing centos8/x86_64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/debian10/amd64" || echo "Missing debian10/amd64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/opensuse-leap15.1/x86_64" || echo "Missing opensuse-leap15.1/x86_64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/ubuntu18.04/amd64" || echo "Missing ubuntu18.04/amd64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/ubuntu18.04/arm64" || echo "Missing ubuntu18.04/arm64"
|
||||
@$(DOCKER) run --rm $(IMAGE) test -d "/artifacts/packages/ubuntu18.04/ppc64le" || echo "Missing ubuntu18.04/ppc64le"
|
||||
|
||||
@@ -16,17 +16,6 @@ PUSH_ON_BUILD ?= false
|
||||
DOCKER_BUILD_OPTIONS = --output=type=image,push=$(PUSH_ON_BUILD)
|
||||
DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64,linux/arm64
|
||||
|
||||
REGCTL ?= regctl
|
||||
$(PUSH_TARGETS): push-%:
|
||||
$(REGCTL) \
|
||||
image copy \
|
||||
$(IMAGE) $(OUT_IMAGE)
|
||||
|
||||
push-short:
|
||||
$(REGCTL) \
|
||||
image copy \
|
||||
$(IMAGE) $(OUT_IMAGE_NAME):$(OUT_IMAGE_VERSION)
|
||||
|
||||
# We only have x86_64 packages for centos7
|
||||
build-centos7: DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64
|
||||
|
||||
|
||||
@@ -13,11 +13,3 @@
|
||||
# limitations under the License.
|
||||
|
||||
DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64
|
||||
|
||||
$(PUSH_TARGETS): push-%:
|
||||
$(DOCKER) tag "$(IMAGE)" "$(OUT_IMAGE)"
|
||||
$(DOCKER) push "$(OUT_IMAGE)"
|
||||
|
||||
push-short:
|
||||
$(DOCKER) tag "$(IMAGE_NAME):$(VERSION)-$(DEFAULT_PUSH_TARGET)" "$(OUT_IMAGE_NAME):$(OUT_IMAGE_VERSION)"
|
||||
$(DOCKER) push "$(OUT_IMAGE_NAME):$(OUT_IMAGE_VERSION)"
|
||||
|
||||
@@ -45,7 +45,7 @@ type nvidiaConfig struct {
|
||||
type containerConfig struct {
|
||||
Pid int
|
||||
Rootfs string
|
||||
Env map[string]string
|
||||
Image image.CUDA
|
||||
Nvidia *nvidiaConfig
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ func getContainerConfig(hook HookConfig) (config containerConfig) {
|
||||
return containerConfig{
|
||||
Pid: h.Pid,
|
||||
Rootfs: s.Root.Path,
|
||||
Env: image,
|
||||
Image: image,
|
||||
Nvidia: getNvidiaConfig(&hook, image, s.Mounts, privileged),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ func TestGetNvidiaConfig(t *testing.T) {
|
||||
getConfig := func() {
|
||||
hookConfig := tc.hookConfig
|
||||
if hookConfig == nil {
|
||||
defaultConfig := getDefaultHookConfig()
|
||||
defaultConfig, _ := getDefaultHookConfig()
|
||||
hookConfig = &defaultConfig
|
||||
}
|
||||
config = getNvidiaConfig(hookConfig, tc.env, nil, tc.privileged)
|
||||
@@ -708,7 +708,7 @@ func TestDeviceListSourcePriority(t *testing.T) {
|
||||
env := map[string]string{
|
||||
envNVVisibleDevices: tc.envvarDevices,
|
||||
}
|
||||
hookConfig := getDefaultHookConfig()
|
||||
hookConfig, _ := getDefaultHookConfig()
|
||||
hookConfig.AcceptEnvvarUnprivileged = tc.acceptUnprivileged
|
||||
hookConfig.AcceptDeviceListAsVolumeMounts = tc.acceptMounts
|
||||
devices = getDevices(&hookConfig, env, tc.mountDevices, tc.privileged)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
@@ -48,8 +49,18 @@ type HookConfig struct {
|
||||
NVIDIAContainerRuntimeHook config.RuntimeHookConfig `toml:"nvidia-container-runtime-hook"`
|
||||
}
|
||||
|
||||
func getDefaultHookConfig() HookConfig {
|
||||
return HookConfig{
|
||||
func getDefaultHookConfig() (HookConfig, error) {
|
||||
rtConfig, err := config.GetDefaultRuntimeConfig()
|
||||
if err != nil {
|
||||
return HookConfig{}, err
|
||||
}
|
||||
|
||||
rtHookConfig, err := config.GetDefaultRuntimeHookConfig()
|
||||
if err != nil {
|
||||
return HookConfig{}, err
|
||||
}
|
||||
|
||||
c := HookConfig{
|
||||
DisableRequire: false,
|
||||
SwarmResource: nil,
|
||||
AcceptEnvvarUnprivileged: true,
|
||||
@@ -67,28 +78,37 @@ func getDefaultHookConfig() HookConfig {
|
||||
User: nil,
|
||||
Ldconfig: nil,
|
||||
},
|
||||
NVIDIAContainerRuntime: *config.GetDefaultRuntimeConfig(),
|
||||
NVIDIAContainerRuntimeHook: *config.GetDefaultRuntimeHookConfig(),
|
||||
NVIDIAContainerRuntime: *rtConfig,
|
||||
NVIDIAContainerRuntimeHook: *rtHookConfig,
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func getHookConfig() (config HookConfig) {
|
||||
func getHookConfig() (*HookConfig, error) {
|
||||
var err error
|
||||
var config HookConfig
|
||||
|
||||
if len(*configflag) > 0 {
|
||||
config = getDefaultHookConfig()
|
||||
config, err = getDefaultHookConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get default configuration: %v", err)
|
||||
}
|
||||
_, err = toml.DecodeFile(*configflag, &config)
|
||||
if err != nil {
|
||||
log.Panicln("couldn't open configuration file:", err)
|
||||
return nil, fmt.Errorf("couldn't open configuration file: %v", err)
|
||||
}
|
||||
} else {
|
||||
for _, p := range defaultPaths {
|
||||
config = getDefaultHookConfig()
|
||||
config, err = getDefaultHookConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get default configuration: %v", err)
|
||||
}
|
||||
_, err = toml.DecodeFile(p, &config)
|
||||
if err == nil {
|
||||
break
|
||||
} else if !os.IsNotExist(err) {
|
||||
log.Panicln("couldn't open default configuration file:", err)
|
||||
return nil, fmt.Errorf("couldn't open default configuration file: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +122,7 @@ func getHookConfig() (config HookConfig) {
|
||||
log.Panicf("Invalid value for config option '%v'; %v (supported: %v)\n", configName, config.SupportedDriverCapabilities, allDriverCapabilities)
|
||||
}
|
||||
|
||||
return config
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// getConfigOption returns the toml config option associated with the
|
||||
|
||||
@@ -89,7 +89,8 @@ func TestGetHookConfig(t *testing.T) {
|
||||
|
||||
var config HookConfig
|
||||
getHookConfig := func() {
|
||||
config = getHookConfig()
|
||||
c, _ := getHookConfig()
|
||||
config = *c
|
||||
}
|
||||
|
||||
if tc.expectedPanic {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/info"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
)
|
||||
|
||||
@@ -71,20 +72,23 @@ func doPrestart() {
|
||||
defer exit()
|
||||
log.SetFlags(0)
|
||||
|
||||
hook := getHookConfig()
|
||||
hook, err := getHookConfig()
|
||||
if err != nil || hook == nil {
|
||||
log.Panicln("error getting hook config:", err)
|
||||
}
|
||||
cli := hook.NvidiaContainerCLI
|
||||
|
||||
if !hook.NVIDIAContainerRuntimeHook.SkipModeDetection && info.ResolveAutoMode(&logInterceptor{}, hook.NVIDIAContainerRuntime.Mode) != "legacy" {
|
||||
log.Panicln("invoking the NVIDIA Container Runtime Hook directly (e.g. specifying the docker --gpus flag) is not supported. Please use the NVIDIA Container Runtime (e.g. specify the --runtime=nvidia flag) instead.")
|
||||
}
|
||||
|
||||
container := getContainerConfig(hook)
|
||||
container := getContainerConfig(*hook)
|
||||
nvidia := container.Nvidia
|
||||
if nvidia == nil {
|
||||
// Not a GPU container, nothing to do.
|
||||
return
|
||||
}
|
||||
|
||||
if !hook.NVIDIAContainerRuntimeHook.SkipModeDetection && info.ResolveAutoMode(&logInterceptor{}, hook.NVIDIAContainerRuntime.Mode, container.Image) != "legacy" {
|
||||
log.Panicln("invoking the NVIDIA Container Runtime Hook directly (e.g. specifying the docker --gpus flag) is not supported. Please use the NVIDIA Container Runtime (e.g. specify the --runtime=nvidia flag) instead.")
|
||||
}
|
||||
|
||||
rootfs := getRootfsPath(container)
|
||||
|
||||
args := []string{getCLIPath(cli)}
|
||||
@@ -185,11 +189,11 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// logInterceptor implements the info.Logger interface to allow for logging from this function.
|
||||
type logInterceptor struct{}
|
||||
// logInterceptor implements the logger.Interface to allow for logging from executable.
|
||||
type logInterceptor struct {
|
||||
logger.NullLogger
|
||||
}
|
||||
|
||||
func (l *logInterceptor) Infof(format string, args ...interface{}) {
|
||||
log.Printf(format, args...)
|
||||
}
|
||||
|
||||
func (l *logInterceptor) Debugf(format string, args ...interface{}) {}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -13,7 +14,7 @@ import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/modifier"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/test"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -42,7 +43,7 @@ func TestMain(m *testing.M) {
|
||||
var err error
|
||||
moduleRoot, err := test.GetModuleRoot()
|
||||
if err != nil {
|
||||
logrus.Fatalf("error in test setup: could not get module root: %v", err)
|
||||
log.Fatalf("error in test setup: could not get module root: %v", err)
|
||||
}
|
||||
testBinPath := filepath.Join(moduleRoot, "test", "bin")
|
||||
testInputPath := filepath.Join(moduleRoot, "test", "input")
|
||||
@@ -54,11 +55,11 @@ func TestMain(m *testing.M) {
|
||||
// Confirm that the environment is configured correctly
|
||||
runcPath, err := exec.LookPath(runcExecutableName)
|
||||
if err != nil || filepath.Join(testBinPath, runcExecutableName) != runcPath {
|
||||
logrus.Fatalf("error in test setup: mock runc path set incorrectly in TestMain(): %v", err)
|
||||
log.Fatalf("error in test setup: mock runc path set incorrectly in TestMain(): %v", err)
|
||||
}
|
||||
hookPath, err := exec.LookPath(nvidiaHook)
|
||||
if err != nil || filepath.Join(testBinPath, nvidiaHook) != hookPath {
|
||||
logrus.Fatalf("error in test setup: mock hook path set incorrectly in TestMain(): %v", err)
|
||||
log.Fatalf("error in test setup: mock hook path set incorrectly in TestMain(): %v", err)
|
||||
}
|
||||
|
||||
// Store the root and binary paths in the test Config
|
||||
@@ -172,7 +173,8 @@ func TestDuplicateHook(t *testing.T) {
|
||||
// addNVIDIAHook is a basic wrapper for an addHookModifier that is used for
|
||||
// testing.
|
||||
func addNVIDIAHook(spec *specs.Spec) error {
|
||||
m := modifier.NewStableRuntimeModifier(logrus.StandardLogger())
|
||||
logger, _ := testlog.NewNullLogger()
|
||||
m := modifier.NewStableRuntimeModifier(logger, nvidiaHook)
|
||||
return m.Modify(spec)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,17 +18,18 @@ package cdi
|
||||
|
||||
import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/cdi/generate"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/cdi/list"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/cdi/transform"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewCommand constructs an info command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -46,6 +47,7 @@ func (m command) build() *cli.Command {
|
||||
hook.Subcommands = []*cli.Command{
|
||||
generate.NewCommand(m.logger),
|
||||
transform.NewCommand(m.logger),
|
||||
list.NewCommand(m.logger),
|
||||
}
|
||||
|
||||
return &hook
|
||||
|
||||
@@ -22,13 +22,13 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/edits"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover/csv"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
specs "github.com/container-orchestrated-devices/container-device-interface/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -37,10 +37,10 @@ const (
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type config struct {
|
||||
type options struct {
|
||||
output string
|
||||
format string
|
||||
deviceNameStrategy string
|
||||
@@ -49,10 +49,14 @@ type config struct {
|
||||
mode string
|
||||
vendor string
|
||||
class string
|
||||
|
||||
csv struct {
|
||||
files cli.StringSlice
|
||||
}
|
||||
}
|
||||
|
||||
// NewCommand constructs a generate-cdi command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -61,17 +65,17 @@ func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
|
||||
// build creates the CLI command
|
||||
func (m command) build() *cli.Command {
|
||||
cfg := config{}
|
||||
opts := options{}
|
||||
|
||||
// Create the 'generate-cdi' command
|
||||
c := cli.Command{
|
||||
Name: "generate",
|
||||
Usage: "Generate CDI specifications for use with CDI-enabled runtimes",
|
||||
Before: func(c *cli.Context) error {
|
||||
return m.validateFlags(c, &cfg)
|
||||
return m.validateFlags(c, &opts)
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return m.run(c, &cfg)
|
||||
return m.run(c, &opts)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -79,109 +83,115 @@ func (m command) build() *cli.Command {
|
||||
&cli.StringFlag{
|
||||
Name: "output",
|
||||
Usage: "Specify the file to output the generated CDI specification to. If this is '' the specification is output to STDOUT",
|
||||
Destination: &cfg.output,
|
||||
Destination: &opts.output,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "The output format for the generated spec [json | yaml]. This overrides the format defined by the output file extension (if specified).",
|
||||
Value: spec.FormatYAML,
|
||||
Destination: &cfg.format,
|
||||
Destination: &opts.format,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "mode",
|
||||
Aliases: []string{"discovery-mode"},
|
||||
Usage: "The mode to use when discovering the available entities. One of [auto | nvml | wsl]. If mode is set to 'auto' the mode will be determined based on the system configuration.",
|
||||
Value: nvcdi.ModeAuto,
|
||||
Destination: &cfg.mode,
|
||||
Destination: &opts.mode,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "device-name-strategy",
|
||||
Usage: "Specify the strategy for generating device names. One of [index | uuid | type-index]",
|
||||
Value: nvcdi.DeviceNameStrategyIndex,
|
||||
Destination: &cfg.deviceNameStrategy,
|
||||
Destination: &opts.deviceNameStrategy,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "driver-root",
|
||||
Usage: "Specify the NVIDIA GPU driver root to use when discovering the entities that should be included in the CDI specification.",
|
||||
Destination: &cfg.driverRoot,
|
||||
Destination: &opts.driverRoot,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "nvidia-ctk-path",
|
||||
Usage: "Specify the path to use for the nvidia-ctk in the generated CDI specification. If this is left empty, the path will be searched.",
|
||||
Destination: &cfg.nvidiaCTKPath,
|
||||
Destination: &opts.nvidiaCTKPath,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "vendor",
|
||||
Aliases: []string{"cdi-vendor"},
|
||||
Usage: "the vendor string to use for the generated CDI specification.",
|
||||
Value: "nvidia.com",
|
||||
Destination: &cfg.vendor,
|
||||
Destination: &opts.vendor,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "class",
|
||||
Aliases: []string{"cdi-class"},
|
||||
Usage: "the class string to use for the generated CDI specification.",
|
||||
Value: "gpu",
|
||||
Destination: &cfg.class,
|
||||
Destination: &opts.class,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "csv.file",
|
||||
Usage: "The path to the list of CSV files to use when generating the CDI specification in CDI mode.",
|
||||
Value: cli.NewStringSlice(csv.DefaultFileList()...),
|
||||
Destination: &opts.csv.files,
|
||||
},
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func (m command) validateFlags(c *cli.Context, cfg *config) error {
|
||||
|
||||
cfg.format = strings.ToLower(cfg.format)
|
||||
switch cfg.format {
|
||||
func (m command) validateFlags(c *cli.Context, opts *options) error {
|
||||
opts.format = strings.ToLower(opts.format)
|
||||
switch opts.format {
|
||||
case spec.FormatJSON:
|
||||
case spec.FormatYAML:
|
||||
default:
|
||||
return fmt.Errorf("invalid output format: %v", cfg.format)
|
||||
return fmt.Errorf("invalid output format: %v", opts.format)
|
||||
}
|
||||
|
||||
cfg.mode = strings.ToLower(cfg.mode)
|
||||
switch cfg.mode {
|
||||
opts.mode = strings.ToLower(opts.mode)
|
||||
switch opts.mode {
|
||||
case nvcdi.ModeAuto:
|
||||
case nvcdi.ModeCSV:
|
||||
case nvcdi.ModeNvml:
|
||||
case nvcdi.ModeWsl:
|
||||
case nvcdi.ModeManagement:
|
||||
default:
|
||||
return fmt.Errorf("invalid discovery mode: %v", cfg.mode)
|
||||
return fmt.Errorf("invalid discovery mode: %v", opts.mode)
|
||||
}
|
||||
|
||||
_, err := nvcdi.NewDeviceNamer(cfg.deviceNameStrategy)
|
||||
_, err := nvcdi.NewDeviceNamer(opts.deviceNameStrategy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg.nvidiaCTKPath = discover.FindNvidiaCTK(m.logger, cfg.nvidiaCTKPath)
|
||||
opts.nvidiaCTKPath = config.ResolveNVIDIACTKPath(m.logger, opts.nvidiaCTKPath)
|
||||
|
||||
if outputFileFormat := formatFromFilename(cfg.output); outputFileFormat != "" {
|
||||
if outputFileFormat := formatFromFilename(opts.output); outputFileFormat != "" {
|
||||
m.logger.Debugf("Inferred output format as %q from output file name", outputFileFormat)
|
||||
if !c.IsSet("format") {
|
||||
cfg.format = outputFileFormat
|
||||
} else if outputFileFormat != cfg.format {
|
||||
m.logger.Warningf("Requested output format %q does not match format implied by output file name: %q", cfg.format, outputFileFormat)
|
||||
opts.format = outputFileFormat
|
||||
} else if outputFileFormat != opts.format {
|
||||
m.logger.Warningf("Requested output format %q does not match format implied by output file name: %q", opts.format, outputFileFormat)
|
||||
}
|
||||
}
|
||||
|
||||
if err := cdi.ValidateVendorName(cfg.vendor); err != nil {
|
||||
if err := cdi.ValidateVendorName(opts.vendor); err != nil {
|
||||
return fmt.Errorf("invalid CDI vendor name: %v", err)
|
||||
}
|
||||
if err := cdi.ValidateClassName(cfg.class); err != nil {
|
||||
if err := cdi.ValidateClassName(opts.class); err != nil {
|
||||
return fmt.Errorf("invalid CDI class name: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m command) run(c *cli.Context, cfg *config) error {
|
||||
spec, err := m.generateSpec(cfg)
|
||||
func (m command) run(c *cli.Context, opts *options) error {
|
||||
spec, err := m.generateSpec(opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate CDI spec: %v", err)
|
||||
}
|
||||
m.logger.Infof("Generated CDI spec with version %v", spec.Raw().Version)
|
||||
|
||||
if cfg.output == "" {
|
||||
if opts.output == "" {
|
||||
_, err := spec.WriteTo(os.Stdout)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write CDI spec to STDOUT: %v", err)
|
||||
@@ -189,7 +199,7 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return spec.Save(cfg.output)
|
||||
return spec.Save(opts.output)
|
||||
}
|
||||
|
||||
func formatFromFilename(filename string) string {
|
||||
@@ -204,18 +214,19 @@ func formatFromFilename(filename string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m command) generateSpec(cfg *config) (spec.Interface, error) {
|
||||
deviceNamer, err := nvcdi.NewDeviceNamer(cfg.deviceNameStrategy)
|
||||
func (m command) generateSpec(opts *options) (spec.Interface, error) {
|
||||
deviceNamer, err := nvcdi.NewDeviceNamer(opts.deviceNameStrategy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create device namer: %v", err)
|
||||
}
|
||||
|
||||
cdilib, err := nvcdi.New(
|
||||
nvcdi.WithLogger(m.logger),
|
||||
nvcdi.WithDriverRoot(cfg.driverRoot),
|
||||
nvcdi.WithNVIDIACTKPath(cfg.nvidiaCTKPath),
|
||||
nvcdi.WithDriverRoot(opts.driverRoot),
|
||||
nvcdi.WithNVIDIACTKPath(opts.nvidiaCTKPath),
|
||||
nvcdi.WithDeviceNamer(deviceNamer),
|
||||
nvcdi.WithMode(string(cfg.mode)),
|
||||
nvcdi.WithMode(string(opts.mode)),
|
||||
nvcdi.WithCSVFiles(opts.csv.files.Value()),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create CDI library: %v", err)
|
||||
@@ -225,20 +236,6 @@ func (m command) generateSpec(cfg *config) (spec.Interface, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create device CDI specs: %v", err)
|
||||
}
|
||||
var hasAll bool
|
||||
for _, deviceSpec := range deviceSpecs {
|
||||
if deviceSpec.Name == allDeviceName {
|
||||
hasAll = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasAll {
|
||||
allDevice, err := MergeDeviceSpecs(deviceSpecs, allDeviceName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create CDI specification for %q device: %v", allDeviceName, err)
|
||||
}
|
||||
deviceSpecs = append(deviceSpecs, allDevice)
|
||||
}
|
||||
|
||||
commonEdits, err := cdilib.GetCommonEdits()
|
||||
if err != nil {
|
||||
@@ -246,38 +243,15 @@ func (m command) generateSpec(cfg *config) (spec.Interface, error) {
|
||||
}
|
||||
|
||||
return spec.New(
|
||||
spec.WithVendor(cfg.vendor),
|
||||
spec.WithClass(cfg.class),
|
||||
spec.WithVendor(opts.vendor),
|
||||
spec.WithClass(opts.class),
|
||||
spec.WithDeviceSpecs(deviceSpecs),
|
||||
spec.WithEdits(*commonEdits.ContainerEdits),
|
||||
spec.WithFormat(cfg.format),
|
||||
spec.WithFormat(opts.format),
|
||||
spec.WithMergedDeviceOptions(
|
||||
transform.WithName(allDeviceName),
|
||||
transform.WithSkipIfExists(true),
|
||||
),
|
||||
spec.WithPermissions(0644),
|
||||
)
|
||||
}
|
||||
|
||||
// MergeDeviceSpecs creates a device with the specified name which combines the edits from the previous devices.
|
||||
// If a device of the specified name already exists, an error is returned.
|
||||
func MergeDeviceSpecs(deviceSpecs []specs.Device, mergedDeviceName string) (specs.Device, error) {
|
||||
if err := cdi.ValidateDeviceName(mergedDeviceName); err != nil {
|
||||
return specs.Device{}, fmt.Errorf("invalid device name %q: %v", mergedDeviceName, err)
|
||||
}
|
||||
for _, d := range deviceSpecs {
|
||||
if d.Name == mergedDeviceName {
|
||||
return specs.Device{}, fmt.Errorf("device %q already exists", mergedDeviceName)
|
||||
}
|
||||
}
|
||||
|
||||
mergedEdits := edits.NewContainerEdits()
|
||||
|
||||
for _, d := range deviceSpecs {
|
||||
edit := cdi.ContainerEdits{
|
||||
ContainerEdits: &d.ContainerEdits,
|
||||
}
|
||||
mergedEdits.Append(&edit)
|
||||
}
|
||||
|
||||
merged := specs.Device{
|
||||
Name: mergedDeviceName,
|
||||
ContainerEdits: *mergedEdits.ContainerEdits,
|
||||
}
|
||||
return merged, nil
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/**
|
||||
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/container-orchestrated-devices/container-device-interface/specs-go"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMergeDeviceSpecs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
deviceSpecs []specs.Device
|
||||
mergedDeviceName string
|
||||
expectedError error
|
||||
expected specs.Device
|
||||
}{
|
||||
{
|
||||
description: "no devices",
|
||||
mergedDeviceName: "all",
|
||||
expected: specs.Device{
|
||||
Name: "all",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "one device",
|
||||
mergedDeviceName: "all",
|
||||
deviceSpecs: []specs.Device{
|
||||
{
|
||||
Name: "gpu0",
|
||||
ContainerEdits: specs.ContainerEdits{
|
||||
Env: []string{"GPU=0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: specs.Device{
|
||||
Name: "all",
|
||||
ContainerEdits: specs.ContainerEdits{
|
||||
Env: []string{"GPU=0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "two devices",
|
||||
mergedDeviceName: "all",
|
||||
deviceSpecs: []specs.Device{
|
||||
{
|
||||
Name: "gpu0",
|
||||
ContainerEdits: specs.ContainerEdits{
|
||||
Env: []string{"GPU=0"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "gpu1",
|
||||
ContainerEdits: specs.ContainerEdits{
|
||||
Env: []string{"GPU=1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: specs.Device{
|
||||
Name: "all",
|
||||
ContainerEdits: specs.ContainerEdits{
|
||||
Env: []string{"GPU=0", "GPU=1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "has merged device",
|
||||
mergedDeviceName: "gpu0",
|
||||
deviceSpecs: []specs.Device{
|
||||
{
|
||||
Name: "gpu0",
|
||||
ContainerEdits: specs.ContainerEdits{
|
||||
Env: []string{"GPU=0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: fmt.Errorf("device %q already exists", "gpu0"),
|
||||
},
|
||||
{
|
||||
description: "invalid merged device name",
|
||||
mergedDeviceName: ".-not-valid",
|
||||
expectedError: fmt.Errorf("invalid device name %q", ".-not-valid"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
mergedDevice, err := MergeDeviceSpecs(tc.deviceSpecs, tc.mergedDeviceName)
|
||||
|
||||
if tc.expectedError != nil {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, tc.expected, mergedDevice)
|
||||
})
|
||||
}
|
||||
}
|
||||
87
cmd/nvidia-ctk/cdi/list/list.go
Normal file
87
cmd/nvidia-ctk/cdi/list/list.go
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package list
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type config struct{}
|
||||
|
||||
// NewCommand constructs a cdi list command with the specified logger
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
return c.build()
|
||||
}
|
||||
|
||||
// build creates the CLI command
|
||||
func (m command) build() *cli.Command {
|
||||
cfg := config{}
|
||||
|
||||
// Create the command
|
||||
c := cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List the available CDI devices",
|
||||
Before: func(c *cli.Context) error {
|
||||
return m.validateFlags(c, &cfg)
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return m.run(c, &cfg)
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags = []cli.Flag{}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func (m command) validateFlags(c *cli.Context, cfg *config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m command) run(c *cli.Context, cfg *config) error {
|
||||
registry, err := cdi.NewCache(
|
||||
cdi.WithAutoRefresh(false),
|
||||
cdi.WithSpecDirs(cdi.DefaultSpecDirs...),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create CDI cache: %v", err)
|
||||
}
|
||||
|
||||
devices := registry.ListDevices()
|
||||
if len(devices) == 0 {
|
||||
m.logger.Info("No CDI devices found")
|
||||
return nil
|
||||
}
|
||||
|
||||
m.logger.Infof("Found %d CDI devices", len(devices))
|
||||
for _, device := range devices {
|
||||
fmt.Printf("%s\n", device)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -21,10 +21,10 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/spec"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@ type loadSaver interface {
|
||||
}
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type transformOptions struct {
|
||||
@@ -49,7 +49,7 @@ type options struct {
|
||||
}
|
||||
|
||||
// NewCommand constructs a generate-cdi command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
@@ -18,16 +18,16 @@ package transform
|
||||
|
||||
import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/cdi/transform/root"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewCommand constructs a command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
50
cmd/nvidia-ctk/config/config.go
Normal file
50
cmd/nvidia-ctk/config/config.go
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
createdefault "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/config/create-default"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewCommand constructs an config command with the specified logger
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
return c.build()
|
||||
}
|
||||
|
||||
// build
|
||||
func (m command) build() *cli.Command {
|
||||
// Create the 'config' command
|
||||
c := cli.Command{
|
||||
Name: "config",
|
||||
Usage: "Interact with the NVIDIA Container Toolkit configuration",
|
||||
}
|
||||
|
||||
c.Subcommands = []*cli.Command{
|
||||
createdefault.NewCommand(m.logger),
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
102
cmd/nvidia-ctk/config/create-default/create-default.go
Normal file
102
cmd/nvidia-ctk/config/create-default/create-default.go
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package defaultsubcommand
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
nvctkConfig "github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// options stores the subcommand options
|
||||
type options struct {
|
||||
output string
|
||||
}
|
||||
|
||||
// NewCommand constructs a default command with the specified logger
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
return c.build()
|
||||
}
|
||||
|
||||
// build creates the CLI command
|
||||
func (m command) build() *cli.Command {
|
||||
opts := options{}
|
||||
|
||||
// Create the 'default' command
|
||||
c := cli.Command{
|
||||
Name: "generate-default",
|
||||
Aliases: []string{"default"},
|
||||
Usage: "Generate the default NVIDIA Container Toolkit configuration file",
|
||||
Before: func(c *cli.Context) error {
|
||||
return m.validateFlags(c, &opts)
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return m.run(c, &opts)
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "output",
|
||||
Usage: "Specify the file to output the generated configuration for to. If this is '' the configuration is ouput to STDOUT.",
|
||||
Destination: &opts.output,
|
||||
},
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func (m command) validateFlags(c *cli.Context, opts *options) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m command) run(c *cli.Context, opts *options) error {
|
||||
defaultConfig, err := nvctkConfig.GetDefaultConfigToml()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get default config: %v", err)
|
||||
}
|
||||
|
||||
var output io.Writer
|
||||
if opts.output == "" {
|
||||
output = os.Stdout
|
||||
} else {
|
||||
outputFile, err := os.Create(opts.output)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create output file: %v", err)
|
||||
}
|
||||
defer outputFile.Close()
|
||||
output = outputFile
|
||||
}
|
||||
|
||||
_, err = defaultConfig.WriteTo(output)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write to output: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -23,14 +23,14 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type config struct {
|
||||
@@ -40,7 +40,7 @@ type config struct {
|
||||
}
|
||||
|
||||
// NewCommand constructs a chmod command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
@@ -23,14 +23,15 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover/csv"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type config struct {
|
||||
@@ -41,7 +42,7 @@ type config struct {
|
||||
}
|
||||
|
||||
// NewCommand constructs a hook command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -116,7 +117,7 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
||||
}
|
||||
targets, err := chainLocator.Locate(ms.Path)
|
||||
if err != nil {
|
||||
m.logger.Warnf("Failed to locate symlink %v", ms.Path)
|
||||
m.logger.Warningf("Failed to locate symlink %v", ms.Path)
|
||||
}
|
||||
candidates = append(candidates, targets...)
|
||||
}
|
||||
@@ -125,21 +126,18 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
||||
created := make(map[string]bool)
|
||||
// candidates is a list of absolute paths to symlinks in a chain, or the final target of the chain.
|
||||
for _, candidate := range candidates {
|
||||
targets, err := m.Locate(candidate)
|
||||
target, err := symlinks.Resolve(candidate)
|
||||
if err != nil {
|
||||
m.logger.Debugf("Skipping invalid link: %v", err)
|
||||
continue
|
||||
} else if len(targets) != 1 {
|
||||
m.logger.Debugf("Unexepected number of targets: %v", targets)
|
||||
continue
|
||||
} else if targets[0] == candidate {
|
||||
} else if target == candidate {
|
||||
m.logger.Debugf("%v is not a symlink", candidate)
|
||||
continue
|
||||
}
|
||||
|
||||
err = m.createLink(created, cfg.hostRoot, containerRoot, targets[0], candidate)
|
||||
err = m.createLink(created, cfg.hostRoot, containerRoot, target, candidate)
|
||||
if err != nil {
|
||||
m.logger.Warnf("Failed to create link %v: %v", []string{targets[0], candidate}, err)
|
||||
m.logger.Warningf("Failed to create link %v: %v", []string{target, candidate}, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,13 +145,13 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
||||
for _, l := range links {
|
||||
parts := strings.Split(l, "::")
|
||||
if len(parts) != 2 {
|
||||
m.logger.Warnf("Invalid link specification %v", l)
|
||||
m.logger.Warningf("Invalid link specification %v", l)
|
||||
continue
|
||||
}
|
||||
|
||||
err := m.createLink(created, cfg.hostRoot, containerRoot, parts[0], parts[1])
|
||||
if err != nil {
|
||||
m.logger.Warnf("Failed to create link %v: %v", parts, err)
|
||||
m.logger.Warningf("Failed to create link %v: %v", parts, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +162,7 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
||||
func (m command) createLink(created map[string]bool, hostRoot string, containerRoot string, target string, link string) error {
|
||||
linkPath, err := changeRoot(hostRoot, containerRoot, link)
|
||||
if err != nil {
|
||||
m.logger.Warnf("Failed to resolve path for link %v relative to %v: %v", link, containerRoot, err)
|
||||
m.logger.Warningf("Failed to resolve path for link %v relative to %v: %v", link, containerRoot, err)
|
||||
}
|
||||
if created[linkPath] {
|
||||
m.logger.Debugf("Link %v already created", linkPath)
|
||||
@@ -173,7 +171,7 @@ func (m command) createLink(created map[string]bool, hostRoot string, containerR
|
||||
|
||||
targetPath, err := changeRoot(hostRoot, "/", target)
|
||||
if err != nil {
|
||||
m.logger.Warnf("Failed to resolve path for target %v relative to %v: %v", target, "/", err)
|
||||
m.logger.Warningf("Failed to resolve path for target %v relative to %v: %v", target, "/", err)
|
||||
}
|
||||
|
||||
m.logger.Infof("Symlinking %v to %v", linkPath, targetPath)
|
||||
|
||||
@@ -18,19 +18,19 @@ package hook
|
||||
|
||||
import (
|
||||
chmod "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/chmod"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
|
||||
symlinks "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/create-symlinks"
|
||||
ldcache "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/update-ldcache"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type hookCommand struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewCommand constructs a hook command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := hookCommand{
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
@@ -22,13 +22,13 @@ import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type config struct {
|
||||
@@ -37,7 +37,7 @@ type config struct {
|
||||
}
|
||||
|
||||
// NewCommand constructs an update-ldcache command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -84,6 +84,12 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
||||
return fmt.Errorf("failed to determined container root: %v", err)
|
||||
}
|
||||
|
||||
_, err = os.Stat(filepath.Join(containerRoot, "/etc/ld.so.cache"))
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
m.logger.Debugf("No ld.so.cache found, skipping update")
|
||||
return nil
|
||||
}
|
||||
|
||||
err = m.createConfig(containerRoot, cfg.folders.Value())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update ld.so.conf: %v", err)
|
||||
@@ -105,6 +111,10 @@ func (m command) createConfig(root string, folders []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(root, "/etc/ld.so.conf.d"), 0755); err != nil {
|
||||
return fmt.Errorf("failed to create ld.so.conf.d: %v", err)
|
||||
}
|
||||
|
||||
configFile, err := os.CreateTemp(filepath.Join(root, "/etc/ld.so.conf.d"), "nvcr-*.conf")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create config file: %v", err)
|
||||
@@ -125,5 +135,10 @@ func (m command) createConfig(root string, folders []string) error {
|
||||
configured[folder] = true
|
||||
}
|
||||
|
||||
// The created file needs to be world readable for the cases where the container is run as a non-root user.
|
||||
if err := os.Chmod(configFile.Name(), 0644); err != nil {
|
||||
return fmt.Errorf("failed to chmod config file: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
package info
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewCommand constructs an info command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -35,13 +35,13 @@ func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
|
||||
// build
|
||||
func (m command) build() *cli.Command {
|
||||
// Create the 'hook' command
|
||||
hook := cli.Command{
|
||||
// Create the 'info' command
|
||||
info := cli.Command{
|
||||
Name: "info",
|
||||
Usage: "Provide information about the system",
|
||||
}
|
||||
|
||||
hook.Subcommands = []*cli.Command{}
|
||||
info.Subcommands = []*cli.Command{}
|
||||
|
||||
return &hook
|
||||
return &info
|
||||
}
|
||||
|
||||
@@ -20,28 +20,29 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/cdi"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook"
|
||||
infoCLI "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/info"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/runtime"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/system"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/info"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
cli "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var logger = log.New()
|
||||
|
||||
// config defines the options that can be set for the CLI through config files,
|
||||
// options defines the options that can be set for the CLI through config files,
|
||||
// environment variables, or command line flags
|
||||
type config struct {
|
||||
type options struct {
|
||||
// Debug indicates whether the CLI is started in "debug" mode
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Create a config struct to hold the parsed environment variables or command line flags
|
||||
config := config{}
|
||||
logger := logrus.New()
|
||||
|
||||
// Create a options struct to hold the parsed environment variables or command line flags
|
||||
opts := options{}
|
||||
|
||||
// Create the top-level CLI
|
||||
c := cli.NewApp()
|
||||
@@ -57,16 +58,16 @@ func main() {
|
||||
Name: "debug",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "Enable debug-level logging",
|
||||
Destination: &config.Debug,
|
||||
Destination: &opts.Debug,
|
||||
EnvVars: []string{"NVIDIA_CTK_DEBUG"},
|
||||
},
|
||||
}
|
||||
|
||||
// Set log-level for all subcommands
|
||||
c.Before = func(c *cli.Context) error {
|
||||
logLevel := log.InfoLevel
|
||||
if config.Debug {
|
||||
logLevel = log.DebugLevel
|
||||
logLevel := logrus.InfoLevel
|
||||
if opts.Debug {
|
||||
logLevel = logrus.DebugLevel
|
||||
}
|
||||
logger.SetLevel(logLevel)
|
||||
return nil
|
||||
@@ -79,12 +80,13 @@ func main() {
|
||||
infoCLI.NewCommand(logger),
|
||||
cdi.NewCommand(logger),
|
||||
system.NewCommand(logger),
|
||||
config.NewCommand(logger),
|
||||
}
|
||||
|
||||
// Run the CLI
|
||||
err := c.Run(os.Args)
|
||||
if err != nil {
|
||||
log.Errorf("%v", err)
|
||||
log.Exit(1)
|
||||
logger.Errorf("%v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,31 +17,37 @@
|
||||
package configure
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/runtime/nvidia"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine/crio"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/engine/docker"
|
||||
"github.com/pelletier/go-toml"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/containerd"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/crio"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/docker"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultRuntime = "docker"
|
||||
|
||||
defaultDockerConfigFilePath = "/etc/docker/daemon.json"
|
||||
defaultCrioConfigFilePath = "/etc/crio/crio.conf"
|
||||
// defaultNVIDIARuntimeName is the default name to use in configs for the NVIDIA Container Runtime
|
||||
defaultNVIDIARuntimeName = "nvidia"
|
||||
// defaultNVIDIARuntimeExecutable is the default NVIDIA Container Runtime executable file name
|
||||
defaultNVIDIARuntimeExecutable = "nvidia-container-runtime"
|
||||
defailtNVIDIARuntimeExpecutablePath = "/usr/bin/nvidia-container-runtime"
|
||||
|
||||
defaultContainerdConfigFilePath = "/etc/containerd/config.toml"
|
||||
defaultCrioConfigFilePath = "/etc/crio/crio.conf"
|
||||
defaultDockerConfigFilePath = "/etc/docker/daemon.json"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewCommand constructs an configure command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -54,7 +60,12 @@ type config struct {
|
||||
dryRun bool
|
||||
runtime string
|
||||
configFilePath string
|
||||
nvidiaOptions nvidia.Options
|
||||
|
||||
nvidiaRuntime struct {
|
||||
name string
|
||||
path string
|
||||
setAsDefault bool
|
||||
}
|
||||
}
|
||||
|
||||
func (m command) build() *cli.Command {
|
||||
@@ -65,6 +76,9 @@ func (m command) build() *cli.Command {
|
||||
configure := cli.Command{
|
||||
Name: "configure",
|
||||
Usage: "Add a runtime to the specified container engine",
|
||||
Before: func(c *cli.Context) error {
|
||||
return validateFlags(c, &config)
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return m.configureWrapper(c, &config)
|
||||
},
|
||||
@@ -78,7 +92,7 @@ func (m command) build() *cli.Command {
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "the target runtime engine. One of [crio, docker]",
|
||||
Usage: "the target runtime engine; one of [containerd, crio, docker]",
|
||||
Value: defaultRuntime,
|
||||
Destination: &config.runtime,
|
||||
},
|
||||
@@ -90,124 +104,122 @@ func (m command) build() *cli.Command {
|
||||
&cli.StringFlag{
|
||||
Name: "nvidia-runtime-name",
|
||||
Usage: "specify the name of the NVIDIA runtime that will be added",
|
||||
Value: nvidia.RuntimeName,
|
||||
Destination: &config.nvidiaOptions.RuntimeName,
|
||||
Value: defaultNVIDIARuntimeName,
|
||||
Destination: &config.nvidiaRuntime.name,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "runtime-path",
|
||||
Name: "nvidia-runtime-path",
|
||||
Aliases: []string{"runtime-path"},
|
||||
Usage: "specify the path to the NVIDIA runtime executable",
|
||||
Value: nvidia.RuntimeExecutable,
|
||||
Destination: &config.nvidiaOptions.RuntimePath,
|
||||
Value: defaultNVIDIARuntimeExecutable,
|
||||
Destination: &config.nvidiaRuntime.path,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "set-as-default",
|
||||
Usage: "set the specified runtime as the default runtime",
|
||||
Destination: &config.nvidiaOptions.SetAsDefault,
|
||||
Name: "nvidia-set-as-default",
|
||||
Aliases: []string{"set-as-default"},
|
||||
Usage: "set the NVIDIA runtime as the default runtime",
|
||||
Destination: &config.nvidiaRuntime.setAsDefault,
|
||||
},
|
||||
}
|
||||
|
||||
return &configure
|
||||
}
|
||||
|
||||
func (m command) configureWrapper(c *cli.Context, config *config) error {
|
||||
func validateFlags(c *cli.Context, config *config) error {
|
||||
switch config.runtime {
|
||||
case "containerd", "crio", "docker":
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("unrecognized runtime '%v'", config.runtime)
|
||||
}
|
||||
|
||||
switch config.runtime {
|
||||
case "containerd", "crio":
|
||||
if config.nvidiaRuntime.path == defaultNVIDIARuntimeExecutable {
|
||||
config.nvidiaRuntime.path = defailtNVIDIARuntimeExpecutablePath
|
||||
}
|
||||
if !filepath.IsAbs(config.nvidiaRuntime.path) {
|
||||
return fmt.Errorf("the NVIDIA runtime path %q is not an absolute path", config.nvidiaRuntime.path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// configureWrapper updates the specified container engine config to enable the NVIDIA runtime
|
||||
func (m command) configureWrapper(c *cli.Context, config *config) error {
|
||||
configFilePath := config.resolveConfigFilePath()
|
||||
|
||||
var cfg engine.Interface
|
||||
var err error
|
||||
switch config.runtime {
|
||||
case "containerd":
|
||||
cfg, err = containerd.New(
|
||||
containerd.WithLogger(m.logger),
|
||||
containerd.WithPath(configFilePath),
|
||||
)
|
||||
case "crio":
|
||||
return m.configureCrio(c, config)
|
||||
cfg, err = crio.New(
|
||||
crio.WithLogger(m.logger),
|
||||
crio.WithPath(configFilePath),
|
||||
)
|
||||
case "docker":
|
||||
return m.configureDocker(c, config)
|
||||
cfg, err = docker.New(
|
||||
docker.WithLogger(m.logger),
|
||||
docker.WithPath(configFilePath),
|
||||
)
|
||||
default:
|
||||
err = fmt.Errorf("unrecognized runtime '%v'", config.runtime)
|
||||
}
|
||||
|
||||
return fmt.Errorf("unrecognized runtime '%v'", config.runtime)
|
||||
}
|
||||
|
||||
// configureDocker updates the docker config to enable the NVIDIA Container Runtime
|
||||
func (m command) configureDocker(c *cli.Context, config *config) error {
|
||||
configFilePath := config.configFilePath
|
||||
if configFilePath == "" {
|
||||
configFilePath = defaultDockerConfigFilePath
|
||||
}
|
||||
|
||||
cfg, err := docker.New(
|
||||
docker.WithPath(configFilePath),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load config: %v", err)
|
||||
if err != nil || cfg == nil {
|
||||
return fmt.Errorf("unable to load config for runtime %v: %v", config.runtime, err)
|
||||
}
|
||||
|
||||
err = cfg.AddRuntime(
|
||||
config.nvidiaOptions.RuntimeName,
|
||||
config.nvidiaOptions.RuntimePath,
|
||||
config.nvidiaOptions.SetAsDefault,
|
||||
config.nvidiaRuntime.name,
|
||||
config.nvidiaRuntime.path,
|
||||
config.nvidiaRuntime.setAsDefault,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update config: %v", err)
|
||||
}
|
||||
|
||||
if config.dryRun {
|
||||
output, err := json.MarshalIndent(cfg, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to convert to JSON: %v", err)
|
||||
}
|
||||
os.Stdout.WriteString(fmt.Sprintf("%s\n", output))
|
||||
return nil
|
||||
}
|
||||
n, err := cfg.Save(configFilePath)
|
||||
outputPath := config.getOuputConfigPath()
|
||||
n, err := cfg.Save(outputPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to flush config: %v", err)
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
m.logger.Infof("Removed empty config from %v", configFilePath)
|
||||
m.logger.Infof("Removed empty config from %v", outputPath)
|
||||
} else {
|
||||
m.logger.Infof("Wrote updated config to %v", configFilePath)
|
||||
m.logger.Infof("Wrote updated config to %v", outputPath)
|
||||
}
|
||||
m.logger.Infof("It is recommended that the docker daemon be restarted.")
|
||||
m.logger.Infof("It is recommended that %v daemon be restarted.", config.runtime)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// configureCrio updates the crio config to enable the NVIDIA Container Runtime
|
||||
func (m command) configureCrio(c *cli.Context, config *config) error {
|
||||
configFilePath := config.configFilePath
|
||||
if configFilePath == "" {
|
||||
configFilePath = defaultCrioConfigFilePath
|
||||
// resolveConfigFilePath returns the default config file path for the configured container engine
|
||||
func (c *config) resolveConfigFilePath() string {
|
||||
if c.configFilePath != "" {
|
||||
return c.configFilePath
|
||||
}
|
||||
|
||||
cfg, err := crio.New(
|
||||
crio.WithPath(configFilePath),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load config: %v", err)
|
||||
switch c.runtime {
|
||||
case "containerd":
|
||||
return defaultContainerdConfigFilePath
|
||||
case "crio":
|
||||
return defaultCrioConfigFilePath
|
||||
case "docker":
|
||||
return defaultDockerConfigFilePath
|
||||
}
|
||||
|
||||
err = cfg.AddRuntime(
|
||||
config.nvidiaOptions.RuntimeName,
|
||||
config.nvidiaOptions.RuntimePath,
|
||||
config.nvidiaOptions.SetAsDefault,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update config: %v", err)
|
||||
}
|
||||
|
||||
if config.dryRun {
|
||||
output, err := toml.Marshal(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to convert to TOML: %v", err)
|
||||
}
|
||||
os.Stdout.WriteString(fmt.Sprintf("%s\n", output))
|
||||
return nil
|
||||
}
|
||||
n, err := cfg.Save(configFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to flush config: %v", err)
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
m.logger.Infof("Removed empty config from %v", configFilePath)
|
||||
} else {
|
||||
m.logger.Infof("Wrote updated config to %v", configFilePath)
|
||||
}
|
||||
m.logger.Infof("It is recommended that the cri-o daemon be restarted.")
|
||||
|
||||
return nil
|
||||
return ""
|
||||
}
|
||||
|
||||
// getOuputConfigPath returns the configured config path or "" if dry-run is enabled
|
||||
func (c *config) getOuputConfigPath() string {
|
||||
if c.dryRun {
|
||||
return ""
|
||||
}
|
||||
return c.resolveConfigFilePath()
|
||||
}
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
*/
|
||||
|
||||
package nvidia
|
||||
|
||||
const (
|
||||
// RuntimeName is the default name to use in configs for the NVIDIA Container Runtime
|
||||
RuntimeName = "nvidia"
|
||||
// RuntimeExecutable is the default NVIDIA Container Runtime executable file name
|
||||
RuntimeExecutable = "nvidia-container-runtime"
|
||||
)
|
||||
|
||||
// Options specifies the options for the NVIDIA Container Runtime w.r.t a container engine such as docker.
|
||||
type Options struct {
|
||||
SetAsDefault bool
|
||||
RuntimeName string
|
||||
RuntimePath string
|
||||
}
|
||||
|
||||
// Runtime defines an NVIDIA runtime with a name and a executable
|
||||
type Runtime struct {
|
||||
Name string
|
||||
Path string
|
||||
}
|
||||
|
||||
// DefaultRuntime returns the default runtime for the configured options.
|
||||
// If the configuration is invalid or the default runtimes should not be set
|
||||
// the empty string is returned.
|
||||
func (o Options) DefaultRuntime() string {
|
||||
if !o.SetAsDefault {
|
||||
return ""
|
||||
}
|
||||
|
||||
return o.RuntimeName
|
||||
}
|
||||
|
||||
// Runtime creates a runtime struct based on the options.
|
||||
func (o Options) Runtime() Runtime {
|
||||
path := o.RuntimePath
|
||||
|
||||
if o.RuntimePath == "" {
|
||||
path = RuntimeExecutable
|
||||
}
|
||||
|
||||
r := Runtime{
|
||||
Name: o.RuntimeName,
|
||||
Path: path,
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// DockerRuntimesConfig generatest the expected docker config for the specified runtime
|
||||
func (r Runtime) DockerRuntimesConfig() map[string]interface{} {
|
||||
runtimes := make(map[string]interface{})
|
||||
runtimes[r.Name] = map[string]interface{}{
|
||||
"path": r.Path,
|
||||
"args": []string{},
|
||||
}
|
||||
|
||||
return runtimes
|
||||
}
|
||||
@@ -18,16 +18,16 @@ package runtime
|
||||
|
||||
import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/runtime/configure"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type runtimeCommand struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewCommand constructs a runtime command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := runtimeCommand{
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
@@ -21,36 +21,47 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc/devices"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvpci"
|
||||
)
|
||||
|
||||
type allPossible struct {
|
||||
logger *logrus.Logger
|
||||
driverRoot string
|
||||
logger logger.Interface
|
||||
devRoot string
|
||||
deviceMajors devices.Devices
|
||||
migCaps nvcaps.MigCaps
|
||||
}
|
||||
|
||||
// newAllPossible returns a new allPossible device node lister.
|
||||
// This lister lists all possible device nodes for NVIDIA GPUs, control devices, and capability devices.
|
||||
func newAllPossible(logger *logrus.Logger, driverRoot string) (nodeLister, error) {
|
||||
func newAllPossible(logger logger.Interface, devRoot string) (nodeLister, error) {
|
||||
deviceMajors, err := devices.GetNVIDIADevices()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed reading device majors: %v", err)
|
||||
}
|
||||
|
||||
var requiredMajors []devices.Name
|
||||
migCaps, err := nvcaps.NewMigCaps()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read MIG caps: %v", err)
|
||||
}
|
||||
if migCaps == nil {
|
||||
migCaps = make(nvcaps.MigCaps)
|
||||
} else {
|
||||
requiredMajors = append(requiredMajors, devices.NVIDIACaps)
|
||||
}
|
||||
|
||||
requiredMajors = append(requiredMajors, devices.NVIDIAGPU, devices.NVIDIAUVM)
|
||||
for _, name := range requiredMajors {
|
||||
if !deviceMajors.Exists(name) {
|
||||
return nil, fmt.Errorf("missing required device major %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
l := allPossible{
|
||||
logger: logger,
|
||||
driverRoot: driverRoot,
|
||||
devRoot: devRoot,
|
||||
deviceMajors: deviceMajors,
|
||||
migCaps: migCaps,
|
||||
}
|
||||
@@ -60,8 +71,8 @@ func newAllPossible(logger *logrus.Logger, driverRoot string) (nodeLister, error
|
||||
|
||||
// DeviceNodes returns a list of all possible device nodes for NVIDIA GPUs, control devices, and capability devices.
|
||||
func (m allPossible) DeviceNodes() ([]deviceNode, error) {
|
||||
gpus, err := nvpci.NewFrom(
|
||||
filepath.Join(m.driverRoot, nvpci.PCIDevicesRoot),
|
||||
gpus, err := nvpci.New(
|
||||
nvpci.WithPCIDevicesRoot(filepath.Join(m.devRoot, nvpci.PCIDevicesRoot)),
|
||||
).GetGPUs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get GPU information: %v", err)
|
||||
@@ -69,7 +80,7 @@ func (m allPossible) DeviceNodes() ([]deviceNode, error) {
|
||||
|
||||
count := len(gpus)
|
||||
if count == 0 {
|
||||
m.logger.Infof("No NVIDIA devices found in %s", m.driverRoot)
|
||||
m.logger.Infof("No NVIDIA devices found in %s", m.devRoot)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -168,7 +179,7 @@ func (m allPossible) newDeviceNode(deviceName devices.Name, path string, minor i
|
||||
major, _ := m.deviceMajors.Get(deviceName)
|
||||
|
||||
return deviceNode{
|
||||
path: filepath.Join(m.driverRoot, path),
|
||||
path: filepath.Join(m.devRoot, path),
|
||||
major: uint32(major),
|
||||
minor: uint32(minor),
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/system/nvdevices"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/system/nvmodules"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -34,19 +36,21 @@ const (
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type config struct {
|
||||
devCharPath string
|
||||
driverRoot string
|
||||
dryRun bool
|
||||
watch bool
|
||||
createAll bool
|
||||
devCharPath string
|
||||
driverRoot string
|
||||
dryRun bool
|
||||
watch bool
|
||||
createAll bool
|
||||
createDeviceNodes bool
|
||||
loadKernelModules bool
|
||||
}
|
||||
|
||||
// NewCommand constructs a command sub-command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -97,6 +101,18 @@ func (m command) build() *cli.Command {
|
||||
Destination: &cfg.createAll,
|
||||
EnvVars: []string{"CREATE_ALL"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "load-kernel-modules",
|
||||
Usage: "Load the NVIDIA kernel modules before creating symlinks. This is only applicable when --create-all is set.",
|
||||
Destination: &cfg.loadKernelModules,
|
||||
EnvVars: []string{"LOAD_KERNEL_MODULES"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "create-device-nodes",
|
||||
Usage: "Create the NVIDIA control device nodes in the driver root if they do not exist. This is only applicable when --create-all is set",
|
||||
Destination: &cfg.createDeviceNodes,
|
||||
EnvVars: []string{"CREATE_DEVICE_NODES"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "dry-run",
|
||||
Usage: "If set, the command will not create any symlinks.",
|
||||
@@ -114,6 +130,16 @@ func (m command) validateFlags(r *cli.Context, cfg *config) error {
|
||||
return fmt.Errorf("create-all and watch are mutually exclusive")
|
||||
}
|
||||
|
||||
if cfg.loadKernelModules && !cfg.createAll {
|
||||
m.logger.Warning("load-kernel-modules is only applicable when create-all is set; ignoring")
|
||||
cfg.loadKernelModules = false
|
||||
}
|
||||
|
||||
if cfg.createDeviceNodes && !cfg.createAll {
|
||||
m.logger.Warning("create-device-nodes is only applicable when create-all is set; ignoring")
|
||||
cfg.createDeviceNodes = false
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -137,6 +163,8 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
||||
WithDriverRoot(cfg.driverRoot),
|
||||
WithDryRun(cfg.dryRun),
|
||||
WithCreateAll(cfg.createAll),
|
||||
WithLoadKernelModules(cfg.loadKernelModules),
|
||||
WithCreateDeviceNodes(cfg.createDeviceNodes),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create symlink creator: %v", err)
|
||||
@@ -186,12 +214,15 @@ create:
|
||||
}
|
||||
|
||||
type linkCreator struct {
|
||||
logger *logrus.Logger
|
||||
lister nodeLister
|
||||
driverRoot string
|
||||
devCharPath string
|
||||
dryRun bool
|
||||
createAll bool
|
||||
logger logger.Interface
|
||||
lister nodeLister
|
||||
driverRoot string
|
||||
devRoot string
|
||||
devCharPath string
|
||||
dryRun bool
|
||||
createAll bool
|
||||
createDeviceNodes bool
|
||||
loadKernelModules bool
|
||||
}
|
||||
|
||||
// Creator is an interface for creating symlinks to /dev/nv* devices in /dev/char.
|
||||
@@ -209,34 +240,81 @@ func NewSymlinkCreator(opts ...Option) (Creator, error) {
|
||||
opt(&c)
|
||||
}
|
||||
if c.logger == nil {
|
||||
c.logger = logrus.StandardLogger()
|
||||
c.logger = logger.New()
|
||||
}
|
||||
if c.driverRoot == "" {
|
||||
c.driverRoot = "/"
|
||||
}
|
||||
if c.devRoot == "" {
|
||||
c.devRoot = "/"
|
||||
}
|
||||
if c.devCharPath == "" {
|
||||
c.devCharPath = defaultDevCharPath
|
||||
}
|
||||
|
||||
if err := c.setup(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.createAll {
|
||||
lister, err := newAllPossible(c.logger, c.driverRoot)
|
||||
lister, err := newAllPossible(c.logger, c.devRoot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create all possible device lister: %v", err)
|
||||
}
|
||||
c.lister = lister
|
||||
} else {
|
||||
c.lister = existing{c.logger, c.driverRoot}
|
||||
c.lister = existing{c.logger, c.devRoot}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (m linkCreator) setup() error {
|
||||
if !m.loadKernelModules && !m.createDeviceNodes {
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.loadKernelModules {
|
||||
modules := nvmodules.New(
|
||||
nvmodules.WithLogger(m.logger),
|
||||
nvmodules.WithDryRun(m.dryRun),
|
||||
nvmodules.WithRoot(m.driverRoot),
|
||||
)
|
||||
if err := modules.LoadAll(); err != nil {
|
||||
return fmt.Errorf("failed to load NVIDIA kernel modules: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if m.createDeviceNodes {
|
||||
devices, err := nvdevices.New(
|
||||
nvdevices.WithLogger(m.logger),
|
||||
nvdevices.WithDryRun(m.dryRun),
|
||||
nvdevices.WithDevRoot(m.devRoot),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := devices.CreateNVIDIAControlDevices(); err != nil {
|
||||
return fmt.Errorf("failed to create NVIDIA device nodes: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithDriverRoot sets the driver root path.
|
||||
// This is the path in which kernel modules must be loaded.
|
||||
func WithDriverRoot(root string) Option {
|
||||
return func(c *linkCreator) {
|
||||
c.driverRoot = root
|
||||
}
|
||||
}
|
||||
|
||||
// WithDevRoot sets the root path for the /dev directory.
|
||||
func WithDevRoot(root string) Option {
|
||||
return func(c *linkCreator) {
|
||||
c.devRoot = root
|
||||
}
|
||||
}
|
||||
|
||||
// WithDevCharPath sets the path at which the symlinks will be created.
|
||||
func WithDevCharPath(path string) Option {
|
||||
return func(c *linkCreator) {
|
||||
@@ -252,7 +330,7 @@ func WithDryRun(dryRun bool) Option {
|
||||
}
|
||||
|
||||
// WithLogger sets the logger.
|
||||
func WithLogger(logger *logrus.Logger) Option {
|
||||
func WithLogger(logger logger.Interface) Option {
|
||||
return func(c *linkCreator) {
|
||||
c.logger = logger
|
||||
}
|
||||
@@ -265,6 +343,20 @@ func WithCreateAll(createAll bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithLoadKernelModules sets the loadKernelModules flag for the linkCreator.
|
||||
func WithLoadKernelModules(loadKernelModules bool) Option {
|
||||
return func(lc *linkCreator) {
|
||||
lc.loadKernelModules = loadKernelModules
|
||||
}
|
||||
}
|
||||
|
||||
// WithCreateDeviceNodes sets the createDeviceNodes flag for the linkCreator.
|
||||
func WithCreateDeviceNodes(createDeviceNodes bool) Option {
|
||||
return func(lc *linkCreator) {
|
||||
lc.createDeviceNodes = createDeviceNodes
|
||||
}
|
||||
}
|
||||
|
||||
// CreateLinks creates symlinks for all NVIDIA device nodes found in the driver root.
|
||||
func (m linkCreator) CreateLinks() error {
|
||||
deviceNodes, err := m.lister.DeviceNodes()
|
||||
@@ -290,7 +382,7 @@ func (m linkCreator) CreateLinks() error {
|
||||
|
||||
err = os.Symlink(target, linkPath)
|
||||
if err != nil {
|
||||
m.logger.Warnf("Could not create symlink: %v", err)
|
||||
m.logger.Warningf("Could not create symlink: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -30,8 +30,8 @@ type nodeLister interface {
|
||||
}
|
||||
|
||||
type existing struct {
|
||||
logger *logrus.Logger
|
||||
driverRoot string
|
||||
logger logger.Interface
|
||||
devRoot string
|
||||
}
|
||||
|
||||
// DeviceNodes returns a list of NVIDIA device nodes in the specified root.
|
||||
@@ -39,22 +39,22 @@ type existing struct {
|
||||
func (m existing) DeviceNodes() ([]deviceNode, error) {
|
||||
locator := lookup.NewCharDeviceLocator(
|
||||
lookup.WithLogger(m.logger),
|
||||
lookup.WithRoot(m.driverRoot),
|
||||
lookup.WithRoot(m.devRoot),
|
||||
lookup.WithOptional(true),
|
||||
)
|
||||
|
||||
devices, err := locator.Locate("/dev/nvidia*")
|
||||
if err != nil {
|
||||
m.logger.Warnf("Error while locating device: %v", err)
|
||||
m.logger.Warningf("Error while locating device: %v", err)
|
||||
}
|
||||
|
||||
capDevices, err := locator.Locate("/dev/nvidia-caps/nvidia-*")
|
||||
if err != nil {
|
||||
m.logger.Warnf("Error while locating caps device: %v", err)
|
||||
m.logger.Warningf("Error while locating caps device: %v", err)
|
||||
}
|
||||
|
||||
if len(devices) == 0 && len(capDevices) == 0 {
|
||||
m.logger.Infof("No NVIDIA devices found in %s", m.driverRoot)
|
||||
m.logger.Infof("No NVIDIA devices found in %s", m.devRoot)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (m existing) DeviceNodes() ([]deviceNode, error) {
|
||||
var stat unix.Stat_t
|
||||
err := unix.Stat(d, &stat)
|
||||
if err != nil {
|
||||
m.logger.Warnf("Could not stat device: %v", err)
|
||||
m.logger.Warningf("Could not stat device: %v", err)
|
||||
continue
|
||||
}
|
||||
deviceNode := deviceNode{
|
||||
|
||||
@@ -19,13 +19,14 @@ package createdevicenodes
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/system"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/system/nvdevices"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/system/nvmodules"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type options struct {
|
||||
@@ -34,10 +35,12 @@ type options struct {
|
||||
dryRun bool
|
||||
|
||||
control bool
|
||||
|
||||
loadKernelModules bool
|
||||
}
|
||||
|
||||
// NewCommand constructs a command sub-command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -50,7 +53,7 @@ func (m command) build() *cli.Command {
|
||||
|
||||
c := cli.Command{
|
||||
Name: "create-device-nodes",
|
||||
Usage: "A utility to create NVIDIA device ndoes",
|
||||
Usage: "A utility to create NVIDIA device nodes",
|
||||
Before: func(c *cli.Context) error {
|
||||
return m.validateFlags(c, &opts)
|
||||
},
|
||||
@@ -72,6 +75,11 @@ func (m command) build() *cli.Command {
|
||||
Usage: "create all control device nodes: nvidiactl, nvidia-modeset, nvidia-uvm, nvidia-uvm-tools",
|
||||
Destination: &opts.control,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "load-kernel-modules",
|
||||
Usage: "load the NVIDIA Kernel Modules before creating devices nodes",
|
||||
Destination: &opts.loadKernelModules,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "dry-run",
|
||||
Usage: "if set, the command will not create any symlinks.",
|
||||
@@ -89,18 +97,29 @@ func (m command) validateFlags(r *cli.Context, opts *options) error {
|
||||
}
|
||||
|
||||
func (m command) run(c *cli.Context, opts *options) error {
|
||||
s, err := system.New(
|
||||
system.WithLogger(m.logger),
|
||||
system.WithDryRun(opts.dryRun),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create library: %v", err)
|
||||
if opts.loadKernelModules {
|
||||
modules := nvmodules.New(
|
||||
nvmodules.WithLogger(m.logger),
|
||||
nvmodules.WithDryRun(opts.dryRun),
|
||||
nvmodules.WithRoot(opts.driverRoot),
|
||||
)
|
||||
if err := modules.LoadAll(); err != nil {
|
||||
return fmt.Errorf("failed to load NVIDIA kernel modules: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if opts.control {
|
||||
devices, err := nvdevices.New(
|
||||
nvdevices.WithLogger(m.logger),
|
||||
nvdevices.WithDryRun(opts.dryRun),
|
||||
nvdevices.WithDevRoot(opts.driverRoot),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.logger.Infof("Creating control device nodes at %s", opts.driverRoot)
|
||||
if err := s.CreateNVIDIAControlDeviceNodesAt(opts.driverRoot); err != nil {
|
||||
return fmt.Errorf("failed to create control device nodes: %v", err)
|
||||
if err := devices.CreateNVIDIAControlDevices(); err != nil {
|
||||
return fmt.Errorf("failed to create NVIDIA control device nodes: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
101
cmd/nvidia-ctk/system/print-ldcache/print-ldcache.go
Normal file
101
cmd/nvidia-ctk/system/print-ldcache/print-ldcache.go
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package createdevicenodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
type options struct {
|
||||
driverRoot string
|
||||
}
|
||||
|
||||
// NewCommand constructs a command sub-command with the specified logger
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
return c.build()
|
||||
}
|
||||
|
||||
// build
|
||||
func (m command) build() *cli.Command {
|
||||
opts := options{}
|
||||
|
||||
c := cli.Command{
|
||||
Name: "print-ldcache",
|
||||
Usage: "A utility to print the contents of the ldcache",
|
||||
Before: func(c *cli.Context) error {
|
||||
return m.validateFlags(c, &opts)
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return m.run(c, &opts)
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "driver-root",
|
||||
Usage: "the path to the driver root. Device nodes will be created at `DRIVER_ROOT`/dev",
|
||||
Value: "/",
|
||||
Destination: &opts.driverRoot,
|
||||
EnvVars: []string{"DRIVER_ROOT"},
|
||||
},
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func (m command) validateFlags(r *cli.Context, opts *options) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m command) run(c *cli.Context, opts *options) error {
|
||||
cache, err := ldcache.New(m.logger, opts.driverRoot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create ldcache: %v", err)
|
||||
}
|
||||
|
||||
lib32, lib64 := cache.List()
|
||||
|
||||
if len(lib32) == 0 {
|
||||
m.logger.Info("No 32-bit libraries found")
|
||||
} else {
|
||||
m.logger.Infof("%d 32-bit libraries found", len(lib32))
|
||||
for _, lib := range lib32 {
|
||||
m.logger.Infof("%v", lib)
|
||||
}
|
||||
}
|
||||
if len(lib64) == 0 {
|
||||
m.logger.Info("No 64-bit libraries found")
|
||||
} else {
|
||||
m.logger.Infof("%d 64-bit libraries found", len(lib64))
|
||||
for _, lib := range lib64 {
|
||||
m.logger.Infof("%v", lib)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -19,16 +19,17 @@ package system
|
||||
import (
|
||||
devchar "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/system/create-dev-char-symlinks"
|
||||
devicenodes "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/system/create-device-nodes"
|
||||
"github.com/sirupsen/logrus"
|
||||
ldcache "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/system/print-ldcache"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewCommand constructs a runtime command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
func NewCommand(logger logger.Interface) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
@@ -45,6 +46,7 @@ func (m command) build() *cli.Command {
|
||||
system.Subcommands = []*cli.Command{
|
||||
devchar.NewCommand(m.logger),
|
||||
devicenodes.NewCommand(m.logger),
|
||||
ldcache.NewCommand(m.logger),
|
||||
}
|
||||
|
||||
return &system
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
disable-require = false
|
||||
#swarm-resource = "DOCKER_RESOURCE_GPU"
|
||||
#accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||
#accept-nvidia-visible-devices-as-volume-mounts = false
|
||||
|
||||
[nvidia-container-cli]
|
||||
#root = "/run/nvidia/driver"
|
||||
#path = "/usr/bin/nvidia-container-cli"
|
||||
environment = []
|
||||
#debug = "/var/log/nvidia-container-toolkit.log"
|
||||
#ldcache = "/etc/ld.so.cache"
|
||||
load-kmods = true
|
||||
#no-cgroups = false
|
||||
#user = "root:video"
|
||||
ldconfig = "@/sbin/ldconfig"
|
||||
|
||||
[nvidia-container-runtime]
|
||||
#debug = "/var/log/nvidia-container-runtime.log"
|
||||
log-level = "info"
|
||||
|
||||
# Specify the runtimes to consider. This list is processed in order and the PATH
|
||||
# searched for matching executables unless the entry is an absolute path.
|
||||
runtimes = [
|
||||
"docker-runc",
|
||||
"runc",
|
||||
]
|
||||
|
||||
mode = "auto"
|
||||
|
||||
[nvidia-container-runtime.modes.csv]
|
||||
|
||||
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||
@@ -1,32 +0,0 @@
|
||||
disable-require = false
|
||||
#swarm-resource = "DOCKER_RESOURCE_GPU"
|
||||
#accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||
#accept-nvidia-visible-devices-as-volume-mounts = false
|
||||
|
||||
[nvidia-container-cli]
|
||||
#root = "/run/nvidia/driver"
|
||||
#path = "/usr/bin/nvidia-container-cli"
|
||||
environment = []
|
||||
#debug = "/var/log/nvidia-container-toolkit.log"
|
||||
#ldcache = "/etc/ld.so.cache"
|
||||
load-kmods = true
|
||||
#no-cgroups = false
|
||||
user = "root:video"
|
||||
ldconfig = "@/sbin/ldconfig"
|
||||
|
||||
[nvidia-container-runtime]
|
||||
#debug = "/var/log/nvidia-container-runtime.log"
|
||||
log-level = "info"
|
||||
|
||||
# Specify the runtimes to consider. This list is processed in order and the PATH
|
||||
# searched for matching executables unless the entry is an absolute path.
|
||||
runtimes = [
|
||||
"docker-runc",
|
||||
"runc",
|
||||
]
|
||||
|
||||
mode = "auto"
|
||||
|
||||
[nvidia-container-runtime.modes.csv]
|
||||
|
||||
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||
@@ -1,32 +0,0 @@
|
||||
disable-require = false
|
||||
#swarm-resource = "DOCKER_RESOURCE_GPU"
|
||||
#accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||
#accept-nvidia-visible-devices-as-volume-mounts = false
|
||||
|
||||
[nvidia-container-cli]
|
||||
#root = "/run/nvidia/driver"
|
||||
#path = "/usr/bin/nvidia-container-cli"
|
||||
environment = []
|
||||
#debug = "/var/log/nvidia-container-toolkit.log"
|
||||
#ldcache = "/etc/ld.so.cache"
|
||||
load-kmods = true
|
||||
#no-cgroups = false
|
||||
#user = "root:video"
|
||||
ldconfig = "@/sbin/ldconfig"
|
||||
|
||||
[nvidia-container-runtime]
|
||||
#debug = "/var/log/nvidia-container-runtime.log"
|
||||
log-level = "info"
|
||||
|
||||
# Specify the runtimes to consider. This list is processed in order and the PATH
|
||||
# searched for matching executables unless the entry is an absolute path.
|
||||
runtimes = [
|
||||
"docker-runc",
|
||||
"runc",
|
||||
]
|
||||
|
||||
mode = "auto"
|
||||
|
||||
[nvidia-container-runtime.modes.csv]
|
||||
|
||||
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||
@@ -1,32 +0,0 @@
|
||||
disable-require = false
|
||||
#swarm-resource = "DOCKER_RESOURCE_GPU"
|
||||
#accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||
#accept-nvidia-visible-devices-as-volume-mounts = false
|
||||
|
||||
[nvidia-container-cli]
|
||||
#root = "/run/nvidia/driver"
|
||||
#path = "/usr/bin/nvidia-container-cli"
|
||||
environment = []
|
||||
#debug = "/var/log/nvidia-container-toolkit.log"
|
||||
#ldcache = "/etc/ld.so.cache"
|
||||
load-kmods = true
|
||||
#no-cgroups = false
|
||||
#user = "root:video"
|
||||
ldconfig = "@/sbin/ldconfig.real"
|
||||
|
||||
[nvidia-container-runtime]
|
||||
#debug = "/var/log/nvidia-container-runtime.log"
|
||||
log-level = "info"
|
||||
|
||||
# Specify the runtimes to consider. This list is processed in order and the PATH
|
||||
# searched for matching executables unless the entry is an absolute path.
|
||||
runtimes = [
|
||||
"docker-runc",
|
||||
"runc",
|
||||
]
|
||||
|
||||
mode = "auto"
|
||||
|
||||
[nvidia-container-runtime.modes.csv]
|
||||
|
||||
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||
@@ -53,15 +53,6 @@ ARG GIT_COMMIT
|
||||
ENV GIT_COMMIT ${GIT_COMMIT}
|
||||
RUN make PREFIX=${DIST_DIR} cmds
|
||||
|
||||
ARG CONFIG_TOML_SUFFIX
|
||||
ENV CONFIG_TOML_SUFFIX ${CONFIG_TOML_SUFFIX}
|
||||
COPY config/config.toml.${CONFIG_TOML_SUFFIX} $DIST_DIR/config.toml
|
||||
|
||||
# Debian Jessie still had ldconfig.real
|
||||
RUN if [ "$(lsb_release -cs)" = "jessie" ]; then \
|
||||
sed -i 's;"@/sbin/ldconfig";"@/sbin/ldconfig.real";' $DIST_DIR/config.toml; \
|
||||
fi
|
||||
|
||||
WORKDIR $DIST_DIR
|
||||
COPY packaging/debian ./debian
|
||||
|
||||
|
||||
@@ -50,10 +50,6 @@ COPY oci-nvidia-hook $DIST_DIR/oci-nvidia-hook
|
||||
# Hook for libpod/CRI-O: https://github.com/containers/libpod/blob/v0.8.5/pkg/hooks/docs/oci-hooks.5.md
|
||||
COPY oci-nvidia-hook.json $DIST_DIR/oci-nvidia-hook.json
|
||||
|
||||
ARG CONFIG_TOML_SUFFIX
|
||||
ENV CONFIG_TOML_SUFFIX ${CONFIG_TOML_SUFFIX}
|
||||
COPY config/config.toml.${CONFIG_TOML_SUFFIX} $DIST_DIR/config.toml
|
||||
|
||||
WORKDIR $DIST_DIR/..
|
||||
COPY packaging/rpm .
|
||||
|
||||
|
||||
@@ -62,10 +62,6 @@ ARG GIT_COMMIT
|
||||
ENV GIT_COMMIT ${GIT_COMMIT}
|
||||
RUN make PREFIX=${DIST_DIR} cmds
|
||||
|
||||
ARG CONFIG_TOML_SUFFIX
|
||||
ENV CONFIG_TOML_SUFFIX ${CONFIG_TOML_SUFFIX}
|
||||
COPY config/config.toml.${CONFIG_TOML_SUFFIX} $DIST_DIR/config.toml
|
||||
|
||||
# Hook for Project Atomic's fork of Docker: https://github.com/projectatomic/docker/tree/docker-1.13.1-rhel#add-dockerhooks-exec-custom-hooks-for-prestartpoststop-containerspatch
|
||||
COPY oci-nvidia-hook $DIST_DIR/oci-nvidia-hook
|
||||
|
||||
|
||||
@@ -51,10 +51,6 @@ ARG GIT_COMMIT
|
||||
ENV GIT_COMMIT ${GIT_COMMIT}
|
||||
RUN make PREFIX=${DIST_DIR} cmds
|
||||
|
||||
ARG CONFIG_TOML_SUFFIX
|
||||
ENV CONFIG_TOML_SUFFIX ${CONFIG_TOML_SUFFIX}
|
||||
COPY config/config.toml.${CONFIG_TOML_SUFFIX} $DIST_DIR/config.toml
|
||||
|
||||
WORKDIR $DIST_DIR
|
||||
COPY packaging/debian ./debian
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ AMD64_TARGETS := ubuntu20.04 ubuntu18.04 ubuntu16.04 debian10 debian9
|
||||
X86_64_TARGETS := centos7 centos8 rhel7 rhel8 amazonlinux2 opensuse-leap15.1
|
||||
PPC64LE_TARGETS := ubuntu18.04 ubuntu16.04 centos7 centos8 rhel7 rhel8
|
||||
ARM64_TARGETS := ubuntu20.04 ubuntu18.04
|
||||
AARCH64_TARGETS := centos8 rhel8 amazonlinux2
|
||||
AARCH64_TARGETS := centos7 centos8 rhel8 amazonlinux2
|
||||
|
||||
# Define top-level build targets
|
||||
docker%: SHELL:=/bin/bash
|
||||
@@ -99,13 +99,11 @@ LIBNVIDIA_CONTAINER_TOOLS_VERSION := $(LIBNVIDIA_CONTAINER_VERSION)$(if $(LIBNVI
|
||||
# private centos target
|
||||
--centos%: OS := centos
|
||||
--centos%: DOCKERFILE = $(CURDIR)/docker/Dockerfile.rpm-yum
|
||||
--centos%: CONFIG_TOML_SUFFIX := rpm-yum
|
||||
--centos8%: BASEIMAGE = quay.io/centos/centos:stream8
|
||||
|
||||
# private amazonlinux target
|
||||
--amazonlinux%: OS := amazonlinux
|
||||
--amazonlinux%: DOCKERFILE = $(CURDIR)/docker/Dockerfile.rpm-yum
|
||||
--amazonlinux%: CONFIG_TOML_SUFFIX := rpm-yum
|
||||
|
||||
# private opensuse-leap target
|
||||
--opensuse-leap%: OS = opensuse-leap
|
||||
@@ -116,13 +114,9 @@ LIBNVIDIA_CONTAINER_TOOLS_VERSION := $(LIBNVIDIA_CONTAINER_VERSION)$(if $(LIBNVI
|
||||
--rhel%: VERSION = $(patsubst rhel%-$(ARCH),%,$(TARGET_PLATFORM))
|
||||
--rhel%: ARTIFACTS_DIR = $(DIST_DIR)/rhel$(VERSION)/$(ARCH)
|
||||
--rhel%: DOCKERFILE = $(CURDIR)/docker/Dockerfile.rpm-yum
|
||||
--rhel%: CONFIG_TOML_SUFFIX := rpm-yum
|
||||
--rhel8%: BASEIMAGE = quay.io/centos/centos:stream8
|
||||
|
||||
|
||||
# We allow the CONFIG_TOML_SUFFIX to be overridden.
|
||||
CONFIG_TOML_SUFFIX ?= $(OS)
|
||||
|
||||
docker-build-%:
|
||||
@echo "Building for $(TARGET_PLATFORM)"
|
||||
docker pull --platform=linux/$(ARCH) $(BASEIMAGE)
|
||||
@@ -136,7 +130,6 @@ docker-build-%:
|
||||
--build-arg PKG_VERS="$(PACKAGE_VERSION)" \
|
||||
--build-arg PKG_REV="$(PACKAGE_REVISION)" \
|
||||
--build-arg LIBNVIDIA_CONTAINER_TOOLS_VERSION="$(LIBNVIDIA_CONTAINER_TOOLS_VERSION)" \
|
||||
--build-arg CONFIG_TOML_SUFFIX="$(CONFIG_TOML_SUFFIX)" \
|
||||
--build-arg GIT_COMMIT="$(GIT_COMMIT)" \
|
||||
--tag $(BUILDIMAGE) \
|
||||
--file $(DOCKERFILE) .
|
||||
|
||||
24
go.mod
24
go.mod
@@ -1,31 +1,30 @@
|
||||
module github.com/NVIDIA/nvidia-container-toolkit
|
||||
|
||||
go 1.18
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.0.0
|
||||
github.com/NVIDIA/go-nvml v0.12.0-0
|
||||
github.com/BurntSushi/toml v1.2.1
|
||||
github.com/NVIDIA/go-nvml v0.12.0-1
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.4-0.20230111111500-5b3b5d81179a
|
||||
github.com/fsnotify/fsnotify v1.5.4
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb
|
||||
github.com/opencontainers/runtime-spec v1.1.0-rc.2
|
||||
github.com/pelletier/go-toml v1.9.4
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230209143738-95328d8c4438
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230613182322-7663cf900f0a
|
||||
golang.org/x/mod v0.5.0
|
||||
golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
golang.org/x/sys v0.7.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/opencontainers/runc v1.1.4 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/opencontainers/runc v1.1.6 // indirect
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect
|
||||
github.com/opencontainers/selinux v1.10.1 // indirect
|
||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||
@@ -33,4 +32,5 @@ require (
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
81
go.sum
81
go.sum
@@ -1,86 +1,75 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
|
||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/NVIDIA/go-nvml v0.11.6-0.0.20220823120812-7e2082095e82 h1:x751Xx1tdxkiA/sdkv2J769n21UbYKzVOpe9S/h1M3k=
|
||||
github.com/NVIDIA/go-nvml v0.11.6-0.0.20220823120812-7e2082095e82/go.mod h1:hy7HYeQy335x6nEss0Ne3PYqleRa6Ct+VKD9RQ4nyFs=
|
||||
github.com/NVIDIA/go-nvml v0.12.0-0 h1:eHYNHbzAsMgWYshf6dEmTY66/GCXnORJFnzm3TNH4mc=
|
||||
github.com/NVIDIA/go-nvml v0.12.0-0/go.mod h1:hy7HYeQy335x6nEss0Ne3PYqleRa6Ct+VKD9RQ4nyFs=
|
||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/NVIDIA/go-nvml v0.12.0-1 h1:6mdjtlFo+17dWL7VFPfuRMtf0061TF4DKls9pkSw6uM=
|
||||
github.com/NVIDIA/go-nvml v0.12.0-1/go.mod h1:hy7HYeQy335x6nEss0Ne3PYqleRa6Ct+VKD9RQ4nyFs=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.4-0.20230111111500-5b3b5d81179a h1:sP3PcgyIkRlHqfF3Jfpe/7G8kf/qpzG4C8r94y9hLbE=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.4-0.20230111111500-5b3b5d81179a/go.mod h1:xMRa4fJgXzSDFUCURSimOUgoSc+odohvO3uXT9xjqH0=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs=
|
||||
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
|
||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||
github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg=
|
||||
github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb h1:1xSVPOd7/UA+39/hXEGnBJ13p6JFB0E1EvQFlrRDOXI=
|
||||
github.com/opencontainers/runc v1.1.6 h1:XbhB8IfG/EsnhNvZtNdLB0GBw92GYEFvKlhaJk9jUgA=
|
||||
github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.1.0-rc.2 h1:ucBtEms2tamYYW/SvGpvq9yUN0NEVL6oyLEwDcTSrk8=
|
||||
github.com/opencontainers/runtime-spec v1.1.0-rc.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI=
|
||||
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opencontainers/selinux v1.10.1 h1:09LIPVRP3uuZGQvgR+SgMSNBd1Eb3vlRbGqQpoHsF8w=
|
||||
github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
||||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@@ -88,35 +77,19 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230119114711-6fe07bb33342 h1:083n9fJt2dWOpJd/X/q9Xgl5XtQLL22uSFYbzVqJssg=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230119114711-6fe07bb33342/go.mod h1:GStidGxhaqJhYFW1YpOnLvYCbL2EsM0od7IW4u7+JgU=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230209143738-95328d8c4438 h1:+qRai7XRl8omFQVCeHcaWzL542Yw64vfmuXG+79ZCIc=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230209143738-95328d8c4438/go.mod h1:GStidGxhaqJhYFW1YpOnLvYCbL2EsM0od7IW4u7+JgU=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230613182322-7663cf900f0a h1:lceJVurLqiWFdxK6KMDw+SIwrAsFW/af44XrNlbGw78=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20230613182322-7663cf900f0a/go.mod h1:KYZksBgh18o+uzgnpDazzG4LVYtnfB96VXHMXypEtik=
|
||||
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6 h1:cy1ko5847T/lJ45eyg/7uLprIE/amW5IXxGtEnQdYMI=
|
||||
golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
||||
@@ -16,33 +16,7 @@
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
// ContainerCLIConfig stores the options for the nvidia-container-cli
|
||||
type ContainerCLIConfig struct {
|
||||
Root string
|
||||
}
|
||||
|
||||
// getContainerCLIConfigFrom reads the nvidia container runtime config from the specified toml Tree.
|
||||
func getContainerCLIConfigFrom(toml *toml.Tree) *ContainerCLIConfig {
|
||||
cfg := getDefaultContainerCLIConfig()
|
||||
|
||||
if toml == nil {
|
||||
return cfg
|
||||
}
|
||||
|
||||
cfg.Root = toml.GetDefault("nvidia-container-cli.root", cfg.Root).(string)
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
// getDefaultContainerCLIConfig defines the default values for the config
|
||||
func getDefaultContainerCLIConfig() *ContainerCLIConfig {
|
||||
c := ContainerCLIConfig{
|
||||
Root: "",
|
||||
}
|
||||
|
||||
return &c
|
||||
Root string `toml:"root"`
|
||||
}
|
||||
|
||||
@@ -17,17 +17,29 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
const (
|
||||
configOverride = "XDG_CONFIG_HOME"
|
||||
configFilePath = "nvidia-container-runtime/config.toml"
|
||||
|
||||
nvidiaCTKExecutable = "nvidia-ctk"
|
||||
nvidiaCTKDefaultFilePath = "/usr/bin/nvidia-ctk"
|
||||
|
||||
nvidiaContainerRuntimeHookExecutable = "nvidia-container-runtime-hook"
|
||||
nvidiaContainerRuntimeHookDefaultPath = "/usr/bin/nvidia-container-runtime-hook"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -64,7 +76,7 @@ func GetConfig() (*Config, error) {
|
||||
|
||||
tomlFile, err := os.Open(configFilePath)
|
||||
if err != nil {
|
||||
return getDefaultConfig(), nil
|
||||
return getDefaultConfig()
|
||||
}
|
||||
defer tomlFile.Close()
|
||||
|
||||
@@ -88,39 +100,198 @@ func loadConfigFrom(reader io.Reader) (*Config, error) {
|
||||
|
||||
// getConfigFrom reads the nvidia container runtime config from the specified toml Tree.
|
||||
func getConfigFrom(toml *toml.Tree) (*Config, error) {
|
||||
cfg := getDefaultConfig()
|
||||
|
||||
if toml == nil {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
cfg.AcceptEnvvarUnprivileged = toml.GetDefault("accept-nvidia-visible-devices-envvar-when-unprivileged", cfg.AcceptEnvvarUnprivileged).(bool)
|
||||
|
||||
cfg.NVIDIAContainerCLIConfig = *getContainerCLIConfigFrom(toml)
|
||||
cfg.NVIDIACTKConfig = *getCTKConfigFrom(toml)
|
||||
runtimeConfig, err := getRuntimeConfigFrom(toml)
|
||||
cfg, err := getDefaultConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load nvidia-container-runtime config: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
cfg.NVIDIAContainerRuntimeConfig = *runtimeConfig
|
||||
|
||||
runtimeHookConfig, err := getRuntimeHookConfigFrom(toml)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load nvidia-container-runtime-hook config: %v", err)
|
||||
if err := toml.Unmarshal(cfg); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config: %v", err)
|
||||
}
|
||||
cfg.NVIDIAContainerRuntimeHookConfig = *runtimeHookConfig
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// getDefaultConfig defines the default values for the config
|
||||
func getDefaultConfig() *Config {
|
||||
c := Config{
|
||||
AcceptEnvvarUnprivileged: true,
|
||||
NVIDIAContainerCLIConfig: *getDefaultContainerCLIConfig(),
|
||||
NVIDIACTKConfig: *getDefaultCTKConfig(),
|
||||
NVIDIAContainerRuntimeConfig: *GetDefaultRuntimeConfig(),
|
||||
func getDefaultConfig() (*Config, error) {
|
||||
tomlConfig, err := GetDefaultConfigToml()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &c
|
||||
// tomlConfig above includes information about the default values and comments.
|
||||
// we need to marshal it back to a string and then unmarshal it to strip the comments.
|
||||
contents, err := tomlConfig.ToTomlString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reloaded, err := toml.Load(contents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := Config{}
|
||||
if err := reloaded.Unmarshal(&d); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config: %v", err)
|
||||
}
|
||||
|
||||
// The default value for the accept-nvidia-visible-devices-envvar-when-unprivileged is non-standard.
|
||||
// As such we explicitly handle it being set here.
|
||||
if reloaded.Get("accept-nvidia-visible-devices-envvar-when-unprivileged") == nil {
|
||||
d.AcceptEnvvarUnprivileged = true
|
||||
}
|
||||
// The default value for the nvidia-container-runtime.debug is non-standard.
|
||||
// As such we explicitly handle it being set here.
|
||||
if reloaded.Get("nvidia-container-runtime.debug") == nil {
|
||||
d.NVIDIAContainerRuntimeConfig.DebugFilePath = "/dev/null"
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
// GetDefaultConfigToml returns the default config as a toml Tree.
|
||||
func GetDefaultConfigToml() (*toml.Tree, error) {
|
||||
tree, err := toml.TreeFromMap(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tree.Set("disable-require", false)
|
||||
tree.SetWithComment("swarm-resource", "", true, "DOCKER_RESOURCE_GPU")
|
||||
tree.SetWithComment("accept-nvidia-visible-devices-envvar-when-unprivileged", "", true, true)
|
||||
tree.SetWithComment("accept-nvidia-visible-devices-as-volume-mounts", "", true, false)
|
||||
|
||||
// nvidia-container-cli
|
||||
tree.SetWithComment("nvidia-container-cli.root", "", true, "/run/nvidia/driver")
|
||||
tree.SetWithComment("nvidia-container-cli.path", "", true, "/usr/bin/nvidia-container-cli")
|
||||
tree.Set("nvidia-container-cli.environment", []string{})
|
||||
tree.SetWithComment("nvidia-container-cli.debug", "", true, "/var/log/nvidia-container-toolkit.log")
|
||||
tree.SetWithComment("nvidia-container-cli.ldcache", "", true, "/etc/ld.so.cache")
|
||||
tree.Set("nvidia-container-cli.load-kmods", true)
|
||||
tree.SetWithComment("nvidia-container-cli.no-cgroups", "", true, false)
|
||||
|
||||
tree.SetWithComment("nvidia-container-cli.user", "", getCommentedUserGroup(), getUserGroup())
|
||||
tree.Set("nvidia-container-cli.ldconfig", getLdConfigPath())
|
||||
|
||||
// nvidia-container-runtime
|
||||
tree.SetWithComment("nvidia-container-runtime.debug", "", true, "/var/log/nvidia-container-runtime.log")
|
||||
tree.Set("nvidia-container-runtime.log-level", "info")
|
||||
|
||||
commentLines := []string{
|
||||
"Specify the runtimes to consider. This list is processed in order and the PATH",
|
||||
"searched for matching executables unless the entry is an absolute path.",
|
||||
}
|
||||
tree.SetWithComment("nvidia-container-runtime.runtimes", strings.Join(commentLines, "\n "), false, []string{"docker-runc", "runc"})
|
||||
|
||||
tree.Set("nvidia-container-runtime.mode", "auto")
|
||||
|
||||
tree.Set("nvidia-container-runtime.modes.csv.mount-spec-path", "/etc/nvidia-container-runtime/host-files-for-container.d")
|
||||
tree.Set("nvidia-container-runtime.modes.cdi.default-kind", "nvidia.com/gpu")
|
||||
tree.Set("nvidia-container-runtime.modes.cdi.annotation-prefixes", []string{cdi.AnnotationPrefix})
|
||||
|
||||
// nvidia-ctk
|
||||
tree.Set("nvidia-ctk.path", nvidiaCTKExecutable)
|
||||
|
||||
// nvidia-container-runtime-hook
|
||||
tree.Set("nvidia-container-runtime-hook.path", nvidiaContainerRuntimeHookExecutable)
|
||||
|
||||
return tree, nil
|
||||
}
|
||||
|
||||
func getLdConfigPath() string {
|
||||
if _, err := os.Stat("/sbin/ldconfig.real"); err == nil {
|
||||
return "@/sbin/ldconfig.real"
|
||||
}
|
||||
return "@/sbin/ldconfig"
|
||||
}
|
||||
|
||||
// getUserGroup returns the user and group to use for the nvidia-container-cli and whether the config option should be commented.
|
||||
func getUserGroup() string {
|
||||
return "root:video"
|
||||
}
|
||||
|
||||
// getCommentedUserGroup returns whether the nvidia-container-cli user and group config option should be commented.
|
||||
func getCommentedUserGroup() bool {
|
||||
uncommentIf := map[string]bool{
|
||||
"suse": true,
|
||||
"opensuse": true,
|
||||
}
|
||||
|
||||
idsLike := getDistIDLike()
|
||||
for _, id := range idsLike {
|
||||
if uncommentIf[id] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// getDistIDLike returns the ID_LIKE field from /etc/os-release.
|
||||
func getDistIDLike() []string {
|
||||
releaseFile, err := os.Open("/etc/os-release")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer releaseFile.Close()
|
||||
|
||||
scanner := bufio.NewScanner(releaseFile)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "ID_LIKE=") {
|
||||
value := strings.Trim(strings.TrimPrefix(line, "ID_LIKE="), "\"")
|
||||
return strings.Split(value, " ")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResolveNVIDIACTKPath resolves the path to the nvidia-ctk binary.
|
||||
// This executable is used in hooks and needs to be an absolute path.
|
||||
// If the path is specified as an absolute path, it is used directly
|
||||
// without checking for existence of an executable at that path.
|
||||
func ResolveNVIDIACTKPath(logger logger.Interface, nvidiaCTKPath string) string {
|
||||
return resolveWithDefault(
|
||||
logger,
|
||||
"NVIDIA Container Toolkit CLI",
|
||||
nvidiaCTKPath,
|
||||
nvidiaCTKDefaultFilePath,
|
||||
)
|
||||
}
|
||||
|
||||
// ResolveNVIDIAContainerRuntimeHookPath resolves the path the nvidia-container-runtime-hook binary.
|
||||
func ResolveNVIDIAContainerRuntimeHookPath(logger logger.Interface, nvidiaContainerRuntimeHookPath string) string {
|
||||
return resolveWithDefault(
|
||||
logger,
|
||||
"NVIDIA Container Runtime Hook",
|
||||
nvidiaContainerRuntimeHookPath,
|
||||
nvidiaContainerRuntimeHookDefaultPath,
|
||||
)
|
||||
}
|
||||
|
||||
// resolveWithDefault resolves the path to the specified binary.
|
||||
// If an absolute path is specified, it is used directly without searching for the binary.
|
||||
// If the binary cannot be found in the path, the specified default is used instead.
|
||||
func resolveWithDefault(logger logger.Interface, label string, path string, defaultPath string) string {
|
||||
if filepath.IsAbs(path) {
|
||||
logger.Debugf("Using specified %v path %v", label, path)
|
||||
return path
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
path = filepath.Base(defaultPath)
|
||||
}
|
||||
logger.Debugf("Locating %v as %v", label, path)
|
||||
lookup := lookup.NewExecutableLocator(logger, "")
|
||||
|
||||
resolvedPath := defaultPath
|
||||
targets, err := lookup.Locate(path)
|
||||
if err != nil {
|
||||
logger.Warningf("Failed to locate %v: %v", path, err)
|
||||
} else {
|
||||
logger.Debugf("Found %v candidates: %v", path, targets)
|
||||
resolvedPath = targets[0]
|
||||
}
|
||||
logger.Debugf("Using %v path %v", label, path)
|
||||
|
||||
return resolvedPath
|
||||
}
|
||||
|
||||
@@ -76,6 +76,9 @@ func TestGetConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||
Path: "nvidia-container-runtime-hook",
|
||||
},
|
||||
NVIDIACTKConfig: CTKConfig{
|
||||
Path: "nvidia-ctk",
|
||||
},
|
||||
@@ -95,6 +98,7 @@ func TestGetConfig(t *testing.T) {
|
||||
"nvidia-container-runtime.modes.cdi.default-kind = \"example.vendor.com/device\"",
|
||||
"nvidia-container-runtime.modes.cdi.annotation-prefixes = [\"cdi.k8s.io/\", \"example.vendor.com/\",]",
|
||||
"nvidia-container-runtime.modes.csv.mount-spec-path = \"/not/etc/nvidia-container-runtime/host-files-for-container.d\"",
|
||||
"nvidia-container-runtime-hook.path = \"/foo/bar/nvidia-container-runtime-hook\"",
|
||||
"nvidia-ctk.path = \"/foo/bar/nvidia-ctk\"",
|
||||
},
|
||||
expectedConfig: &Config{
|
||||
@@ -120,6 +124,9 @@ func TestGetConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||
Path: "/foo/bar/nvidia-container-runtime-hook",
|
||||
},
|
||||
NVIDIACTKConfig: CTKConfig{
|
||||
Path: "/foo/bar/nvidia-ctk",
|
||||
},
|
||||
@@ -143,6 +150,8 @@ func TestGetConfig(t *testing.T) {
|
||||
"annotation-prefixes = [\"cdi.k8s.io/\", \"example.vendor.com/\",]",
|
||||
"[nvidia-container-runtime.modes.csv]",
|
||||
"mount-spec-path = \"/not/etc/nvidia-container-runtime/host-files-for-container.d\"",
|
||||
"[nvidia-container-runtime-hook]",
|
||||
"path = \"/foo/bar/nvidia-container-runtime-hook\"",
|
||||
"[nvidia-ctk]",
|
||||
"path = \"/foo/bar/nvidia-ctk\"",
|
||||
},
|
||||
@@ -169,6 +178,9 @@ func TestGetConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||
Path: "/foo/bar/nvidia-container-runtime-hook",
|
||||
},
|
||||
NVIDIACTKConfig: CTKConfig{
|
||||
Path: "/foo/bar/nvidia-ctk",
|
||||
},
|
||||
|
||||
@@ -16,47 +16,21 @@
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
// RuntimeHookConfig stores the config options for the NVIDIA Container Runtime
|
||||
type RuntimeHookConfig struct {
|
||||
// Path specifies the path to the NVIDIA Container Runtime hook binary.
|
||||
// If an executable name is specified, this will be resolved in the path.
|
||||
Path string `toml:"path"`
|
||||
// SkipModeDetection disables the mode check for the runtime hook.
|
||||
SkipModeDetection bool `toml:"skip-mode-detection"`
|
||||
}
|
||||
|
||||
// dummyHookConfig allows us to unmarshal only a RuntimeHookConfig from a *toml.Tree
|
||||
type dummyHookConfig struct {
|
||||
RuntimeHook RuntimeHookConfig `toml:"nvidia-container-runtime-hook"`
|
||||
}
|
||||
|
||||
// getRuntimeHookConfigFrom reads the nvidia container runtime config from the specified toml Tree.
|
||||
func getRuntimeHookConfigFrom(toml *toml.Tree) (*RuntimeHookConfig, error) {
|
||||
cfg := GetDefaultRuntimeHookConfig()
|
||||
|
||||
if toml == nil {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
d := dummyHookConfig{
|
||||
RuntimeHook: *cfg,
|
||||
}
|
||||
|
||||
if err := toml.Unmarshal(&d); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal runtime config: %v", err)
|
||||
}
|
||||
|
||||
return &d.RuntimeHook, nil
|
||||
}
|
||||
|
||||
// GetDefaultRuntimeHookConfig defines the default values for the config
|
||||
func GetDefaultRuntimeHookConfig() *RuntimeHookConfig {
|
||||
c := RuntimeHookConfig{
|
||||
SkipModeDetection: false,
|
||||
func GetDefaultRuntimeHookConfig() (*RuntimeHookConfig, error) {
|
||||
cfg, err := getDefaultConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &c
|
||||
return &cfg.NVIDIAContainerRuntimeHookConfig, nil
|
||||
}
|
||||
|
||||
@@ -16,21 +16,6 @@
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"github.com/pelletier/go-toml"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
dockerRuncExecutableName = "docker-runc"
|
||||
runcExecutableName = "runc"
|
||||
|
||||
auto = "auto"
|
||||
)
|
||||
|
||||
// RuntimeConfig stores the config options for the NVIDIA Container Runtime
|
||||
type RuntimeConfig struct {
|
||||
DebugFilePath string `toml:"debug"`
|
||||
@@ -61,52 +46,12 @@ type csvModeConfig struct {
|
||||
MountSpecPath string `toml:"mount-spec-path"`
|
||||
}
|
||||
|
||||
// dummy allows us to unmarshal only a RuntimeConfig from a *toml.Tree
|
||||
type dummy struct {
|
||||
Runtime RuntimeConfig `toml:"nvidia-container-runtime"`
|
||||
}
|
||||
|
||||
// getRuntimeConfigFrom reads the nvidia container runtime config from the specified toml Tree.
|
||||
func getRuntimeConfigFrom(toml *toml.Tree) (*RuntimeConfig, error) {
|
||||
cfg := GetDefaultRuntimeConfig()
|
||||
|
||||
if toml == nil {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
d := dummy{
|
||||
Runtime: *cfg,
|
||||
}
|
||||
|
||||
if err := toml.Unmarshal(&d); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal runtime config: %v", err)
|
||||
}
|
||||
|
||||
return &d.Runtime, nil
|
||||
}
|
||||
|
||||
// GetDefaultRuntimeConfig defines the default values for the config
|
||||
func GetDefaultRuntimeConfig() *RuntimeConfig {
|
||||
c := RuntimeConfig{
|
||||
DebugFilePath: "/dev/null",
|
||||
LogLevel: logrus.InfoLevel.String(),
|
||||
Runtimes: []string{
|
||||
dockerRuncExecutableName,
|
||||
runcExecutableName,
|
||||
},
|
||||
Mode: auto,
|
||||
Modes: modesConfig{
|
||||
CSV: csvModeConfig{
|
||||
MountSpecPath: "/etc/nvidia-container-runtime/host-files-for-container.d",
|
||||
},
|
||||
CDI: cdiModeConfig{
|
||||
DefaultKind: "nvidia.com/gpu",
|
||||
AnnotationPrefixes: []string{
|
||||
cdi.AnnotationPrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
func GetDefaultRuntimeConfig() (*RuntimeConfig, error) {
|
||||
cfg, err := getDefaultConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &c
|
||||
return &cfg.NVIDIAContainerRuntimeConfig, nil
|
||||
}
|
||||
|
||||
@@ -16,31 +16,7 @@
|
||||
|
||||
package config
|
||||
|
||||
import "github.com/pelletier/go-toml"
|
||||
|
||||
// CTKConfig stores the config options for the NVIDIA Container Toolkit CLI (nvidia-ctk)
|
||||
type CTKConfig struct {
|
||||
Path string `toml:"path"`
|
||||
}
|
||||
|
||||
// getCTKConfigFrom reads the nvidia container runtime config from the specified toml Tree.
|
||||
func getCTKConfigFrom(toml *toml.Tree) *CTKConfig {
|
||||
cfg := getDefaultCTKConfig()
|
||||
|
||||
if toml == nil {
|
||||
return cfg
|
||||
}
|
||||
|
||||
cfg.Path = toml.GetDefault("nvidia-ctk.path", cfg.Path).(string)
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
// getDefaultCTKConfig defines the default values for the config
|
||||
func getDefaultCTKConfig() *CTKConfig {
|
||||
c := CTKConfig{
|
||||
Path: "nvidia-ctk",
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
package discover
|
||||
|
||||
import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// charDevices is a discover for a list of character devices
|
||||
@@ -27,7 +27,7 @@ type charDevices mounts
|
||||
var _ Discover = (*charDevices)(nil)
|
||||
|
||||
// NewCharDeviceDiscoverer creates a discoverer which locates the specified set of device nodes.
|
||||
func NewCharDeviceDiscoverer(logger *logrus.Logger, devices []string, root string) Discover {
|
||||
func NewCharDeviceDiscoverer(logger logger.Interface, devices []string, root string) Discover {
|
||||
locator := lookup.NewCharDeviceLocator(
|
||||
lookup.WithLogger(logger),
|
||||
lookup.WithRoot(root),
|
||||
@@ -37,7 +37,7 @@ func NewCharDeviceDiscoverer(logger *logrus.Logger, devices []string, root strin
|
||||
}
|
||||
|
||||
// NewDeviceDiscoverer creates a discoverer which locates the specified set of device nodes using the specified locator.
|
||||
func NewDeviceDiscoverer(logger *logrus.Logger, locator lookup.Locator, root string, devices []string) Discover {
|
||||
func NewDeviceDiscoverer(logger logger.Interface, locator lookup.Locator, root string, devices []string) Discover {
|
||||
m := NewMounts(logger, locator, root, devices).(*mounts)
|
||||
|
||||
return (*charDevices)(m)
|
||||
|
||||
@@ -20,16 +20,16 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover/csv"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// NewFromCSVFiles creates a discoverer for the specified CSV files. A logger is also supplied.
|
||||
// The constructed discoverer is comprised of a list, with each element in the list being associated with a
|
||||
// single CSV files.
|
||||
func NewFromCSVFiles(logger *logrus.Logger, files []string, driverRoot string) (Discover, error) {
|
||||
func NewFromCSVFiles(logger logger.Interface, files []string, driverRoot string) (Discover, error) {
|
||||
if len(files) == 0 {
|
||||
logger.Warnf("No CSV files specified")
|
||||
logger.Warningf("No CSV files specified")
|
||||
return None{}, nil
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func NewFromCSVFiles(logger *logrus.Logger, files []string, driverRoot string) (
|
||||
for _, filename := range files {
|
||||
targets, err := loadCSVFile(logger, filename)
|
||||
if err != nil {
|
||||
logger.Warnf("Skipping CSV file %v: %v", filename, err)
|
||||
logger.Warningf("Skipping CSV file %v: %v", filename, err)
|
||||
continue
|
||||
}
|
||||
mountSpecs = append(mountSpecs, targets...)
|
||||
@@ -56,7 +56,7 @@ func NewFromCSVFiles(logger *logrus.Logger, files []string, driverRoot string) (
|
||||
}
|
||||
|
||||
// loadCSVFile loads the specified CSV file and returns the list of mount specs
|
||||
func loadCSVFile(logger *logrus.Logger, filename string) ([]*csv.MountSpec, error) {
|
||||
func loadCSVFile(logger logger.Interface, filename string) ([]*csv.MountSpec, error) {
|
||||
// Create a discoverer for each file-kind combination
|
||||
targets, err := csv.NewCSVFileParser(logger, filename).Parse()
|
||||
if err != nil {
|
||||
@@ -71,7 +71,7 @@ func loadCSVFile(logger *logrus.Logger, filename string) ([]*csv.MountSpec, erro
|
||||
|
||||
// newFromMountSpecs creates a discoverer for the CSV file. A logger is also supplied.
|
||||
// A list of csvDiscoverers is returned, with each being associated with a single MountSpecType.
|
||||
func newFromMountSpecs(logger *logrus.Logger, locators map[csv.MountSpecType]lookup.Locator, driverRoot string, targets []*csv.MountSpec) (Discover, error) {
|
||||
func newFromMountSpecs(logger logger.Interface, locators map[csv.MountSpecType]lookup.Locator, driverRoot string, targets []*csv.MountSpec) (Discover, error) {
|
||||
if len(targets) == 0 {
|
||||
return &None{}, nil
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -33,6 +33,22 @@ const (
|
||||
DefaultMountSpecPath = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||
)
|
||||
|
||||
// DefaultFileList returns the list of CSV files that are used by default.
|
||||
func DefaultFileList() []string {
|
||||
files := []string{
|
||||
"devices.csv",
|
||||
"drivers.csv",
|
||||
"l4t.csv",
|
||||
}
|
||||
|
||||
var paths []string
|
||||
for _, file := range files {
|
||||
paths = append(paths, filepath.Join(DefaultMountSpecPath, file))
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
// GetFileList returns the (non-recursive) list of CSV files in the specified
|
||||
// folder
|
||||
func GetFileList(root string) ([]string, error) {
|
||||
@@ -87,12 +103,12 @@ type Parser interface {
|
||||
}
|
||||
|
||||
type csv struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
filename string
|
||||
}
|
||||
|
||||
// NewCSVFileParser creates a new parser for reading MountSpecs from the specified CSV file
|
||||
func NewCSVFileParser(logger *logrus.Logger, filename string) Parser {
|
||||
func NewCSVFileParser(logger logger.Interface, filename string) Parser {
|
||||
p := csv{
|
||||
logger: logger,
|
||||
filename: filename,
|
||||
|
||||
@@ -16,12 +16,6 @@
|
||||
|
||||
package discover
|
||||
|
||||
// Config represents the configuration options for discovery
|
||||
type Config struct {
|
||||
DriverRoot string
|
||||
NvidiaCTKPath string
|
||||
}
|
||||
|
||||
// Device represents a discovered character device.
|
||||
type Device struct {
|
||||
HostPath string
|
||||
|
||||
@@ -13,25 +13,25 @@ var _ Discover = &DiscoverMock{}
|
||||
|
||||
// DiscoverMock is a mock implementation of Discover.
|
||||
//
|
||||
// func TestSomethingThatUsesDiscover(t *testing.T) {
|
||||
// func TestSomethingThatUsesDiscover(t *testing.T) {
|
||||
//
|
||||
// // make and configure a mocked Discover
|
||||
// mockedDiscover := &DiscoverMock{
|
||||
// DevicesFunc: func() ([]Device, error) {
|
||||
// panic("mock out the Devices method")
|
||||
// },
|
||||
// HooksFunc: func() ([]Hook, error) {
|
||||
// panic("mock out the Hooks method")
|
||||
// },
|
||||
// MountsFunc: func() ([]Mount, error) {
|
||||
// panic("mock out the Mounts method")
|
||||
// },
|
||||
// }
|
||||
// // make and configure a mocked Discover
|
||||
// mockedDiscover := &DiscoverMock{
|
||||
// DevicesFunc: func() ([]Device, error) {
|
||||
// panic("mock out the Devices method")
|
||||
// },
|
||||
// HooksFunc: func() ([]Hook, error) {
|
||||
// panic("mock out the Hooks method")
|
||||
// },
|
||||
// MountsFunc: func() ([]Mount, error) {
|
||||
// panic("mock out the Mounts method")
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // use mockedDiscover in code that requires Discover
|
||||
// // and then make assertions.
|
||||
// // use mockedDiscover in code that requires Discover
|
||||
// // and then make assertions.
|
||||
//
|
||||
// }
|
||||
// }
|
||||
type DiscoverMock struct {
|
||||
// DevicesFunc mocks the Devices method.
|
||||
DevicesFunc func() ([]Device, error)
|
||||
@@ -78,7 +78,8 @@ func (mock *DiscoverMock) Devices() ([]Device, error) {
|
||||
|
||||
// DevicesCalls gets all the calls that were made to Devices.
|
||||
// Check the length with:
|
||||
// len(mockedDiscover.DevicesCalls())
|
||||
//
|
||||
// len(mockedDiscover.DevicesCalls())
|
||||
func (mock *DiscoverMock) DevicesCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
@@ -108,7 +109,8 @@ func (mock *DiscoverMock) Hooks() ([]Hook, error) {
|
||||
|
||||
// HooksCalls gets all the calls that were made to Hooks.
|
||||
// Check the length with:
|
||||
// len(mockedDiscover.HooksCalls())
|
||||
//
|
||||
// len(mockedDiscover.HooksCalls())
|
||||
func (mock *DiscoverMock) HooksCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
@@ -138,7 +140,8 @@ func (mock *DiscoverMock) Mounts() ([]Mount, error) {
|
||||
|
||||
// MountsCalls gets all the calls that were made to Mounts.
|
||||
// Check the length with:
|
||||
// len(mockedDiscover.MountsCalls())
|
||||
//
|
||||
// len(mockedDiscover.MountsCalls())
|
||||
func (mock *DiscoverMock) MountsCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package discover
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
import "github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
|
||||
// Filter defines an interface for filtering discovered entities
|
||||
type Filter interface {
|
||||
@@ -26,12 +26,12 @@ type Filter interface {
|
||||
// filtered represents a filtered discoverer
|
||||
type filtered struct {
|
||||
Discover
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
filter Filter
|
||||
}
|
||||
|
||||
// newFilteredDisoverer creates a discoverer that applies the specified filter to the returned entities of the discoverer
|
||||
func newFilteredDisoverer(logger *logrus.Logger, applyTo Discover, filter Filter) Discover {
|
||||
func newFilteredDisoverer(logger logger.Interface, applyTo Discover, filter Filter) Discover {
|
||||
return filtered{
|
||||
Discover: applyTo,
|
||||
logger: logger,
|
||||
|
||||
@@ -17,19 +17,19 @@
|
||||
package discover
|
||||
|
||||
import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type gdsDeviceDiscoverer struct {
|
||||
None
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
devices Discover
|
||||
mounts Discover
|
||||
}
|
||||
|
||||
// NewGDSDiscoverer creates a discoverer for GPUDirect Storage devices and mounts.
|
||||
func NewGDSDiscoverer(logger *logrus.Logger, root string) (Discover, error) {
|
||||
func NewGDSDiscoverer(logger logger.Interface, root string) (Discover, error) {
|
||||
devices := NewCharDeviceDiscoverer(
|
||||
logger,
|
||||
[]string{"/dev/nvidia-fs*"},
|
||||
|
||||
@@ -25,16 +25,14 @@ import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/info/drm"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/info/proc"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/cuda"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// NewGraphicsDiscoverer returns the discoverer for graphics tools such as Vulkan.
|
||||
func NewGraphicsDiscoverer(logger *logrus.Logger, devices image.VisibleDevices, cfg *Config) (Discover, error) {
|
||||
driverRoot := cfg.DriverRoot
|
||||
|
||||
mounts, err := NewGraphicsMountsDiscoverer(logger, driverRoot)
|
||||
func NewGraphicsDiscoverer(logger logger.Interface, devices image.VisibleDevices, driverRoot string, nvidiaCTKPath string) (Discover, error) {
|
||||
mounts, err := NewGraphicsMountsDiscoverer(logger, driverRoot, nvidiaCTKPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create mounts discoverer: %v", err)
|
||||
}
|
||||
@@ -44,24 +42,18 @@ func NewGraphicsDiscoverer(logger *logrus.Logger, devices image.VisibleDevices,
|
||||
return nil, fmt.Errorf("failed to create DRM device discoverer: %v", err)
|
||||
}
|
||||
|
||||
drmByPathSymlinks := newCreateDRMByPathSymlinks(logger, drmDeviceNodes, cfg)
|
||||
|
||||
xorg, err := newXorgDiscoverer(logger, driverRoot, cfg.NvidiaCTKPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create Xorg discoverer: %v", err)
|
||||
}
|
||||
drmByPathSymlinks := newCreateDRMByPathSymlinks(logger, drmDeviceNodes, driverRoot, nvidiaCTKPath)
|
||||
|
||||
discover := Merge(
|
||||
Merge(drmDeviceNodes, drmByPathSymlinks),
|
||||
mounts,
|
||||
xorg,
|
||||
)
|
||||
|
||||
return discover, nil
|
||||
}
|
||||
|
||||
// NewGraphicsMountsDiscoverer creates a discoverer for the mounts required by graphics tools such as vulkan.
|
||||
func NewGraphicsMountsDiscoverer(logger *logrus.Logger, driverRoot string) (Discover, error) {
|
||||
func NewGraphicsMountsDiscoverer(logger logger.Interface, driverRoot string, nvidiaCTKPath string) (Discover, error) {
|
||||
locator, err := lookup.NewLibraryLocator(logger, driverRoot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct library locator: %v", err)
|
||||
@@ -92,9 +84,12 @@ func NewGraphicsMountsDiscoverer(logger *logrus.Logger, driverRoot string) (Disc
|
||||
},
|
||||
)
|
||||
|
||||
xorg := optionalXorgDiscoverer(logger, driverRoot, nvidiaCTKPath)
|
||||
|
||||
discover := Merge(
|
||||
libraries,
|
||||
jsonMounts,
|
||||
xorg,
|
||||
)
|
||||
|
||||
return discover, nil
|
||||
@@ -102,18 +97,18 @@ func NewGraphicsMountsDiscoverer(logger *logrus.Logger, driverRoot string) (Disc
|
||||
|
||||
type drmDevicesByPath struct {
|
||||
None
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
nvidiaCTKPath string
|
||||
driverRoot string
|
||||
devicesFrom Discover
|
||||
}
|
||||
|
||||
// newCreateDRMByPathSymlinks creates a discoverer for a hook to create the by-path symlinks for DRM devices discovered by the specified devices discoverer
|
||||
func newCreateDRMByPathSymlinks(logger *logrus.Logger, devices Discover, cfg *Config) Discover {
|
||||
func newCreateDRMByPathSymlinks(logger logger.Interface, devices Discover, driverRoot string, nvidiaCTKPath string) Discover {
|
||||
d := drmDevicesByPath{
|
||||
logger: logger,
|
||||
nvidiaCTKPath: FindNvidiaCTK(logger, cfg.NvidiaCTKPath),
|
||||
driverRoot: cfg.DriverRoot,
|
||||
nvidiaCTKPath: nvidiaCTKPath,
|
||||
driverRoot: driverRoot,
|
||||
devicesFrom: devices,
|
||||
}
|
||||
|
||||
@@ -186,7 +181,7 @@ func (d drmDevicesByPath) getSpecificLinkArgs(devices []Device) ([]string, error
|
||||
}
|
||||
|
||||
// newDRMDeviceDiscoverer creates a discoverer for the DRM devices associated with the requested devices.
|
||||
func newDRMDeviceDiscoverer(logger *logrus.Logger, devices image.VisibleDevices, driverRoot string) (Discover, error) {
|
||||
func newDRMDeviceDiscoverer(logger logger.Interface, devices image.VisibleDevices, driverRoot string) (Discover, error) {
|
||||
allDevices := NewDeviceDiscoverer(
|
||||
logger,
|
||||
lookup.NewCharDeviceLocator(
|
||||
@@ -216,7 +211,7 @@ func newDRMDeviceDiscoverer(logger *logrus.Logger, devices image.VisibleDevices,
|
||||
}
|
||||
|
||||
// newDRMDeviceFilter creates a filter that matches DRM devices nodes for the visible devices.
|
||||
func newDRMDeviceFilter(logger *logrus.Logger, devices image.VisibleDevices, driverRoot string) (Filter, error) {
|
||||
func newDRMDeviceFilter(logger logger.Interface, devices image.VisibleDevices, driverRoot string) (Filter, error) {
|
||||
gpuInformationPaths, err := proc.GetInformationFilePaths(driverRoot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read GPU information: %v", err)
|
||||
@@ -259,11 +254,22 @@ type xorgHooks struct {
|
||||
|
||||
var _ Discover = (*xorgHooks)(nil)
|
||||
|
||||
func newXorgDiscoverer(logger *logrus.Logger, driverRoot string, nvidiaCTKPath string) (Discover, error) {
|
||||
// optionalXorgDiscoverer creates a discoverer for Xorg libraries.
|
||||
// If the creation of the discoverer fails, a None discoverer is returned.
|
||||
func optionalXorgDiscoverer(logger logger.Interface, driverRoot string, nvidiaCTKPath string) Discover {
|
||||
xorg, err := newXorgDiscoverer(logger, driverRoot, nvidiaCTKPath)
|
||||
if err != nil {
|
||||
logger.Warningf("Failed to create Xorg discoverer: %v; skipping xorg libraries", err)
|
||||
return None{}
|
||||
}
|
||||
return xorg
|
||||
}
|
||||
|
||||
func newXorgDiscoverer(logger logger.Interface, driverRoot string, nvidiaCTKPath string) (Discover, error) {
|
||||
libCudaPaths, err := cuda.New(
|
||||
cuda.WithLogger(logger),
|
||||
cuda.WithDriverRoot(driverRoot),
|
||||
).Locate(".*.*.*")
|
||||
).Locate(".*.*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to locate libcuda.so: %v", err)
|
||||
}
|
||||
@@ -292,7 +298,7 @@ func newXorgDiscoverer(logger *logrus.Logger, driverRoot string, nvidiaCTKPath s
|
||||
xorgHooks := xorgHooks{
|
||||
libraries: xorgLibs,
|
||||
driverVersion: version,
|
||||
nvidiaCTKPath: FindNvidiaCTK(logger, nvidiaCTKPath),
|
||||
nvidiaCTKPath: nvidiaCTKPath,
|
||||
}
|
||||
|
||||
xorgConfg := NewMounts(
|
||||
|
||||
@@ -19,14 +19,7 @@ package discover
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
nvidiaCTKExecutable = "nvidia-ctk"
|
||||
nvidiaCTKDefaultFilePath = "/usr/bin/nvidia-ctk"
|
||||
)
|
||||
|
||||
var _ Discover = (*Hook)(nil)
|
||||
@@ -72,32 +65,3 @@ func CreateNvidiaCTKHook(nvidiaCTKPath string, hookName string, additionalArgs .
|
||||
Args: append([]string{filepath.Base(nvidiaCTKPath), "hook", hookName}, additionalArgs...),
|
||||
}
|
||||
}
|
||||
|
||||
// FindNvidiaCTK locates the nvidia-ctk executable to be used in hooks.
|
||||
// If an nvidia-ctk path is specified as an absolute path, it is used directly
|
||||
// without checking for existence of an executable at that path.
|
||||
func FindNvidiaCTK(logger *logrus.Logger, nvidiaCTKPath string) string {
|
||||
if filepath.IsAbs(nvidiaCTKPath) {
|
||||
logger.Debugf("Using specified NVIDIA Container Toolkit CLI path %v", nvidiaCTKPath)
|
||||
return nvidiaCTKPath
|
||||
}
|
||||
|
||||
if nvidiaCTKPath == "" {
|
||||
nvidiaCTKPath = nvidiaCTKExecutable
|
||||
}
|
||||
logger.Debugf("Locating NVIDIA Container Toolkit CLI as %v", nvidiaCTKPath)
|
||||
lookup := lookup.NewExecutableLocator(logger, "")
|
||||
hookPath := nvidiaCTKDefaultFilePath
|
||||
targets, err := lookup.Locate(nvidiaCTKPath)
|
||||
if err != nil {
|
||||
logger.Warnf("Failed to locate %v: %v", nvidiaCTKPath, err)
|
||||
} else if len(targets) == 0 {
|
||||
logger.Warnf("%v not found", nvidiaCTKPath)
|
||||
} else {
|
||||
logger.Debugf("Found %v candidates: %v", nvidiaCTKPath, targets)
|
||||
hookPath = targets[0]
|
||||
}
|
||||
logger.Debugf("Using NVIDIA Container Toolkit CLI path %v", hookPath)
|
||||
|
||||
return hookPath
|
||||
}
|
||||
|
||||
@@ -20,14 +20,15 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/sirupsen/logrus"
|
||||
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIPCMounts(t *testing.T) {
|
||||
logger, _ := testlog.NewNullLogger()
|
||||
l := ipcMounts(
|
||||
mounts{
|
||||
logger: logrus.New(),
|
||||
logger: logger,
|
||||
lookup: &lookup.LocatorMock{
|
||||
LocateFunc: func(path string) ([]string, error) {
|
||||
return []string{"/host/path"}, nil
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
package discover
|
||||
|
||||
import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ipcMounts mounts
|
||||
|
||||
// NewIPCDiscoverer creats a discoverer for NVIDIA IPC sockets.
|
||||
func NewIPCDiscoverer(logger *logrus.Logger, driverRoot string) (Discover, error) {
|
||||
func NewIPCDiscoverer(logger logger.Interface, driverRoot string) (Discover, error) {
|
||||
sockets := newMounts(
|
||||
logger,
|
||||
lookup.NewFileLocator(
|
||||
|
||||
@@ -21,14 +21,14 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
)
|
||||
|
||||
// NewLDCacheUpdateHook creates a discoverer that updates the ldcache for the specified mounts. A logger can also be specified
|
||||
func NewLDCacheUpdateHook(logger *logrus.Logger, mounts Discover, cfg *Config) (Discover, error) {
|
||||
func NewLDCacheUpdateHook(logger logger.Interface, mounts Discover, nvidiaCTKPath string) (Discover, error) {
|
||||
d := ldconfig{
|
||||
logger: logger,
|
||||
nvidiaCTKPath: FindNvidiaCTK(logger, cfg.NvidiaCTKPath),
|
||||
nvidiaCTKPath: nvidiaCTKPath,
|
||||
mountsFrom: mounts,
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func NewLDCacheUpdateHook(logger *logrus.Logger, mounts Discover, cfg *Config) (
|
||||
|
||||
type ldconfig struct {
|
||||
None
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
nvidiaCTKPath string
|
||||
mountsFrom Discover
|
||||
}
|
||||
|
||||
@@ -31,11 +31,6 @@ const (
|
||||
func TestLDCacheUpdateHook(t *testing.T) {
|
||||
logger, _ := testlog.NewNullLogger()
|
||||
|
||||
cfg := Config{
|
||||
DriverRoot: "/",
|
||||
NvidiaCTKPath: testNvidiaCTKPath,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
description string
|
||||
mounts []Mount
|
||||
@@ -95,7 +90,7 @@ func TestLDCacheUpdateHook(t *testing.T) {
|
||||
Lifecycle: "createContainer",
|
||||
}
|
||||
|
||||
d, err := NewLDCacheUpdateHook(logger, mountMock, &cfg)
|
||||
d, err := NewLDCacheUpdateHook(logger, mountMock, testNvidiaCTKPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
hooks, err := d.Hooks()
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
|
||||
package discover
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
import "github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
|
||||
// NewMOFEDDiscoverer creates a discoverer for MOFED devices.
|
||||
func NewMOFEDDiscoverer(logger *logrus.Logger, root string) (Discover, error) {
|
||||
func NewMOFEDDiscoverer(logger logger.Interface, root string) (Discover, error) {
|
||||
devices := NewCharDeviceDiscoverer(
|
||||
logger,
|
||||
[]string{
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// mounts is a generic discoverer for Mounts. It is customized by specifying the
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
// based on the entry in the list.
|
||||
type mounts struct {
|
||||
None
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
lookup lookup.Locator
|
||||
root string
|
||||
required []string
|
||||
@@ -42,12 +42,12 @@ type mounts struct {
|
||||
var _ Discover = (*mounts)(nil)
|
||||
|
||||
// NewMounts creates a discoverer for the required mounts using the specified locator.
|
||||
func NewMounts(logger *logrus.Logger, lookup lookup.Locator, root string, required []string) Discover {
|
||||
func NewMounts(logger logger.Interface, lookup lookup.Locator, root string, required []string) Discover {
|
||||
return newMounts(logger, lookup, root, required)
|
||||
}
|
||||
|
||||
// newMounts creates a discoverer for the required mounts using the specified locator.
|
||||
func newMounts(logger *logrus.Logger, lookup lookup.Locator, root string, required []string) *mounts {
|
||||
func newMounts(logger logger.Interface, lookup lookup.Locator, root string, required []string) *mounts {
|
||||
return &mounts{
|
||||
logger: logger,
|
||||
lookup: lookup,
|
||||
@@ -75,11 +75,11 @@ func (d *mounts) Mounts() ([]Mount, error) {
|
||||
d.logger.Debugf("Locating %v", candidate)
|
||||
located, err := d.lookup.Locate(candidate)
|
||||
if err != nil {
|
||||
d.logger.Warnf("Could not locate %v: %v", candidate, err)
|
||||
d.logger.Warningf("Could not locate %v: %v", candidate, err)
|
||||
continue
|
||||
}
|
||||
if len(located) == 0 {
|
||||
d.logger.Warnf("Missing %v", candidate)
|
||||
d.logger.Warningf("Missing %v", candidate)
|
||||
continue
|
||||
}
|
||||
d.logger.Debugf("Located %v as %v", candidate, located)
|
||||
|
||||
@@ -21,22 +21,26 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover/csv"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks"
|
||||
)
|
||||
|
||||
type symlinks struct {
|
||||
type symlinkHook struct {
|
||||
None
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
driverRoot string
|
||||
nvidiaCTKPath string
|
||||
csvFiles []string
|
||||
mountsFrom Discover
|
||||
}
|
||||
|
||||
// NewCreateSymlinksHook creates a discoverer for a hook that creates required symlinks in the container
|
||||
func NewCreateSymlinksHook(logger *logrus.Logger, csvFiles []string, mounts Discover, cfg *Config) (Discover, error) {
|
||||
d := symlinks{
|
||||
func NewCreateSymlinksHook(logger logger.Interface, csvFiles []string, mounts Discover, nvidiaCTKPath string) (Discover, error) {
|
||||
d := symlinkHook{
|
||||
logger: logger,
|
||||
nvidiaCTKPath: FindNvidiaCTK(logger, cfg.NvidiaCTKPath),
|
||||
nvidiaCTKPath: nvidiaCTKPath,
|
||||
csvFiles: csvFiles,
|
||||
mountsFrom: mounts,
|
||||
}
|
||||
@@ -45,17 +49,17 @@ func NewCreateSymlinksHook(logger *logrus.Logger, csvFiles []string, mounts Disc
|
||||
}
|
||||
|
||||
// Hooks returns a hook to create the symlinks from the required CSV files
|
||||
func (d symlinks) Hooks() ([]Hook, error) {
|
||||
var args []string
|
||||
for _, f := range d.csvFiles {
|
||||
args = append(args, "--csv-filename", f)
|
||||
}
|
||||
|
||||
links, err := d.getSpecificLinkArgs()
|
||||
func (d symlinkHook) Hooks() ([]Hook, error) {
|
||||
specificLinks, err := d.getSpecificLinks()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to determine specific links: %v", err)
|
||||
}
|
||||
args = append(args, links...)
|
||||
|
||||
csvSymlinks := d.getCSVFileSymlinks()
|
||||
var args []string
|
||||
for _, link := range append(csvSymlinks, specificLinks...) {
|
||||
args = append(args, "--link", link)
|
||||
}
|
||||
|
||||
hook := CreateNvidiaCTKHook(
|
||||
d.nvidiaCTKPath,
|
||||
@@ -66,8 +70,8 @@ func (d symlinks) Hooks() ([]Hook, error) {
|
||||
return []Hook{hook}, nil
|
||||
}
|
||||
|
||||
// getSpecificLinkArgs returns the required specic links that need to be created
|
||||
func (d symlinks) getSpecificLinkArgs() ([]string, error) {
|
||||
// getSpecificLinks returns the required specic links that need to be created
|
||||
func (d symlinkHook) getSpecificLinks() ([]string, error) {
|
||||
mounts, err := d.mountsFrom.Mounts()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to discover mounts for ldcache update: %v", err)
|
||||
@@ -99,11 +103,60 @@ func (d symlinks) getSpecificLinkArgs() ([]string, error) {
|
||||
if linkProcessed[link] {
|
||||
continue
|
||||
}
|
||||
linkProcessed[link] = true
|
||||
|
||||
linkPath := filepath.Join(filepath.Dir(m.Path), link)
|
||||
links = append(links, "--link", fmt.Sprintf("%v::%v", target, linkPath))
|
||||
linkProcessed[link] = true
|
||||
links = append(links, fmt.Sprintf("%v::%v", target, linkPath))
|
||||
}
|
||||
|
||||
return links, nil
|
||||
}
|
||||
|
||||
func (d symlinkHook) getCSVFileSymlinks() []string {
|
||||
chainLocator := lookup.NewSymlinkChainLocator(d.logger, d.driverRoot)
|
||||
|
||||
var candidates []string
|
||||
for _, file := range d.csvFiles {
|
||||
mountSpecs, err := csv.NewCSVFileParser(d.logger, file).Parse()
|
||||
if err != nil {
|
||||
d.logger.Debugf("Skipping CSV file %v: %v", file, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ms := range mountSpecs {
|
||||
if ms.Type != csv.MountSpecSym {
|
||||
continue
|
||||
}
|
||||
targets, err := chainLocator.Locate(ms.Path)
|
||||
if err != nil {
|
||||
d.logger.Warningf("Failed to locate symlink %v", ms.Path)
|
||||
}
|
||||
candidates = append(candidates, targets...)
|
||||
}
|
||||
}
|
||||
|
||||
var links []string
|
||||
created := make(map[string]bool)
|
||||
// candidates is a list of absolute paths to symlinks in a chain, or the final target of the chain.
|
||||
for _, candidate := range candidates {
|
||||
target, err := symlinks.Resolve(candidate)
|
||||
if err != nil {
|
||||
d.logger.Debugf("Skipping invalid link: %v", err)
|
||||
continue
|
||||
} else if target == candidate {
|
||||
d.logger.Debugf("%v is not a symlink", candidate)
|
||||
continue
|
||||
}
|
||||
|
||||
link := fmt.Sprintf("%v::%v", target, candidate)
|
||||
if created[link] {
|
||||
d.logger.Debugf("skipping duplicate link: %v", link)
|
||||
continue
|
||||
}
|
||||
created[link] = true
|
||||
|
||||
links = append(links, link)
|
||||
}
|
||||
|
||||
return links
|
||||
}
|
||||
|
||||
106
internal/discover/tegra/tegra.go
Normal file
106
internal/discover/tegra/tegra.go
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package tegra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
)
|
||||
|
||||
type tegraOptions struct {
|
||||
logger logger.Interface
|
||||
csvFiles []string
|
||||
driverRoot string
|
||||
nvidiaCTKPath string
|
||||
}
|
||||
|
||||
// Option defines a functional option for configuring a Tegra discoverer.
|
||||
type Option func(*tegraOptions)
|
||||
|
||||
// New creates a new tegra discoverer using the supplied options.
|
||||
func New(opts ...Option) (discover.Discover, error) {
|
||||
o := &tegraOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
|
||||
csvDiscoverer, err := discover.NewFromCSVFiles(o.logger, o.csvFiles, o.driverRoot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create CSV discoverer: %v", err)
|
||||
}
|
||||
|
||||
createSymlinksHook, err := discover.NewCreateSymlinksHook(o.logger, o.csvFiles, csvDiscoverer, o.nvidiaCTKPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create symlink hook discoverer: %v", err)
|
||||
}
|
||||
|
||||
ldcacheUpdateHook, err := discover.NewLDCacheUpdateHook(o.logger, csvDiscoverer, o.nvidiaCTKPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ldcach update hook discoverer: %v", err)
|
||||
}
|
||||
|
||||
tegraSystemMounts := discover.NewMounts(
|
||||
o.logger,
|
||||
lookup.NewFileLocator(lookup.WithLogger(o.logger)),
|
||||
"",
|
||||
[]string{
|
||||
"/etc/nv_tegra_release",
|
||||
"/sys/devices/soc0/family",
|
||||
},
|
||||
)
|
||||
|
||||
d := discover.Merge(
|
||||
csvDiscoverer,
|
||||
createSymlinksHook,
|
||||
// The ldcacheUpdateHook is added last to ensure that the created symlinks are included
|
||||
ldcacheUpdateHook,
|
||||
tegraSystemMounts,
|
||||
)
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// WithLogger sets the logger for the discoverer.
|
||||
func WithLogger(logger logger.Interface) Option {
|
||||
return func(o *tegraOptions) {
|
||||
o.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
// WithDriverRoot sets the driver root for the discoverer.
|
||||
func WithDriverRoot(driverRoot string) Option {
|
||||
return func(o *tegraOptions) {
|
||||
o.driverRoot = driverRoot
|
||||
}
|
||||
}
|
||||
|
||||
// WithCSVFiles sets the CSV files for the discoverer.
|
||||
func WithCSVFiles(csvFiles []string) Option {
|
||||
return func(o *tegraOptions) {
|
||||
o.csvFiles = csvFiles
|
||||
}
|
||||
}
|
||||
|
||||
// WithNVIDIACTKPath sets the path to the nvidia-container-toolkit binary.
|
||||
func WithNVIDIACTKPath(nvidiaCTKPath string) Option {
|
||||
return func(o *tegraOptions) {
|
||||
o.nvidiaCTKPath = nvidiaCTKPath
|
||||
}
|
||||
}
|
||||
@@ -20,21 +20,21 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/specs-go"
|
||||
ociSpecs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type edits struct {
|
||||
cdi.ContainerEdits
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// NewSpecEdits creates a SpecModifier that defines the required OCI spec edits (as CDI ContainerEdits) from the specified
|
||||
// discoverer.
|
||||
func NewSpecEdits(logger *logrus.Logger, d discover.Discover) (oci.SpecModifier, error) {
|
||||
func NewSpecEdits(logger logger.Interface, d discover.Discover) (oci.SpecModifier, error) {
|
||||
c, err := FromDiscoverer(d)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error constructing container edits: %v", err)
|
||||
|
||||
@@ -16,31 +16,51 @@
|
||||
|
||||
package info
|
||||
|
||||
import "gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/info"
|
||||
import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/info"
|
||||
)
|
||||
|
||||
// Logger is a basic interface for logging to allow these functions to be called
|
||||
// from code where logrus is not used.
|
||||
type Logger interface {
|
||||
Infof(string, ...interface{})
|
||||
Debugf(string, ...interface{})
|
||||
// infoInterface provides an alias for mocking.
|
||||
//
|
||||
//go:generate moq -stub -out info-interface_mock.go . infoInterface
|
||||
type infoInterface info.Interface
|
||||
|
||||
type resolver struct {
|
||||
logger logger.Interface
|
||||
info info.Interface
|
||||
}
|
||||
|
||||
// ResolveAutoMode determines the correct mode for the platform if set to "auto"
|
||||
func ResolveAutoMode(logger Logger, mode string) (rmode string) {
|
||||
func ResolveAutoMode(logger logger.Interface, mode string, image image.CUDA) (rmode string) {
|
||||
nvinfo := info.New()
|
||||
r := resolver{
|
||||
logger: logger,
|
||||
info: nvinfo,
|
||||
}
|
||||
return r.resolveMode(mode, image)
|
||||
}
|
||||
|
||||
// resolveMode determines the correct mode for the platform if set to "auto"
|
||||
func (r resolver) resolveMode(mode string, image image.CUDA) (rmode string) {
|
||||
if mode != "auto" {
|
||||
return mode
|
||||
}
|
||||
defer func() {
|
||||
logger.Infof("Auto-detected mode as '%v'", rmode)
|
||||
r.logger.Infof("Auto-detected mode as '%v'", rmode)
|
||||
}()
|
||||
|
||||
nvinfo := info.New()
|
||||
if onlyFullyQualifiedCDIDevices(image) {
|
||||
return "cdi"
|
||||
}
|
||||
|
||||
isTegra, reason := nvinfo.IsTegraSystem()
|
||||
logger.Debugf("Is Tegra-based system? %v: %v", isTegra, reason)
|
||||
isTegra, reason := r.info.IsTegraSystem()
|
||||
r.logger.Debugf("Is Tegra-based system? %v: %v", isTegra, reason)
|
||||
|
||||
hasNVML, reason := nvinfo.HasNvml()
|
||||
logger.Debugf("Has NVML? %v: %v", hasNVML, reason)
|
||||
hasNVML, reason := r.info.HasNvml()
|
||||
r.logger.Debugf("Has NVML? %v: %v", hasNVML, reason)
|
||||
|
||||
if isTegra && !hasNVML {
|
||||
return "csv"
|
||||
@@ -48,3 +68,14 @@ func ResolveAutoMode(logger Logger, mode string) (rmode string) {
|
||||
|
||||
return "legacy"
|
||||
}
|
||||
|
||||
func onlyFullyQualifiedCDIDevices(image image.CUDA) bool {
|
||||
var hasCDIdevice bool
|
||||
for _, device := range image.DevicesFromEnvvars("NVIDIA_VISIBLE_DEVICES").List() {
|
||||
if !cdi.IsQualifiedName(device) {
|
||||
return false
|
||||
}
|
||||
hasCDIdevice = true
|
||||
}
|
||||
return hasCDIdevice
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ package info
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/info"
|
||||
)
|
||||
|
||||
func TestResolveAutoMode(t *testing.T) {
|
||||
@@ -30,23 +32,123 @@ func TestResolveAutoMode(t *testing.T) {
|
||||
description string
|
||||
mode string
|
||||
expectedMode string
|
||||
info info.Interface
|
||||
image image.CUDA
|
||||
}{
|
||||
{
|
||||
description: "non-auto resolves to input",
|
||||
mode: "not-auto",
|
||||
expectedMode: "not-auto",
|
||||
},
|
||||
// TODO: The following test is brittle in that it will break on Tegra-based systems.
|
||||
// {
|
||||
// description: "auto resolves to legacy",
|
||||
// mode: "auto",
|
||||
// expectedMode: "legacy",
|
||||
// },
|
||||
{
|
||||
description: "nvml non-tegra resolves to legacy",
|
||||
mode: "auto",
|
||||
info: &infoInterfaceMock{
|
||||
HasNvmlFunc: func() (bool, string) {
|
||||
return true, "nvml"
|
||||
},
|
||||
IsTegraSystemFunc: func() (bool, string) {
|
||||
return false, "tegra"
|
||||
},
|
||||
},
|
||||
expectedMode: "legacy",
|
||||
},
|
||||
{
|
||||
description: "non-nvml non-tegra resolves to legacy",
|
||||
mode: "auto",
|
||||
info: &infoInterfaceMock{
|
||||
HasNvmlFunc: func() (bool, string) {
|
||||
return false, "nvml"
|
||||
},
|
||||
IsTegraSystemFunc: func() (bool, string) {
|
||||
return false, "tegra"
|
||||
},
|
||||
},
|
||||
expectedMode: "legacy",
|
||||
},
|
||||
{
|
||||
description: "nvml tegra resolves to legacy",
|
||||
mode: "auto",
|
||||
info: &infoInterfaceMock{
|
||||
HasNvmlFunc: func() (bool, string) {
|
||||
return true, "nvml"
|
||||
},
|
||||
IsTegraSystemFunc: func() (bool, string) {
|
||||
return true, "tegra"
|
||||
},
|
||||
},
|
||||
expectedMode: "legacy",
|
||||
},
|
||||
{
|
||||
description: "non-nvml tegra resolves to csv",
|
||||
mode: "auto",
|
||||
info: &infoInterfaceMock{
|
||||
HasNvmlFunc: func() (bool, string) {
|
||||
return false, "nvml"
|
||||
},
|
||||
IsTegraSystemFunc: func() (bool, string) {
|
||||
return true, "tegra"
|
||||
},
|
||||
},
|
||||
expectedMode: "csv",
|
||||
},
|
||||
{
|
||||
description: "cdi devices resolves to cdi",
|
||||
mode: "auto",
|
||||
expectedMode: "cdi",
|
||||
image: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "nvidia.com/gpu=all",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "multiple cdi devices resolves to cdi",
|
||||
mode: "auto",
|
||||
expectedMode: "cdi",
|
||||
image: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "nvidia.com/gpu=0,nvidia.com/gpu=1",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "at least one non-cdi device resolves to legacy",
|
||||
mode: "auto",
|
||||
image: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "nvidia.com/gpu=0,0",
|
||||
},
|
||||
info: &infoInterfaceMock{
|
||||
HasNvmlFunc: func() (bool, string) {
|
||||
return true, "nvml"
|
||||
},
|
||||
IsTegraSystemFunc: func() (bool, string) {
|
||||
return true, "tegra"
|
||||
},
|
||||
},
|
||||
expectedMode: "legacy",
|
||||
},
|
||||
{
|
||||
description: "at least one non-cdi device resolves to csv",
|
||||
mode: "auto",
|
||||
image: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "nvidia.com/gpu=0,0",
|
||||
},
|
||||
info: &infoInterfaceMock{
|
||||
HasNvmlFunc: func() (bool, string) {
|
||||
return false, "nvml"
|
||||
},
|
||||
IsTegraSystemFunc: func() (bool, string) {
|
||||
return true, "tegra"
|
||||
},
|
||||
},
|
||||
expectedMode: "csv",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
mode := ResolveAutoMode(logger, tc.mode)
|
||||
r := resolver{
|
||||
logger: logger,
|
||||
info: tc.info,
|
||||
}
|
||||
mode := r.resolveMode(tc.mode, tc.image)
|
||||
require.EqualValues(t, tc.expectedMode, mode)
|
||||
})
|
||||
}
|
||||
|
||||
153
internal/info/info-interface_mock.go
Normal file
153
internal/info/info-interface_mock.go
Normal file
@@ -0,0 +1,153 @@
|
||||
// Code generated by moq; DO NOT EDIT.
|
||||
// github.com/matryer/moq
|
||||
|
||||
package info
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Ensure, that infoInterfaceMock does implement infoInterface.
|
||||
// If this is not the case, regenerate this file with moq.
|
||||
var _ infoInterface = &infoInterfaceMock{}
|
||||
|
||||
// infoInterfaceMock is a mock implementation of infoInterface.
|
||||
//
|
||||
// func TestSomethingThatUsesinfoInterface(t *testing.T) {
|
||||
//
|
||||
// // make and configure a mocked infoInterface
|
||||
// mockedinfoInterface := &infoInterfaceMock{
|
||||
// HasDXCoreFunc: func() (bool, string) {
|
||||
// panic("mock out the HasDXCore method")
|
||||
// },
|
||||
// HasNvmlFunc: func() (bool, string) {
|
||||
// panic("mock out the HasNvml method")
|
||||
// },
|
||||
// IsTegraSystemFunc: func() (bool, string) {
|
||||
// panic("mock out the IsTegraSystem method")
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // use mockedinfoInterface in code that requires infoInterface
|
||||
// // and then make assertions.
|
||||
//
|
||||
// }
|
||||
type infoInterfaceMock struct {
|
||||
// HasDXCoreFunc mocks the HasDXCore method.
|
||||
HasDXCoreFunc func() (bool, string)
|
||||
|
||||
// HasNvmlFunc mocks the HasNvml method.
|
||||
HasNvmlFunc func() (bool, string)
|
||||
|
||||
// IsTegraSystemFunc mocks the IsTegraSystem method.
|
||||
IsTegraSystemFunc func() (bool, string)
|
||||
|
||||
// calls tracks calls to the methods.
|
||||
calls struct {
|
||||
// HasDXCore holds details about calls to the HasDXCore method.
|
||||
HasDXCore []struct {
|
||||
}
|
||||
// HasNvml holds details about calls to the HasNvml method.
|
||||
HasNvml []struct {
|
||||
}
|
||||
// IsTegraSystem holds details about calls to the IsTegraSystem method.
|
||||
IsTegraSystem []struct {
|
||||
}
|
||||
}
|
||||
lockHasDXCore sync.RWMutex
|
||||
lockHasNvml sync.RWMutex
|
||||
lockIsTegraSystem sync.RWMutex
|
||||
}
|
||||
|
||||
// HasDXCore calls HasDXCoreFunc.
|
||||
func (mock *infoInterfaceMock) HasDXCore() (bool, string) {
|
||||
callInfo := struct {
|
||||
}{}
|
||||
mock.lockHasDXCore.Lock()
|
||||
mock.calls.HasDXCore = append(mock.calls.HasDXCore, callInfo)
|
||||
mock.lockHasDXCore.Unlock()
|
||||
if mock.HasDXCoreFunc == nil {
|
||||
var (
|
||||
bOut bool
|
||||
sOut string
|
||||
)
|
||||
return bOut, sOut
|
||||
}
|
||||
return mock.HasDXCoreFunc()
|
||||
}
|
||||
|
||||
// HasDXCoreCalls gets all the calls that were made to HasDXCore.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedinfoInterface.HasDXCoreCalls())
|
||||
func (mock *infoInterfaceMock) HasDXCoreCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
}
|
||||
mock.lockHasDXCore.RLock()
|
||||
calls = mock.calls.HasDXCore
|
||||
mock.lockHasDXCore.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// HasNvml calls HasNvmlFunc.
|
||||
func (mock *infoInterfaceMock) HasNvml() (bool, string) {
|
||||
callInfo := struct {
|
||||
}{}
|
||||
mock.lockHasNvml.Lock()
|
||||
mock.calls.HasNvml = append(mock.calls.HasNvml, callInfo)
|
||||
mock.lockHasNvml.Unlock()
|
||||
if mock.HasNvmlFunc == nil {
|
||||
var (
|
||||
bOut bool
|
||||
sOut string
|
||||
)
|
||||
return bOut, sOut
|
||||
}
|
||||
return mock.HasNvmlFunc()
|
||||
}
|
||||
|
||||
// HasNvmlCalls gets all the calls that were made to HasNvml.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedinfoInterface.HasNvmlCalls())
|
||||
func (mock *infoInterfaceMock) HasNvmlCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
}
|
||||
mock.lockHasNvml.RLock()
|
||||
calls = mock.calls.HasNvml
|
||||
mock.lockHasNvml.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// IsTegraSystem calls IsTegraSystemFunc.
|
||||
func (mock *infoInterfaceMock) IsTegraSystem() (bool, string) {
|
||||
callInfo := struct {
|
||||
}{}
|
||||
mock.lockIsTegraSystem.Lock()
|
||||
mock.calls.IsTegraSystem = append(mock.calls.IsTegraSystem, callInfo)
|
||||
mock.lockIsTegraSystem.Unlock()
|
||||
if mock.IsTegraSystemFunc == nil {
|
||||
var (
|
||||
bOut bool
|
||||
sOut string
|
||||
)
|
||||
return bOut, sOut
|
||||
}
|
||||
return mock.IsTegraSystemFunc()
|
||||
}
|
||||
|
||||
// IsTegraSystemCalls gets all the calls that were made to IsTegraSystem.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedinfoInterface.IsTegraSystemCalls())
|
||||
func (mock *infoInterfaceMock) IsTegraSystemCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
}
|
||||
mock.lockIsTegraSystem.RLock()
|
||||
calls = mock.calls.IsTegraSystem
|
||||
mock.lockIsTegraSystem.RUnlock()
|
||||
return calls
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package devices
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -72,7 +73,14 @@ func (d devices) Get(name Name) (Major, bool) {
|
||||
|
||||
// GetNVIDIADevices returns the set of NVIDIA Devices on the machine
|
||||
func GetNVIDIADevices() (Devices, error) {
|
||||
devicesFile, err := os.Open(procDevicesPath)
|
||||
return nvidiaDevices(procDevicesPath)
|
||||
}
|
||||
|
||||
// nvidiaDevices returns the set of NVIDIA Devices from the specified devices file.
|
||||
// This is useful for testing since we may be testing on a system where `/proc/devices` does
|
||||
// contain a reference to NVIDIA devices.
|
||||
func nvidiaDevices(devicesPath string) (Devices, error) {
|
||||
devicesFile, err := os.Open(devicesPath)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -81,20 +89,28 @@ func GetNVIDIADevices() (Devices, error) {
|
||||
}
|
||||
defer devicesFile.Close()
|
||||
|
||||
return nvidiaDeviceFrom(devicesFile), nil
|
||||
return nvidiaDeviceFrom(devicesFile)
|
||||
}
|
||||
|
||||
func nvidiaDeviceFrom(reader io.Reader) devices {
|
||||
var errNoNvidiaDevices = errors.New("no NVIDIA devices found")
|
||||
|
||||
func nvidiaDeviceFrom(reader io.Reader) (devices, error) {
|
||||
allDevices := devicesFrom(reader)
|
||||
nvidiaDevices := make(devices)
|
||||
|
||||
var hasNvidiaDevices bool
|
||||
for n, d := range allDevices {
|
||||
if !strings.HasPrefix(string(n), nvidiaDevicePrefix) {
|
||||
continue
|
||||
}
|
||||
nvidiaDevices[n] = d
|
||||
hasNvidiaDevices = true
|
||||
}
|
||||
|
||||
return nvidiaDevices
|
||||
if !hasNvidiaDevices {
|
||||
return nil, errNoNvidiaDevices
|
||||
}
|
||||
return nvidiaDevices, nil
|
||||
}
|
||||
|
||||
func devicesFrom(reader io.Reader) devices {
|
||||
|
||||
@@ -45,21 +45,23 @@ func TestNvidiaDevices(t *testing.T) {
|
||||
|
||||
func TestProcessDeviceFile(t *testing.T) {
|
||||
testCases := []struct {
|
||||
lines []string
|
||||
expected devices
|
||||
lines []string
|
||||
expected devices
|
||||
expectedError error
|
||||
}{
|
||||
{[]string{}, make(devices)},
|
||||
{[]string{"Not a valid line:"}, make(devices)},
|
||||
{[]string{"195 nvidia-frontend"}, devices{"nvidia-frontend": 195}},
|
||||
{[]string{"195 nvidia-frontend", "235 nvidia-caps"}, devices{"nvidia-frontend": 195, "nvidia-caps": 235}},
|
||||
{[]string{" 195 nvidia-frontend"}, devices{"nvidia-frontend": 195}},
|
||||
{[]string{"Not a valid line:", "", "195 nvidia-frontend"}, devices{"nvidia-frontend": 195}},
|
||||
{[]string{"195 not-nvidia-frontend"}, make(devices)},
|
||||
{lines: []string{}, expectedError: errNoNvidiaDevices},
|
||||
{lines: []string{"Not a valid line:"}, expectedError: errNoNvidiaDevices},
|
||||
{lines: []string{"195 nvidia-frontend"}, expected: devices{"nvidia-frontend": 195}},
|
||||
{lines: []string{"195 nvidia-frontend", "235 nvidia-caps"}, expected: devices{"nvidia-frontend": 195, "nvidia-caps": 235}},
|
||||
{lines: []string{" 195 nvidia-frontend"}, expected: devices{"nvidia-frontend": 195}},
|
||||
{lines: []string{"Not a valid line:", "", "195 nvidia-frontend"}, expected: devices{"nvidia-frontend": 195}},
|
||||
{lines: []string{"195 not-nvidia-frontend"}, expectedError: errNoNvidiaDevices},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("testcase %d", i), func(t *testing.T) {
|
||||
contents := strings.NewReader(strings.Join(tc.lines, "\n"))
|
||||
d := nvidiaDeviceFrom(contents)
|
||||
d, err := nvidiaDeviceFrom(contents)
|
||||
require.ErrorIs(t, err, tc.expectedError)
|
||||
|
||||
require.EqualValues(t, tc.expected, d)
|
||||
})
|
||||
|
||||
@@ -29,7 +29,8 @@ import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks"
|
||||
)
|
||||
|
||||
const ldcachePath = "/etc/ld.so.cache"
|
||||
@@ -93,11 +94,11 @@ type ldcache struct {
|
||||
entries []entry2
|
||||
|
||||
root string
|
||||
logger *log.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
// New creates a new LDCache with the specified logger and root.
|
||||
func New(logger *log.Logger, root string) (LDCache, error) {
|
||||
func New(logger logger.Interface, root string) (LDCache, error) {
|
||||
path := filepath.Join(root, ldcachePath)
|
||||
|
||||
logger.Debugf("Opening ld.conf at %v", path)
|
||||
@@ -288,30 +289,20 @@ func (c *ldcache) resolve(target string) (string, error) {
|
||||
|
||||
c.logger.Debugf("checking %v", string(name))
|
||||
|
||||
info, err := os.Lstat(name)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get file info: %v", info)
|
||||
}
|
||||
if info.Mode()&os.ModeSymlink == 0 {
|
||||
c.logger.Debugf("Resolved regular file: %v", name)
|
||||
return name, nil
|
||||
}
|
||||
|
||||
link, err := os.Readlink(name)
|
||||
link, err := symlinks.Resolve(name)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to resolve symlink: %v", err)
|
||||
}
|
||||
if link == name {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// We return absolute paths for all targets
|
||||
if !filepath.IsAbs(link) || strings.HasPrefix(link, ".") {
|
||||
link = filepath.Join(filepath.Dir(target), link)
|
||||
}
|
||||
|
||||
// Ensure that the returned path is relative to the root.
|
||||
link = filepath.Join(c.root, link)
|
||||
|
||||
c.logger.Debugf("Resolved link: '%v' => '%v'", name, link)
|
||||
return link, nil
|
||||
return c.resolve(link)
|
||||
}
|
||||
|
||||
// bytesToString converts a byte slice to a string.
|
||||
|
||||
27
internal/logger/api.go
Normal file
27
internal/logger/api.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package logger
|
||||
|
||||
// Interface defines the API for the logger package
|
||||
type Interface interface {
|
||||
Debugf(string, ...interface{})
|
||||
Errorf(string, ...interface{})
|
||||
Info(...interface{})
|
||||
Infof(string, ...interface{})
|
||||
Warning(...interface{})
|
||||
Warningf(string, ...interface{})
|
||||
}
|
||||
47
internal/logger/lib.go
Normal file
47
internal/logger/lib.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package logger
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// New returns a new logger
|
||||
func New() Interface {
|
||||
return logrus.StandardLogger()
|
||||
}
|
||||
|
||||
// NullLogger is a logger that does nothing
|
||||
type NullLogger struct{}
|
||||
|
||||
var _ Interface = (*NullLogger)(nil)
|
||||
|
||||
// Debugf is a no-op for the null logger
|
||||
func (l *NullLogger) Debugf(string, ...interface{}) {}
|
||||
|
||||
// Errorf is a no-op for the null logger
|
||||
func (l *NullLogger) Errorf(string, ...interface{}) {}
|
||||
|
||||
// Info is a no-op for the null logger
|
||||
func (l *NullLogger) Info(...interface{}) {}
|
||||
|
||||
// Infof is a no-op for the null logger
|
||||
func (l *NullLogger) Infof(string, ...interface{}) {}
|
||||
|
||||
// Warning is a no-op for the null logger
|
||||
func (l *NullLogger) Warning(...interface{}) {}
|
||||
|
||||
// Warningf is a no-op for the null logger
|
||||
func (l *NullLogger) Warningf(string, ...interface{}) {}
|
||||
@@ -19,12 +19,12 @@ package cuda
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type cudaLocator struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
driverRoot string
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ type cudaLocator struct {
|
||||
type Options func(*cudaLocator)
|
||||
|
||||
// WithLogger is an option that configures the logger used by the locator.
|
||||
func WithLogger(logger *logrus.Logger) Options {
|
||||
func WithLogger(logger logger.Interface) Options {
|
||||
return func(c *cudaLocator) {
|
||||
c.logger = logger
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func New(opts ...Options) lookup.Locator {
|
||||
}
|
||||
|
||||
if c.logger == nil {
|
||||
c.logger = logrus.StandardLogger()
|
||||
c.logger = logger.New()
|
||||
}
|
||||
if c.driverRoot == "" {
|
||||
c.driverRoot = "/"
|
||||
@@ -94,6 +94,8 @@ func (l *cudaLocator) Locate(pattern string) ([]string, error) {
|
||||
"/usr/lib64",
|
||||
"/usr/lib/x86_64-linux-gnu",
|
||||
"/usr/lib/aarch64-linux-gnu",
|
||||
"/usr/lib/x86_64-linux-gnu/nvidia/current",
|
||||
"/usr/lib/aarch64-linux-gnu/nvidia/current",
|
||||
),
|
||||
lookup.WithCount(1),
|
||||
)
|
||||
|
||||
@@ -20,12 +20,12 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
)
|
||||
|
||||
// NewDirectoryLocator creates a Locator that can be used to find directories at the specified root. A logger
|
||||
// is also specified.
|
||||
func NewDirectoryLocator(logger *log.Logger, root string) Locator {
|
||||
func NewDirectoryLocator(logger logger.Interface, root string) Locator {
|
||||
return NewFileLocator(
|
||||
WithLogger(logger),
|
||||
WithRoot(root),
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
)
|
||||
|
||||
type executable struct {
|
||||
@@ -29,13 +29,13 @@ type executable struct {
|
||||
}
|
||||
|
||||
// NewExecutableLocator creates a locator to fine executable files in the path. A logger can also be specified.
|
||||
func NewExecutableLocator(logger *log.Logger, root string) Locator {
|
||||
func NewExecutableLocator(logger logger.Interface, root string) Locator {
|
||||
paths := GetPaths(root)
|
||||
|
||||
return newExecutableLocator(logger, root, paths...)
|
||||
}
|
||||
|
||||
func newExecutableLocator(logger *log.Logger, root string, paths ...string) *executable {
|
||||
func newExecutableLocator(logger logger.Interface, root string, paths ...string) *executable {
|
||||
f := newFileLocator(
|
||||
WithLogger(logger),
|
||||
WithRoot(root),
|
||||
|
||||
@@ -21,13 +21,13 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
)
|
||||
|
||||
// file can be used to locate file (or file-like elements) at a specified set of
|
||||
// prefixes. The validity of a file is determined by a filter function.
|
||||
type file struct {
|
||||
logger *log.Logger
|
||||
logger logger.Interface
|
||||
root string
|
||||
prefixes []string
|
||||
filter func(string) error
|
||||
@@ -46,7 +46,7 @@ func WithRoot(root string) Option {
|
||||
}
|
||||
|
||||
// WithLogger sets the logger for the file locator
|
||||
func WithLogger(logger *log.Logger) Option {
|
||||
func WithLogger(logger logger.Interface) Option {
|
||||
return func(f *file) {
|
||||
f.logger = logger
|
||||
}
|
||||
@@ -93,7 +93,7 @@ func newFileLocator(opts ...Option) *file {
|
||||
opt(f)
|
||||
}
|
||||
if f.logger == nil {
|
||||
f.logger = log.StandardLogger()
|
||||
f.logger = logger.New()
|
||||
}
|
||||
if f.filter == nil {
|
||||
f.filter = assertFile
|
||||
|
||||
@@ -21,11 +21,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
)
|
||||
|
||||
type library struct {
|
||||
logger *log.Logger
|
||||
logger logger.Interface
|
||||
symlink Locator
|
||||
cache ldcache.LDCache
|
||||
}
|
||||
@@ -33,7 +33,7 @@ type library struct {
|
||||
var _ Locator = (*library)(nil)
|
||||
|
||||
// NewLibraryLocator creates a library locator using the specified logger.
|
||||
func NewLibraryLocator(logger *log.Logger, root string) (Locator, error) {
|
||||
func NewLibraryLocator(logger logger.Interface, root string) (Locator, error) {
|
||||
cache, err := ldcache.New(logger, root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading ldcache: %v", err)
|
||||
@@ -58,7 +58,7 @@ func (l library) Locate(libname string) ([]string, error) {
|
||||
|
||||
paths32, paths64 := l.cache.Lookup(libname)
|
||||
if len(paths32) > 0 {
|
||||
l.logger.Warnf("Ignoring 32-bit libraries for %v: %v", libname, paths32)
|
||||
l.logger.Warningf("Ignoring 32-bit libraries for %v: %v", libname, paths32)
|
||||
}
|
||||
|
||||
if len(paths64) == 0 {
|
||||
|
||||
@@ -13,29 +13,23 @@ var _ Locator = &LocatorMock{}
|
||||
|
||||
// LocatorMock is a mock implementation of Locator.
|
||||
//
|
||||
// func TestSomethingThatUsesLocator(t *testing.T) {
|
||||
// func TestSomethingThatUsesLocator(t *testing.T) {
|
||||
//
|
||||
// // make and configure a mocked Locator
|
||||
// mockedLocator := &LocatorMock{
|
||||
// LocateFunc: func(s string) ([]string, error) {
|
||||
// panic("mock out the Locate method")
|
||||
// },
|
||||
// RelativeFunc: func(s string) (string, error) {
|
||||
// panic("mock out the Relative method")
|
||||
// },
|
||||
// }
|
||||
// // make and configure a mocked Locator
|
||||
// mockedLocator := &LocatorMock{
|
||||
// LocateFunc: func(s string) ([]string, error) {
|
||||
// panic("mock out the Locate method")
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // use mockedLocator in code that requires Locator
|
||||
// // and then make assertions.
|
||||
// // use mockedLocator in code that requires Locator
|
||||
// // and then make assertions.
|
||||
//
|
||||
// }
|
||||
// }
|
||||
type LocatorMock struct {
|
||||
// LocateFunc mocks the Locate method.
|
||||
LocateFunc func(s string) ([]string, error)
|
||||
|
||||
// RelativeFunc mocks the Relative method.
|
||||
RelativeFunc func(s string) (string, error)
|
||||
|
||||
// calls tracks calls to the methods.
|
||||
calls struct {
|
||||
// Locate holds details about calls to the Locate method.
|
||||
@@ -43,14 +37,8 @@ type LocatorMock struct {
|
||||
// S is the s argument value.
|
||||
S string
|
||||
}
|
||||
// Relative holds details about calls to the Relative method.
|
||||
Relative []struct {
|
||||
// S is the s argument value.
|
||||
S string
|
||||
}
|
||||
}
|
||||
lockLocate sync.RWMutex
|
||||
lockRelative sync.RWMutex
|
||||
lockLocate sync.RWMutex
|
||||
}
|
||||
|
||||
// Locate calls LocateFunc.
|
||||
@@ -75,7 +63,8 @@ func (mock *LocatorMock) Locate(s string) ([]string, error) {
|
||||
|
||||
// LocateCalls gets all the calls that were made to Locate.
|
||||
// Check the length with:
|
||||
// len(mockedLocator.LocateCalls())
|
||||
//
|
||||
// len(mockedLocator.LocateCalls())
|
||||
func (mock *LocatorMock) LocateCalls() []struct {
|
||||
S string
|
||||
} {
|
||||
@@ -87,38 +76,3 @@ func (mock *LocatorMock) LocateCalls() []struct {
|
||||
mock.lockLocate.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Relative calls RelativeFunc.
|
||||
func (mock *LocatorMock) Relative(s string) (string, error) {
|
||||
callInfo := struct {
|
||||
S string
|
||||
}{
|
||||
S: s,
|
||||
}
|
||||
mock.lockRelative.Lock()
|
||||
mock.calls.Relative = append(mock.calls.Relative, callInfo)
|
||||
mock.lockRelative.Unlock()
|
||||
if mock.RelativeFunc == nil {
|
||||
var (
|
||||
sOut string
|
||||
errOut error
|
||||
)
|
||||
return sOut, errOut
|
||||
}
|
||||
return mock.RelativeFunc(s)
|
||||
}
|
||||
|
||||
// RelativeCalls gets all the calls that were made to Relative.
|
||||
// Check the length with:
|
||||
// len(mockedLocator.RelativeCalls())
|
||||
func (mock *LocatorMock) RelativeCalls() []struct {
|
||||
S string
|
||||
} {
|
||||
var calls []struct {
|
||||
S string
|
||||
}
|
||||
mock.lockRelative.RLock()
|
||||
calls = mock.calls.Relative
|
||||
mock.lockRelative.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ package lookup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks"
|
||||
)
|
||||
|
||||
type symlinkChain struct {
|
||||
@@ -34,7 +34,7 @@ type symlink struct {
|
||||
|
||||
// NewSymlinkChainLocator creats a locator that can be used for locating files through symlinks.
|
||||
// A logger can also be specified.
|
||||
func NewSymlinkChainLocator(logger *logrus.Logger, root string) Locator {
|
||||
func NewSymlinkChainLocator(logger logger.Interface, root string) Locator {
|
||||
f := newFileLocator(WithLogger(logger), WithRoot(root))
|
||||
l := symlinkChain{
|
||||
file: *f,
|
||||
@@ -45,7 +45,7 @@ func NewSymlinkChainLocator(logger *logrus.Logger, root string) Locator {
|
||||
|
||||
// NewSymlinkLocator creats a locator that can be used for locating files through symlinks.
|
||||
// A logger can also be specified.
|
||||
func NewSymlinkLocator(logger *logrus.Logger, root string) Locator {
|
||||
func NewSymlinkLocator(logger logger.Interface, root string) Locator {
|
||||
f := newFileLocator(WithLogger(logger), WithRoot(root))
|
||||
l := symlink{
|
||||
file: *f,
|
||||
@@ -74,16 +74,9 @@ func (p symlinkChain) Locate(pattern string) ([]string, error) {
|
||||
}
|
||||
found[candidate] = true
|
||||
|
||||
info, err := os.Lstat(candidate)
|
||||
target, err := symlinks.Resolve(candidate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get file info: %v", info)
|
||||
}
|
||||
if info.Mode()&os.ModeSymlink == 0 {
|
||||
continue
|
||||
}
|
||||
target, err := os.Readlink(candidate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error checking symlink: %v", err)
|
||||
return nil, fmt.Errorf("error resolving symlink: %v", err)
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(target) {
|
||||
|
||||
35
internal/lookup/symlinks/symlink.go
Normal file
35
internal/lookup/symlinks/symlink.go
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
**/
|
||||
|
||||
package symlinks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Resolve returns the link target of the specified filename or the filename if it is not a link.
|
||||
func Resolve(filename string) (string, error) {
|
||||
info, err := os.Lstat(filename)
|
||||
if err != nil {
|
||||
return filename, fmt.Errorf("failed to get file info: %v", info)
|
||||
}
|
||||
if info.Mode()&os.ModeSymlink == 0 {
|
||||
return filename, nil
|
||||
}
|
||||
|
||||
return os.Readlink(filename)
|
||||
}
|
||||
@@ -22,14 +22,14 @@ import (
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
cdi "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type cdiModifier struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
specDirs []string
|
||||
devices []string
|
||||
}
|
||||
@@ -37,7 +37,7 @@ type cdiModifier struct {
|
||||
// NewCDIModifier creates an OCI spec modifier that determines the modifications to make based on the
|
||||
// CDI specifications available on the system. The NVIDIA_VISIBLE_DEVICES enviroment variable is
|
||||
// used to select the devices to include.
|
||||
func NewCDIModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
||||
func NewCDIModifier(logger logger.Interface, cfg *config.Config, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
||||
devices, err := getDevicesFromSpec(logger, ociSpec, cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get required devices from OCI specification: %v", err)
|
||||
@@ -62,7 +62,7 @@ func NewCDIModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec)
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func getDevicesFromSpec(logger *logrus.Logger, ociSpec oci.Spec, cfg *config.Config) ([]string, error) {
|
||||
func getDevicesFromSpec(logger logger.Interface, ociSpec oci.Spec, cfg *config.Config) ([]string, error) {
|
||||
rawSpec, err := ociSpec.Load()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load OCI spec: %v", err)
|
||||
|
||||
@@ -24,14 +24,15 @@ import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/cuda"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover/csv"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover/tegra"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/requirements"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// csvMode represents the modifications as performed by the csv runtime mode
|
||||
type csvMode struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
discoverer discover.Discover
|
||||
}
|
||||
|
||||
@@ -44,7 +45,7 @@ const (
|
||||
|
||||
// NewCSVModifier creates a modifier that applies modications to an OCI spec if required by the runtime wrapper.
|
||||
// The modifications are defined by CSV MountSpecs.
|
||||
func NewCSVModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
||||
func NewCSVModifier(logger logger.Interface, cfg *config.Config, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
||||
rawSpec, err := ociSpec.Load()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load OCI spec: %v", err)
|
||||
@@ -61,11 +62,6 @@ func NewCSVModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec)
|
||||
}
|
||||
logger.Infof("Constructing modifier from config: %+v", *cfg)
|
||||
|
||||
config := &discover.Config{
|
||||
DriverRoot: cfg.NVIDIAContainerCLIConfig.Root,
|
||||
NvidiaCTKPath: cfg.NVIDIACTKConfig.Path,
|
||||
}
|
||||
|
||||
if err := checkRequirements(logger, image); err != nil {
|
||||
return nil, fmt.Errorf("requirements not met: %v", err)
|
||||
}
|
||||
@@ -79,27 +75,15 @@ func NewCSVModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec)
|
||||
csvFiles = csv.BaseFilesOnly(csvFiles)
|
||||
}
|
||||
|
||||
csvDiscoverer, err := discover.NewFromCSVFiles(logger, csvFiles, config.DriverRoot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create CSV discoverer: %v", err)
|
||||
}
|
||||
|
||||
createSymlinksHook, err := discover.NewCreateSymlinksHook(logger, csvFiles, csvDiscoverer, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create symlink hook discoverer: %v", err)
|
||||
}
|
||||
|
||||
ldcacheUpdateHook, err := discover.NewLDCacheUpdateHook(logger, csvDiscoverer, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ldcach update hook discoverer: %v", err)
|
||||
}
|
||||
|
||||
d := discover.Merge(
|
||||
csvDiscoverer,
|
||||
createSymlinksHook,
|
||||
// The ldcacheUpdateHook is added last to ensure that the created symlinks are included
|
||||
ldcacheUpdateHook,
|
||||
d, err := tegra.New(
|
||||
tegra.WithLogger(logger),
|
||||
tegra.WithDriverRoot(cfg.NVIDIAContainerCLIConfig.Root),
|
||||
tegra.WithNVIDIACTKPath(cfg.NVIDIACTKConfig.Path),
|
||||
tegra.WithCSVFiles(csvFiles),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct discoverer: %v", err)
|
||||
}
|
||||
|
||||
discoverModifier, err := NewModifierFromDiscoverer(logger, d)
|
||||
if err != nil {
|
||||
@@ -114,7 +98,7 @@ func NewCSVModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec)
|
||||
return modifiers, nil
|
||||
}
|
||||
|
||||
func checkRequirements(logger *logrus.Logger, image image.CUDA) error {
|
||||
func checkRequirements(logger logger.Interface, image image.CUDA) error {
|
||||
if image.HasDisableRequire() {
|
||||
// TODO: We could print the real value here instead
|
||||
logger.Debugf("NVIDIA_DISABLE_REQUIRE=%v; skipping requirement checks", true)
|
||||
@@ -131,14 +115,14 @@ func checkRequirements(logger *logrus.Logger, image image.CUDA) error {
|
||||
|
||||
cudaVersion, err := cuda.Version()
|
||||
if err != nil {
|
||||
logger.Warnf("Failed to get CUDA version: %v", err)
|
||||
logger.Warningf("Failed to get CUDA version: %v", err)
|
||||
} else {
|
||||
r.AddVersionProperty(requirements.CUDA, cudaVersion)
|
||||
}
|
||||
|
||||
compteCapability, err := cuda.ComputeCapability(0)
|
||||
if err != nil {
|
||||
logger.Warnf("Failed to get CUDA Compute Capability: %v", err)
|
||||
logger.Warningf("Failed to get CUDA Compute Capability: %v", err)
|
||||
} else {
|
||||
r.AddVersionProperty(requirements.ARCH, compteCapability)
|
||||
}
|
||||
|
||||
@@ -21,19 +21,19 @@ import (
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/edits"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type discoverModifier struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
discoverer discover.Discover
|
||||
}
|
||||
|
||||
// NewModifierFromDiscoverer creates a modifier that applies the discovered
|
||||
// modifications to an OCI spec if required by the runtime wrapper.
|
||||
func NewModifierFromDiscoverer(logger *logrus.Logger, d discover.Discover) (oci.SpecModifier, error) {
|
||||
func NewModifierFromDiscoverer(logger logger.Interface, d discover.Discover) (oci.SpecModifier, error) {
|
||||
m := discoverModifier{
|
||||
logger: logger,
|
||||
discoverer: d,
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -32,17 +32,7 @@ const (
|
||||
|
||||
// NewGDSModifier creates the modifiers for GDS devices.
|
||||
// If the spec does not contain the NVIDIA_GDS=enabled environment variable no changes are made.
|
||||
func NewGDSModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
||||
rawSpec, err := ociSpec.Load()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load OCI spec: %v", err)
|
||||
}
|
||||
|
||||
image, err := image.NewCUDAImageFromSpec(rawSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func NewGDSModifier(logger logger.Interface, cfg *config.Config, image image.CUDA) (oci.SpecModifier, error) {
|
||||
if devices := image.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices.List()) == 0 {
|
||||
logger.Infof("No modification required; no devices requested")
|
||||
return nil, nil
|
||||
|
||||
@@ -22,36 +22,23 @@ import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// NewGraphicsModifier constructs a modifier that injects graphics-related modifications into an OCI runtime specification.
|
||||
// The value of the NVIDIA_DRIVER_CAPABILITIES environment variable is checked to determine if this modification should be made.
|
||||
func NewGraphicsModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
||||
rawSpec, err := ociSpec.Load()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load OCI spec: %v", err)
|
||||
}
|
||||
|
||||
image, err := image.NewCUDAImageFromSpec(rawSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func NewGraphicsModifier(logger logger.Interface, cfg *config.Config, image image.CUDA) (oci.SpecModifier, error) {
|
||||
if required, reason := requiresGraphicsModifier(image); !required {
|
||||
logger.Infof("No graphics modifier required: %v", reason)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
config := &discover.Config{
|
||||
DriverRoot: cfg.NVIDIAContainerCLIConfig.Root,
|
||||
NvidiaCTKPath: cfg.NVIDIACTKConfig.Path,
|
||||
}
|
||||
d, err := discover.NewGraphicsDiscoverer(
|
||||
logger,
|
||||
image.DevicesFromEnvvars(visibleDevicesEnvvar),
|
||||
config,
|
||||
cfg.NVIDIAContainerCLIConfig.Root,
|
||||
cfg.NVIDIACTKConfig.Path,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct discoverer: %v", err)
|
||||
|
||||
@@ -20,14 +20,14 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// nvidiaContainerRuntimeHookRemover is a spec modifer that detects and removes inserted nvidia-container-runtime hooks
|
||||
type nvidiaContainerRuntimeHookRemover struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
}
|
||||
|
||||
var _ oci.SpecModifier = (*nvidiaContainerRuntimeHookRemover)(nil)
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -32,17 +32,7 @@ const (
|
||||
|
||||
// NewMOFEDModifier creates the modifiers for MOFED devices.
|
||||
// If the spec does not contain the NVIDIA_MOFED=enabled environment variable no changes are made.
|
||||
func NewMOFEDModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
||||
rawSpec, err := ociSpec.Load()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load OCI spec: %v", err)
|
||||
}
|
||||
|
||||
image, err := image.NewCUDAImageFromSpec(rawSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func NewMOFEDModifier(logger logger.Interface, cfg *config.Config, image image.CUDA) (oci.SpecModifier, error) {
|
||||
if devices := image.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices.List()) == 0 {
|
||||
logger.Infof("No modification required; no devices requested")
|
||||
return nil, nil
|
||||
|
||||
@@ -17,19 +17,20 @@
|
||||
package modifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// NewStableRuntimeModifier creates an OCI spec modifier that inserts the NVIDIA Container Runtime Hook into an OCI
|
||||
// spec. The specified logger is used to capture log output.
|
||||
func NewStableRuntimeModifier(logger *logrus.Logger) oci.SpecModifier {
|
||||
m := stableRuntimeModifier{logger: logger}
|
||||
func NewStableRuntimeModifier(logger logger.Interface, nvidiaContainerRuntimeHookPath string) oci.SpecModifier {
|
||||
m := stableRuntimeModifier{
|
||||
logger: logger,
|
||||
nvidiaContainerRuntimeHookPath: nvidiaContainerRuntimeHookPath,
|
||||
}
|
||||
|
||||
return &m
|
||||
}
|
||||
@@ -37,7 +38,8 @@ func NewStableRuntimeModifier(logger *logrus.Logger) oci.SpecModifier {
|
||||
// stableRuntimeModifier modifies an OCI spec inplace, inserting the nvidia-container-runtime-hook as a
|
||||
// prestart hook. If the hook is already present, no modification is made.
|
||||
type stableRuntimeModifier struct {
|
||||
logger *logrus.Logger
|
||||
logger logger.Interface
|
||||
nvidiaContainerRuntimeHookPath string
|
||||
}
|
||||
|
||||
// Modify applies the required modification to the incoming OCI spec, inserting the nvidia-container-runtime-hook
|
||||
@@ -53,18 +55,9 @@ func (m stableRuntimeModifier) Modify(spec *specs.Spec) error {
|
||||
}
|
||||
}
|
||||
|
||||
// We create a locator and look for the NVIDIA Container Runtime Hook in the path.
|
||||
candidates, err := lookup.NewExecutableLocator(m.logger, "").Locate(config.NVIDIAContainerRuntimeHookExecutable)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to locate NVIDIA Container Runtime Hook: %v", err)
|
||||
}
|
||||
path := candidates[0]
|
||||
if len(candidates) > 1 {
|
||||
m.logger.Debugf("Using %v from multiple NVIDIA Container Runtime Hook candidates: %v", path, candidates)
|
||||
}
|
||||
|
||||
path := m.nvidiaContainerRuntimeHookPath
|
||||
m.logger.Infof("Using prestart hook path: %v", path)
|
||||
args := []string{path}
|
||||
args := []string{filepath.Base(path)}
|
||||
if spec.Hooks == nil {
|
||||
spec.Hooks = &specs.Hooks{}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user