mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2025-06-26 18:18:24 +00:00
Compare commits
110 Commits
v1.11.0-rc
...
v1.12.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
217a135eb1 | ||
|
|
22e65b320b | ||
|
|
53bb940b30 | ||
|
|
1c1ad8098a | ||
|
|
203db4390c | ||
|
|
b6d9c2c1ad | ||
|
|
429ef4d4e9 | ||
|
|
25759ca933 | ||
|
|
74abea07e2 | ||
|
|
7955bb1a84 | ||
|
|
75b11eb80a | ||
|
|
c958817eef | ||
|
|
80f8c2a418 | ||
|
|
08640a6f64 | ||
|
|
9db31f7506 | ||
|
|
7fd40632fe | ||
|
|
6ef19d2925 | ||
|
|
83ce83239b | ||
|
|
30fb486e44 | ||
|
|
0022661565 | ||
|
|
28e882f26f | ||
|
|
71fbe7a812 | ||
|
|
ce3d94af1a | ||
|
|
0bc09665a8 | ||
|
|
205ba098e9 | ||
|
|
877832da69 | ||
|
|
b7ba96a72e | ||
|
|
93c59f2d9c | ||
|
|
5a56b658ba | ||
|
|
99889671b5 | ||
|
|
a2fb017208 | ||
|
|
f7021d84b5 | ||
|
|
c793fc27d8 | ||
|
|
3d2328bdfd | ||
|
|
76b69f45de | ||
|
|
73e65edaa9 | ||
|
|
cd7ee5a435 | ||
|
|
eac4faddc6 | ||
|
|
bc8a73dde4 | ||
|
|
624b9d8ee6 | ||
|
|
9d6e2ff1b0 | ||
|
|
aca0c7bc5a | ||
|
|
db47b58275 | ||
|
|
59bf7607ce | ||
|
|
61ff3fbd7b | ||
|
|
523fc57ab4 | ||
|
|
ae18c5d847 | ||
|
|
4abdc2f35d | ||
|
|
f8748bfa9a | ||
|
|
5fb0ae2c2d | ||
|
|
899fc72014 | ||
|
|
1267c1d9a2 | ||
|
|
9a697e340b | ||
|
|
abe8ca71e0 | ||
|
|
9bbf7dcf96 | ||
|
|
ec1222b58b | ||
|
|
229b46e0ca | ||
|
|
b6a68c4add | ||
|
|
e588bfac7d | ||
|
|
224020533e | ||
|
|
3736bb3aca | ||
|
|
1e72f92b74 | ||
|
|
896f5b2e9f | ||
|
|
c068d4048f | ||
|
|
8796cd76b0 | ||
|
|
1597ede2af | ||
|
|
3dd8020695 | ||
|
|
dfa041991f | ||
|
|
568896742b | ||
|
|
f52973217f | ||
|
|
efd29f1cec | ||
|
|
4b02670049 | ||
|
|
8550874686 | ||
|
|
38513d5a53 | ||
|
|
a35236a8f6 | ||
|
|
0c2e72b7c1 | ||
|
|
f0bdfbebe4 | ||
|
|
a4fa61d05d | ||
|
|
6e23a635c6 | ||
|
|
4dedac6a24 | ||
|
|
8c1b9b33c1 | ||
|
|
d37c17857e | ||
|
|
a0065456d0 | ||
|
|
a34a571d2e | ||
|
|
bb4cfece61 | ||
|
|
b16d263ee7 | ||
|
|
027395bb8a | ||
|
|
3ecd790206 | ||
|
|
52bb9e186b | ||
|
|
68b6d1cab1 | ||
|
|
bdb67b4fba | ||
|
|
d0c39a11d5 | ||
|
|
9de6361938 | ||
|
|
fb016dca86 | ||
|
|
8beb7b4231 | ||
|
|
2b08a79206 | ||
|
|
5885fead8f | ||
|
|
a9fb7a4a88 | ||
|
|
b5dbcaeaf9 | ||
|
|
80a46d4a5c | ||
|
|
febce822d5 | ||
|
|
e8099a713c | ||
|
|
d9de4a09b8 | ||
|
|
2dbcda2619 | ||
|
|
691b93ffb0 | ||
|
|
cb0c94cd40 | ||
|
|
3168718563 | ||
|
|
dc8972a26a | ||
|
|
0a2d8f4d22 | ||
|
|
8d623967ed |
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2021-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.
|
||||
@@ -34,55 +34,91 @@ stages:
|
||||
- scan
|
||||
- release
|
||||
|
||||
.main-or-manual:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
- if: $CI_COMMIT_TAG && $CI_COMMIT_TAG != ""
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
when: manual
|
||||
|
||||
# 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-debian9:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: debian9
|
||||
PACKAGE_REPO_TYPE: debian
|
||||
|
||||
.dist-fedora35:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: fedora35
|
||||
PACKAGE_REPO_TYPE: rpm
|
||||
|
||||
.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-ubuntu16.04:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: ubuntu16.04
|
||||
PACKAGE_REPO_TYPE: debian
|
||||
|
||||
.dist-ubuntu18.04:
|
||||
variables:
|
||||
DIST: ubuntu18.04
|
||||
CVE_UPDATES: "libsasl2-2 libsasl2-modules-db"
|
||||
PACKAGE_REPO_TYPE: debian
|
||||
|
||||
.dist-ubuntu20.04:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
DIST: ubuntu20.04
|
||||
CVE_UPDATES: "libsasl2-2 libsasl2-modules-db"
|
||||
PACKAGE_REPO_TYPE: debian
|
||||
|
||||
.dist-packaging:
|
||||
variables:
|
||||
@@ -102,6 +138,8 @@ stages:
|
||||
ARCH: arm64
|
||||
|
||||
.arch-ppc64le:
|
||||
rules:
|
||||
- !reference [.main-or-manual, rules]
|
||||
variables:
|
||||
ARCH: ppc64le
|
||||
|
||||
@@ -142,7 +180,7 @@ test-packaging:
|
||||
# Download the regctl binary for use in the release steps
|
||||
.regctl-setup:
|
||||
before_script:
|
||||
- export REGCTL_VERSION=v0.3.10
|
||||
- export REGCTL_VERSION=v0.4.5
|
||||
- apk add --no-cache curl
|
||||
- mkdir -p bin
|
||||
- curl -sSLo bin/regctl https://github.com/regclient/regclient/releases/download/${REGCTL_VERSION}/regctl-linux-amd64
|
||||
@@ -236,10 +274,7 @@ release:staging-ubuntu20.04:
|
||||
- .release:staging
|
||||
- .dist-ubuntu20.04
|
||||
needs:
|
||||
- test-toolkit-ubuntu20.04
|
||||
- test-containerd-ubuntu20.04
|
||||
- test-crio-ubuntu20.04
|
||||
- test-docker-ubuntu20.04
|
||||
- image-ubuntu20.04
|
||||
|
||||
release:staging-packaging:
|
||||
extends:
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,6 +4,8 @@ dist
|
||||
/coverage.out*
|
||||
/test/output/
|
||||
/nvidia-container-runtime
|
||||
/nvidia-container-runtime-hook
|
||||
/nvidia-container-toolkit
|
||||
/nvidia-ctk
|
||||
/shared-*
|
||||
/release-*
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2019-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.
|
||||
@@ -262,7 +262,8 @@ image-ubuntu18.04:
|
||||
needs:
|
||||
- package-ubuntu18.04-amd64
|
||||
- package-ubuntu18.04-arm64
|
||||
- package-ubuntu18.04-ppc64le
|
||||
- job: package-ubuntu18.04-ppc64le
|
||||
optional: true
|
||||
|
||||
image-ubuntu20.04:
|
||||
extends:
|
||||
@@ -281,23 +282,36 @@ image-packaging:
|
||||
- .package-artifacts
|
||||
- .dist-packaging
|
||||
needs:
|
||||
- package-amazonlinux2-aarch64
|
||||
- package-amazonlinux2-x86_64
|
||||
- package-centos7-ppc64le
|
||||
- package-centos7-x86_64
|
||||
- package-centos8-aarch64
|
||||
- package-centos8-ppc64le
|
||||
- package-centos8-x86_64
|
||||
- package-debian10-amd64
|
||||
- package-debian9-amd64
|
||||
- package-fedora35-aarch64
|
||||
- package-fedora35-x86_64
|
||||
- package-opensuse-leap15.1-x86_64
|
||||
- package-ubuntu16.04-amd64
|
||||
- package-ubuntu16.04-ppc64le
|
||||
- package-ubuntu18.04-amd64
|
||||
- package-ubuntu18.04-arm64
|
||||
- package-ubuntu18.04-ppc64le
|
||||
- job: package-centos8-aarch64
|
||||
- job: package-centos8-x86_64
|
||||
- job: package-ubuntu18.04-amd64
|
||||
- job: package-ubuntu18.04-arm64
|
||||
- job: package-amazonlinux2-aarch64
|
||||
optional: true
|
||||
- job: package-amazonlinux2-x86_64
|
||||
optional: true
|
||||
- job: package-centos7-ppc64le
|
||||
optional: true
|
||||
- job: package-centos7-x86_64
|
||||
optional: true
|
||||
- job: package-centos8-ppc64le
|
||||
optional: true
|
||||
- job: package-debian10-amd64
|
||||
optional: true
|
||||
- job: package-debian9-amd64
|
||||
optional: true
|
||||
- job: package-fedora35-aarch64
|
||||
optional: true
|
||||
- job: package-fedora35-x86_64
|
||||
optional: true
|
||||
- job: package-opensuse-leap15.1-x86_64
|
||||
optional: true
|
||||
- job: package-ubuntu16.04-amd64
|
||||
optional: true
|
||||
- job: package-ubuntu16.04-ppc64le
|
||||
optional: true
|
||||
- job: package-ubuntu18.04-ppc64le
|
||||
optional: true
|
||||
|
||||
# Define publish test helpers
|
||||
.test:toolkit:
|
||||
@@ -357,31 +371,3 @@ test-docker-ubuntu18.04:
|
||||
needs:
|
||||
- image-ubuntu18.04
|
||||
|
||||
test-toolkit-ubuntu20.04:
|
||||
extends:
|
||||
- .test:toolkit
|
||||
- .dist-ubuntu20.04
|
||||
needs:
|
||||
- image-ubuntu20.04
|
||||
|
||||
test-containerd-ubuntu20.04:
|
||||
extends:
|
||||
- .test:containerd
|
||||
- .dist-ubuntu20.04
|
||||
needs:
|
||||
- image-ubuntu20.04
|
||||
|
||||
test-crio-ubuntu20.04:
|
||||
extends:
|
||||
- .test:crio
|
||||
- .dist-ubuntu20.04
|
||||
needs:
|
||||
- image-ubuntu20.04
|
||||
|
||||
test-docker-ubuntu20.04:
|
||||
extends:
|
||||
- .test:docker
|
||||
- .dist-ubuntu20.04
|
||||
needs:
|
||||
- image-ubuntu20.04
|
||||
|
||||
|
||||
179
.nvidia-ci.yml
179
.nvidia-ci.yml
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2021-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.
|
||||
@@ -35,6 +35,9 @@ variables:
|
||||
# Define the public staging registry
|
||||
STAGING_REGISTRY: registry.gitlab.com/nvidia/container-toolkit/container-toolkit/staging
|
||||
STAGING_VERSION: ${CI_COMMIT_SHORT_SHA}
|
||||
ARTIFACTORY_REPO_BASE: "https://urm.nvidia.com/artifactory/sw-gpu-cloudnative"
|
||||
# TODO: We should set the kitmaker release folder here once we have the end-to-end workflow set up
|
||||
KITMAKER_RELEASE_FOLDER: "testing"
|
||||
|
||||
.image-pull:
|
||||
stage: image-build
|
||||
@@ -48,8 +51,9 @@ variables:
|
||||
OUT_IMAGE_NAME: "${CI_REGISTRY_IMAGE}/container-toolkit"
|
||||
PUSH_MULTIPLE_TAGS: "false"
|
||||
# We delay the job start to allow the public pipeline to generate the required images.
|
||||
when: delayed
|
||||
start_in: 30 minutes
|
||||
rules:
|
||||
- when: delayed
|
||||
start_in: 30 minutes
|
||||
timeout: 30 minutes
|
||||
retry:
|
||||
max: 2
|
||||
@@ -67,29 +71,132 @@ variables:
|
||||
|
||||
image-centos7:
|
||||
extends:
|
||||
- .image-pull
|
||||
- .dist-centos7
|
||||
- .image-pull
|
||||
|
||||
image-ubi8:
|
||||
extends:
|
||||
- .image-pull
|
||||
- .dist-ubi8
|
||||
- .image-pull
|
||||
|
||||
image-ubuntu18.04:
|
||||
extends:
|
||||
- .image-pull
|
||||
- .dist-ubuntu18.04
|
||||
- .image-pull
|
||||
|
||||
image-ubuntu20.04:
|
||||
extends:
|
||||
- .image-pull
|
||||
- .dist-ubuntu20.04
|
||||
- .image-pull
|
||||
|
||||
# The DIST=packaging target creates an image containing all built packages
|
||||
image-packaging:
|
||||
extends:
|
||||
- .image-pull
|
||||
- .dist-packaging
|
||||
- .image-pull
|
||||
|
||||
# Define the package release targets
|
||||
release:packages:amazonlinux2-aarch64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-amazonlinux2
|
||||
- .arch-aarch64
|
||||
|
||||
release:packages:amazonlinux2-x86_64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-amazonlinux2
|
||||
- .arch-x86_64
|
||||
|
||||
release:packages:centos7-ppc64le:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-centos7
|
||||
- .arch-ppc64le
|
||||
|
||||
release:packages:centos7-x86_64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-centos7
|
||||
- .arch-x86_64
|
||||
|
||||
release:packages:centos8-aarch64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-centos8
|
||||
- .arch-aarch64
|
||||
|
||||
release:packages:centos8-ppc64le:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-centos8
|
||||
- .arch-ppc64le
|
||||
|
||||
release:packages:centos8-x86_64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-centos8
|
||||
- .arch-x86_64
|
||||
|
||||
release:packages:debian10-amd64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-debian10
|
||||
- .arch-amd64
|
||||
|
||||
release:packages:debian9-amd64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-debian9
|
||||
- .arch-amd64
|
||||
|
||||
release:packages:fedora35-aarch64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-fedora35
|
||||
- .arch-aarch64
|
||||
|
||||
release:packages:fedora35-x86_64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-fedora35
|
||||
- .arch-x86_64
|
||||
|
||||
release:packages:opensuse-leap15.1-x86_64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-opensuse-leap15.1
|
||||
- .arch-x86_64
|
||||
|
||||
release:packages:ubuntu16.04-amd64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-ubuntu16.04
|
||||
- .arch-amd64
|
||||
|
||||
release:packages:ubuntu16.04-ppc64le:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-ubuntu16.04
|
||||
- .arch-ppc64le
|
||||
|
||||
release:packages:ubuntu18.04-amd64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-ubuntu18.04
|
||||
- .arch-amd64
|
||||
|
||||
release:packages:ubuntu18.04-arm64:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-ubuntu18.04
|
||||
- .arch-arm64
|
||||
|
||||
release:packages:ubuntu18.04-ppc64le:
|
||||
extends:
|
||||
- .release:packages
|
||||
- .dist-ubuntu18.04
|
||||
- .arch-ppc64le
|
||||
|
||||
# We skip the integration tests for the internal CI:
|
||||
.integration:
|
||||
@@ -107,9 +214,9 @@ image-packaging:
|
||||
variables:
|
||||
IMAGE: "${CI_REGISTRY_IMAGE}/container-toolkit:${CI_COMMIT_SHORT_SHA}-${DIST}"
|
||||
IMAGE_ARCHIVE: "container-toolkit.tar"
|
||||
except:
|
||||
variables:
|
||||
- $SKIP_SCANS && $SKIP_SCANS == "yes"
|
||||
rules:
|
||||
- if: $SKIP_SCANS != "yes"
|
||||
- when: manual
|
||||
before_script:
|
||||
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"
|
||||
# TODO: We should specify the architecture here and scan all architectures
|
||||
@@ -134,59 +241,59 @@ image-packaging:
|
||||
# Define the scan targets
|
||||
scan-centos7-amd64:
|
||||
extends:
|
||||
- .scan
|
||||
- .dist-centos7
|
||||
- .platform-amd64
|
||||
- .scan
|
||||
needs:
|
||||
- image-centos7
|
||||
|
||||
scan-centos7-arm64:
|
||||
extends:
|
||||
- .scan
|
||||
- .dist-centos7
|
||||
- .platform-arm64
|
||||
- .scan
|
||||
needs:
|
||||
- image-centos7
|
||||
- scan-centos7-amd64
|
||||
|
||||
scan-ubuntu18.04-amd64:
|
||||
extends:
|
||||
- .scan
|
||||
- .dist-ubuntu18.04
|
||||
- .platform-amd64
|
||||
- .scan
|
||||
needs:
|
||||
- image-ubuntu18.04
|
||||
|
||||
scan-ubuntu20.04-amd64:
|
||||
extends:
|
||||
- .scan
|
||||
- .dist-ubuntu20.04
|
||||
- .platform-amd64
|
||||
- .scan
|
||||
needs:
|
||||
- image-ubuntu20.04
|
||||
|
||||
scan-ubuntu20.04-arm64:
|
||||
extends:
|
||||
- .scan
|
||||
- .dist-ubuntu20.04
|
||||
- .platform-arm64
|
||||
- .scan
|
||||
needs:
|
||||
- image-ubuntu20.04
|
||||
- scan-ubuntu20.04-amd64
|
||||
|
||||
scan-ubi8-amd64:
|
||||
extends:
|
||||
- .scan
|
||||
- .dist-ubi8
|
||||
- .platform-amd64
|
||||
- .scan
|
||||
needs:
|
||||
- image-ubi8
|
||||
|
||||
scan-ubi8-arm64:
|
||||
extends:
|
||||
- .scan
|
||||
- .dist-ubi8
|
||||
- .platform-arm64
|
||||
- .scan
|
||||
needs:
|
||||
- image-ubi8
|
||||
- scan-ubi8-amd64
|
||||
@@ -201,6 +308,27 @@ scan-ubi8-arm64:
|
||||
OUT_REGISTRY: "${NGC_REGISTRY}"
|
||||
OUT_IMAGE_NAME: "${NGC_REGISTRY_IMAGE}"
|
||||
|
||||
.release:packages:
|
||||
stage: release
|
||||
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_ARTIFACTORY_REPO: "${ARTIFACTORY_REPO_BASE}-${PACKAGE_REPO_TYPE}-local"
|
||||
KITMAKER_ARTIFACTORY_REPO: "${ARTIFACTORY_REPO_BASE}-generic-local/${KITMAKER_RELEASE_FOLDER}"
|
||||
script:
|
||||
- !reference [.regctl-setup, before_script]
|
||||
- apk add --no-cache bash
|
||||
- regctl registry login "${PACKAGE_REGISTRY}" -u "${PACKAGE_REGISTRY_USER}" -p "${PACKAGE_REGISTRY_TOKEN}"
|
||||
- ./scripts/extract-packages.sh "${PACKAGE_IMAGE_NAME}:${PACKAGE_IMAGE_TAG}" "${DIST}-${ARCH}"
|
||||
# TODO: ./scripts/release-packages-artifactory.sh "${DIST}-${ARCH}" "${PACKAGE_ARTIFACTORY_REPO}"
|
||||
- ./scripts/release-kitmaker-artifactory.sh "${DIST}-${ARCH}" "${KITMAKER_ARTIFACTORY_REPO}"
|
||||
|
||||
release:staging-ubuntu18.04:
|
||||
extends:
|
||||
- .release:staging
|
||||
@@ -208,31 +336,24 @@ release:staging-ubuntu18.04:
|
||||
needs:
|
||||
- image-ubuntu18.04
|
||||
|
||||
release:staging-ubuntu20.04:
|
||||
extends:
|
||||
- .release:staging
|
||||
- .dist-ubuntu20.04
|
||||
needs:
|
||||
- image-ubuntu20.04
|
||||
|
||||
# Define the external release targets
|
||||
# Release to NGC
|
||||
release:ngc-centos7:
|
||||
extends:
|
||||
- .release:ngc
|
||||
- .dist-centos7
|
||||
- .release:ngc
|
||||
|
||||
release:ngc-ubuntu18.04:
|
||||
extends:
|
||||
- .release:ngc
|
||||
- .dist-ubuntu18.04
|
||||
- .release:ngc
|
||||
|
||||
release:ngc-ubuntu20.04:
|
||||
extends:
|
||||
- .release:ngc
|
||||
- .dist-ubuntu20.04
|
||||
- .release:ngc
|
||||
|
||||
release:ngc-ubi8:
|
||||
extends:
|
||||
- .release:ngc
|
||||
- .dist-ubi8
|
||||
- .release:ngc
|
||||
|
||||
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,5 +1,24 @@
|
||||
# NVIDIA Container Toolkit Changelog
|
||||
|
||||
## v1.12.0-rc.2
|
||||
|
||||
* Inject Direct Rendering Manager (DRM) devices into a container using the NVIDIA Container Runtime
|
||||
* Improve logging of errors from the NVIDIA Container Runtime
|
||||
* Improve CDI specification generation to support rootless podman
|
||||
* Use `nvidia-ctk cdi generate` to generate CDI specifications instead of `nvidia-ctk info generate-cdi`
|
||||
* [libnvidia-container] Skip creation of existing files when these are already mounted
|
||||
|
||||
## v1.12.0-rc.1
|
||||
|
||||
* Add support for multiple Docker Swarm resources
|
||||
* Improve injection of Vulkan configurations and libraries
|
||||
* Add `nvidia-ctk info generate-cdi` command to generated CDI specification for available devices
|
||||
* [libnvidia-container] Include NVVM compiler library in compute libs
|
||||
|
||||
## v1.11.0
|
||||
|
||||
* Promote v1.11.0-rc.3 to v1.11.0
|
||||
|
||||
## v1.11.0-rc.3
|
||||
|
||||
* Build fedora35 packages
|
||||
|
||||
3
Makefile
3
Makefile
@@ -51,6 +51,7 @@ CLI_VERSION = $(LIB_VERSION)$(if $(LIB_TAG),-$(LIB_TAG))
|
||||
else
|
||||
CLI_VERSION = $(VERSION)
|
||||
endif
|
||||
CLI_VERSION_PACKAGE = github.com/NVIDIA/nvidia-container-toolkit/internal/info
|
||||
|
||||
GOOS ?= linux
|
||||
|
||||
@@ -60,7 +61,7 @@ cmd-%: COMMAND_BUILD_OPTIONS = -o $(PREFIX)/$(*)
|
||||
endif
|
||||
cmds: $(CMD_TARGETS)
|
||||
$(CMD_TARGETS): cmd-%:
|
||||
GOOS=$(GOOS) go build -ldflags "-s -w -X github.com/NVIDIA/nvidia-container-toolkit/internal/info.gitCommit=$(GIT_COMMIT) -X github.com/NVIDIA/nvidia-container-toolkit/internal/info.version=$(CLI_VERSION)" $(COMMAND_BUILD_OPTIONS) $(MODULE)/cmd/$(*)
|
||||
GOOS=$(GOOS) go build -ldflags "-s -w -X $(CLI_VERSION_PACKAGE).gitCommit=$(GIT_COMMIT) -X $(CLI_VERSION_PACKAGE).version=$(CLI_VERSION)" $(COMMAND_BUILD_OPTIONS) $(MODULE)/cmd/$(*)
|
||||
|
||||
build:
|
||||
GOOS=$(GOOS) go build ./...
|
||||
|
||||
@@ -25,5 +25,7 @@ ARG ARTIFACTS_ROOT
|
||||
COPY ${ARTIFACTS_ROOT} /artifacts/packages/
|
||||
|
||||
WORKDIR /artifacts/packages
|
||||
# Create a manifest.txt file with the absolute paths of all deb and rpm packages in the container
|
||||
RUN find /artifacts/packages -iname '*.deb' -o -iname '*.rpm' > /artifacts/manifest.txt
|
||||
|
||||
RUN mkdir /licenses && mv /NGC-DL-CONTAINER-LICENSE /licenses/NGC-DL-CONTAINER-LICENSE
|
||||
|
||||
@@ -13,8 +13,6 @@ import (
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
var envSwarmGPU *string
|
||||
|
||||
const (
|
||||
envCUDAVersion = "CUDA_VERSION"
|
||||
envNVRequirePrefix = "NVIDIA_REQUIRE_"
|
||||
@@ -165,15 +163,24 @@ func isPrivileged(s *Spec) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func getDevicesFromEnvvar(image image.CUDA) *string {
|
||||
// Build a list of envvars to consider.
|
||||
envVars := []string{envNVVisibleDevices}
|
||||
if envSwarmGPU != nil {
|
||||
// The Swarm envvar has higher precedence.
|
||||
envVars = append([]string{*envSwarmGPU}, envVars...)
|
||||
func getDevicesFromEnvvar(image image.CUDA, swarmResourceEnvvars []string) *string {
|
||||
// We check if the image has at least one of the Swarm resource envvars defined and use this
|
||||
// if specified.
|
||||
var hasSwarmEnvvar bool
|
||||
for _, envvar := range swarmResourceEnvvars {
|
||||
if _, exists := image[envvar]; exists {
|
||||
hasSwarmEnvvar = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var devices []string
|
||||
if hasSwarmEnvvar {
|
||||
devices = image.DevicesFromEnvvars(swarmResourceEnvvars...).List()
|
||||
} else {
|
||||
devices = image.DevicesFromEnvvars(envNVVisibleDevices).List()
|
||||
}
|
||||
|
||||
devices := image.DevicesFromEnvvars(envVars...)
|
||||
if len(devices) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -230,7 +237,7 @@ func getDevices(hookConfig *HookConfig, image image.CUDA, mounts []Mount, privil
|
||||
}
|
||||
|
||||
// Fallback to reading from the environment variable if privileges are correct
|
||||
devices := getDevicesFromEnvvar(image)
|
||||
devices := getDevicesFromEnvvar(image, hookConfig.getSwarmResourceEnvvars())
|
||||
if devices == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -348,7 +355,6 @@ func getContainerConfig(hook HookConfig) (config containerConfig) {
|
||||
}
|
||||
|
||||
privileged := isPrivileged(s)
|
||||
envSwarmGPU = hook.SwarmResource
|
||||
return containerConfig{
|
||||
Pid: h.Pid,
|
||||
Rootfs: s.Root.Path,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
@@ -69,7 +70,7 @@ func TestGetNvidiaConfig(t *testing.T) {
|
||||
description: "Legacy image, devices 'void', no capabilities, no requirements",
|
||||
env: map[string]string{
|
||||
envCUDAVersion: "9.0",
|
||||
envNVVisibleDevices: "",
|
||||
envNVVisibleDevices: "void",
|
||||
},
|
||||
privileged: false,
|
||||
expectedConfig: nil,
|
||||
@@ -226,7 +227,7 @@ func TestGetNvidiaConfig(t *testing.T) {
|
||||
description: "Modern image, devices 'void', no capabilities, no requirements",
|
||||
env: map[string]string{
|
||||
envNVRequireCUDA: "cuda>=9.0",
|
||||
envNVVisibleDevices: "",
|
||||
envNVVisibleDevices: "void",
|
||||
},
|
||||
privileged: false,
|
||||
expectedConfig: nil,
|
||||
@@ -449,6 +450,44 @@ func TestGetNvidiaConfig(t *testing.T) {
|
||||
DriverCapabilities: defaultDriverCapabilities.String(),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Hook config set, swarmResource overrides device selection",
|
||||
env: map[string]string{
|
||||
envNVVisibleDevices: "all",
|
||||
"DOCKER_SWARM_RESOURCE": "GPU1,GPU2",
|
||||
},
|
||||
privileged: true,
|
||||
hookConfig: &HookConfig{
|
||||
SwarmResource: func() *string {
|
||||
s := "DOCKER_SWARM_RESOURCE"
|
||||
return &s
|
||||
}(),
|
||||
SupportedDriverCapabilities: "video,display,utility,compute",
|
||||
},
|
||||
expectedConfig: &nvidiaConfig{
|
||||
Devices: "GPU1,GPU2",
|
||||
DriverCapabilities: defaultDriverCapabilities.String(),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Hook config set, comma separated swarmResource is split and overrides device selection",
|
||||
env: map[string]string{
|
||||
envNVVisibleDevices: "all",
|
||||
"DOCKER_SWARM_RESOURCE": "GPU1,GPU2",
|
||||
},
|
||||
privileged: true,
|
||||
hookConfig: &HookConfig{
|
||||
SwarmResource: func() *string {
|
||||
s := "NOT_DOCKER_SWARM_RESOURCE,DOCKER_SWARM_RESOURCE"
|
||||
return &s
|
||||
}(),
|
||||
SupportedDriverCapabilities: "video,display,utility,compute",
|
||||
},
|
||||
expectedConfig: &nvidiaConfig{
|
||||
Devices: "GPU1,GPU2",
|
||||
DriverCapabilities: defaultDriverCapabilities.String(),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
@@ -689,12 +728,13 @@ func TestGetDevicesFromEnvvar(t *testing.T) {
|
||||
envDockerResourceGPUs := "DOCKER_RESOURCE_GPUS"
|
||||
gpuID := "GPU-12345"
|
||||
anotherGPUID := "GPU-67890"
|
||||
thirdGPUID := "MIG-12345"
|
||||
|
||||
var tests = []struct {
|
||||
description string
|
||||
envSwarmGPU *string
|
||||
env map[string]string
|
||||
expectedDevices *string
|
||||
description string
|
||||
swarmResourceEnvvars []string
|
||||
env map[string]string
|
||||
expectedDevices *string
|
||||
}{
|
||||
{
|
||||
description: "empty env returns nil for non-legacy image",
|
||||
@@ -798,42 +838,42 @@ func TestGetDevicesFromEnvvar(t *testing.T) {
|
||||
// Add the `DOCKER_RESOURCE_GPUS` envvar and ensure that this is selected when
|
||||
// enabled
|
||||
{
|
||||
description: "empty env returns nil for non-legacy image",
|
||||
envSwarmGPU: &envDockerResourceGPUs,
|
||||
description: "empty env returns nil for non-legacy image",
|
||||
swarmResourceEnvvars: []string{envDockerResourceGPUs},
|
||||
},
|
||||
{
|
||||
description: "blank DOCKER_RESOURCE_GPUS returns nil for non-legacy image",
|
||||
envSwarmGPU: &envDockerResourceGPUs,
|
||||
description: "blank DOCKER_RESOURCE_GPUS returns nil for non-legacy image",
|
||||
swarmResourceEnvvars: []string{envDockerResourceGPUs},
|
||||
env: map[string]string{
|
||||
envDockerResourceGPUs: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "'void' DOCKER_RESOURCE_GPUS returns nil for non-legacy image",
|
||||
envSwarmGPU: &envDockerResourceGPUs,
|
||||
description: "'void' DOCKER_RESOURCE_GPUS returns nil for non-legacy image",
|
||||
swarmResourceEnvvars: []string{envDockerResourceGPUs},
|
||||
env: map[string]string{
|
||||
envDockerResourceGPUs: "void",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "'none' DOCKER_RESOURCE_GPUS returns empty for non-legacy image",
|
||||
envSwarmGPU: &envDockerResourceGPUs,
|
||||
description: "'none' DOCKER_RESOURCE_GPUS returns empty for non-legacy image",
|
||||
swarmResourceEnvvars: []string{envDockerResourceGPUs},
|
||||
env: map[string]string{
|
||||
envDockerResourceGPUs: "none",
|
||||
},
|
||||
expectedDevices: &empty,
|
||||
},
|
||||
{
|
||||
description: "DOCKER_RESOURCE_GPUS set returns value for non-legacy image",
|
||||
envSwarmGPU: &envDockerResourceGPUs,
|
||||
description: "DOCKER_RESOURCE_GPUS set returns value for non-legacy image",
|
||||
swarmResourceEnvvars: []string{envDockerResourceGPUs},
|
||||
env: map[string]string{
|
||||
envDockerResourceGPUs: gpuID,
|
||||
},
|
||||
expectedDevices: &gpuID,
|
||||
},
|
||||
{
|
||||
description: "DOCKER_RESOURCE_GPUS set returns value for legacy image",
|
||||
envSwarmGPU: &envDockerResourceGPUs,
|
||||
description: "DOCKER_RESOURCE_GPUS set returns value for legacy image",
|
||||
swarmResourceEnvvars: []string{envDockerResourceGPUs},
|
||||
env: map[string]string{
|
||||
envDockerResourceGPUs: gpuID,
|
||||
envCUDAVersion: "legacy",
|
||||
@@ -841,28 +881,58 @@ func TestGetDevicesFromEnvvar(t *testing.T) {
|
||||
expectedDevices: &gpuID,
|
||||
},
|
||||
{
|
||||
description: "DOCKER_RESOURCE_GPUS is selected if present",
|
||||
envSwarmGPU: &envDockerResourceGPUs,
|
||||
description: "DOCKER_RESOURCE_GPUS is selected if present",
|
||||
swarmResourceEnvvars: []string{envDockerResourceGPUs},
|
||||
env: map[string]string{
|
||||
envDockerResourceGPUs: anotherGPUID,
|
||||
},
|
||||
expectedDevices: &anotherGPUID,
|
||||
},
|
||||
{
|
||||
description: "DOCKER_RESOURCE_GPUS overrides NVIDIA_VISIBLE_DEVICES if present",
|
||||
envSwarmGPU: &envDockerResourceGPUs,
|
||||
description: "DOCKER_RESOURCE_GPUS overrides NVIDIA_VISIBLE_DEVICES if present",
|
||||
swarmResourceEnvvars: []string{envDockerResourceGPUs},
|
||||
env: map[string]string{
|
||||
envNVVisibleDevices: gpuID,
|
||||
envDockerResourceGPUs: anotherGPUID,
|
||||
},
|
||||
expectedDevices: &anotherGPUID,
|
||||
},
|
||||
{
|
||||
description: "DOCKER_RESOURCE_GPUS_ADDITIONAL overrides NVIDIA_VISIBLE_DEVICES if present",
|
||||
swarmResourceEnvvars: []string{"DOCKER_RESOURCE_GPUS_ADDITIONAL"},
|
||||
env: map[string]string{
|
||||
envNVVisibleDevices: gpuID,
|
||||
"DOCKER_RESOURCE_GPUS_ADDITIONAL": anotherGPUID,
|
||||
},
|
||||
expectedDevices: &anotherGPUID,
|
||||
},
|
||||
{
|
||||
description: "All available swarm resource envvars are selected and override NVIDIA_VISIBLE_DEVICES if present",
|
||||
swarmResourceEnvvars: []string{"DOCKER_RESOURCE_GPUS", "DOCKER_RESOURCE_GPUS_ADDITIONAL"},
|
||||
env: map[string]string{
|
||||
envNVVisibleDevices: gpuID,
|
||||
"DOCKER_RESOURCE_GPUS": thirdGPUID,
|
||||
"DOCKER_RESOURCE_GPUS_ADDITIONAL": anotherGPUID,
|
||||
},
|
||||
expectedDevices: func() *string {
|
||||
result := fmt.Sprintf("%s,%s", thirdGPUID, anotherGPUID)
|
||||
return &result
|
||||
}(),
|
||||
},
|
||||
{
|
||||
description: "DOCKER_RESOURCE_GPUS_ADDITIONAL or DOCKER_RESOURCE_GPUS override NVIDIA_VISIBLE_DEVICES if present",
|
||||
swarmResourceEnvvars: []string{"DOCKER_RESOURCE_GPUS", "DOCKER_RESOURCE_GPUS_ADDITIONAL"},
|
||||
env: map[string]string{
|
||||
envNVVisibleDevices: gpuID,
|
||||
"DOCKER_RESOURCE_GPUS_ADDITIONAL": anotherGPUID,
|
||||
},
|
||||
expectedDevices: &anotherGPUID,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
envSwarmGPU = tc.envSwarmGPU
|
||||
devices := getDevicesFromEnvvar(image.CUDA(tc.env))
|
||||
devices := getDevicesFromEnvvar(image.CUDA(tc.env), tc.swarmResourceEnvvars)
|
||||
if tc.expectedDevices == nil {
|
||||
require.Nil(t, devices, "%d: %v", i, tc)
|
||||
return
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
@@ -116,3 +117,22 @@ func (c HookConfig) getConfigOption(fieldName string) string {
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// getSwarmResourceEnvvars returns the swarm resource envvars for the config.
|
||||
func (c *HookConfig) getSwarmResourceEnvvars() []string {
|
||||
if c.SwarmResource == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
candidates := strings.Split(*c.SwarmResource, ",")
|
||||
|
||||
var envvars []string
|
||||
for _, c := range candidates {
|
||||
trimmed := strings.TrimSpace(c)
|
||||
if len(trimmed) > 0 {
|
||||
envvars = append(envvars, trimmed)
|
||||
}
|
||||
}
|
||||
|
||||
return envvars
|
||||
}
|
||||
|
||||
@@ -103,3 +103,59 @@ func TestGetHookConfig(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwarmResourceEnvvars(t *testing.T) {
|
||||
testCases := []struct {
|
||||
value string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
value: "nil",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
value: " ",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
value: "single",
|
||||
expected: []string{"single"},
|
||||
},
|
||||
{
|
||||
value: "single ",
|
||||
expected: []string{"single"},
|
||||
},
|
||||
{
|
||||
value: "one,two",
|
||||
expected: []string{"one", "two"},
|
||||
},
|
||||
{
|
||||
value: "one ,two",
|
||||
expected: []string{"one", "two"},
|
||||
},
|
||||
{
|
||||
value: "one, two",
|
||||
expected: []string{"one", "two"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
c := &HookConfig{
|
||||
SwarmResource: func() *string {
|
||||
if tc.value == "nil" {
|
||||
return nil
|
||||
}
|
||||
return &tc.value
|
||||
}(),
|
||||
}
|
||||
|
||||
envvars := c.getSwarmResourceEnvvars()
|
||||
require.EqualValues(t, tc.expected, envvars)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,12 @@ func run(argv []string) (rerr error) {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set up logger: %v", err)
|
||||
}
|
||||
defer logger.Reset()
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
logger.Errorf("%v", rerr)
|
||||
}
|
||||
logger.Reset()
|
||||
}()
|
||||
|
||||
logger.Debugf("Command line arguments: %v", argv)
|
||||
runtime, err := newNVIDIAContainerRuntime(logger.Logger, cfg, argv)
|
||||
|
||||
@@ -67,6 +67,11 @@ func newSpecModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec
|
||||
return nil, err
|
||||
}
|
||||
|
||||
graphicsModifier, err := modifier.NewGraphicsModifier(logger, cfg, ociSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gdsModifier, err := modifier.NewGDSModifier(logger, cfg, ociSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -84,6 +89,7 @@ func newSpecModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec
|
||||
|
||||
modifiers := modifier.Merge(
|
||||
modeModifier,
|
||||
graphicsModifier,
|
||||
gdsModifier,
|
||||
mofedModifier,
|
||||
tegraModifier,
|
||||
|
||||
@@ -15,3 +15,34 @@ nvidia-ctk runtime configure --set-as-default
|
||||
```
|
||||
will ensure that the NVIDIA Container Runtime is added as the default runtime to the default container
|
||||
engine.
|
||||
|
||||
### Generate CDI specifications
|
||||
|
||||
The [Container Device Interface (CDI)](https://github.com/container-orchestrated-devices/container-device-interface) provides
|
||||
a vendor-agnostic mechanism to make arbitrary devices accessible in containerized environments. To allow NVIDIA devices to be
|
||||
used in these environments, the NVIDIA Container Toolkit CLI includes functionality to generate a CDI specification for the
|
||||
available NVIDIA GPUs in a system.
|
||||
|
||||
In order to generate the CDI specification for the available devices, run the following command:\
|
||||
```bash
|
||||
nvidia-ctk cdi generate
|
||||
```
|
||||
|
||||
The default is to print the specification to STDOUT and a filename can be specified using the `--output` flag.
|
||||
|
||||
The specification will contain a device entries as follows (where applicable):
|
||||
* An `nvidia.com/gpu=gpu{INDEX}` device for each non-MIG-enabled full GPU in the system
|
||||
* An `nvidia.com/gpu=mig{GPU_INDEX}:{MIG_INDEX}` device for each MIG-device in the system
|
||||
* A special device called `nvidia.com/gpu=all` which represents all available devices.
|
||||
|
||||
For example, to generate the CDI specification in the default location where CDI-enabled tools such as `podman`, `containerd`, `cri-o`, or the NVIDIA Container Runtime can be configured to load it, the following command can be run:
|
||||
|
||||
```bash
|
||||
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml
|
||||
```
|
||||
(Note that `sudo` is used to ensure the correct permissions to write to the `/etc/cdi` folder)
|
||||
|
||||
With the specification generated, a GPU can be requested by specifying the fully-qualified CDI device name. With `podman` as an exmaple:
|
||||
```bash
|
||||
podman run --rm -ti --device=nvidia.com/gpu=gpu0 ubuntu nvidia-smi -L
|
||||
```
|
||||
|
||||
50
cmd/nvidia-ctk/cdi/cdi.go
Normal file
50
cmd/nvidia-ctk/cdi/cdi.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 cdi
|
||||
|
||||
import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/cdi/generate"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
}
|
||||
|
||||
// NewCommand constructs an info command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
return c.build()
|
||||
}
|
||||
|
||||
// build
|
||||
func (m command) build() *cli.Command {
|
||||
// Create the 'hook' command
|
||||
hook := cli.Command{
|
||||
Name: "cdi",
|
||||
Usage: "Provide tools for interacting with Container Device Interface specifications",
|
||||
}
|
||||
|
||||
hook.Subcommands = []*cli.Command{
|
||||
generate.NewCommand(m.logger),
|
||||
}
|
||||
|
||||
return &hook
|
||||
}
|
||||
559
cmd/nvidia-ctk/cdi/generate/generate.go
Normal file
559
cmd/nvidia-ctk/cdi/generate/generate.go
Normal file
@@ -0,0 +1,559 @@
|
||||
/**
|
||||
# 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 generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"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"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
nvidiaCTKExecutable = "nvidia-ctk"
|
||||
nvidiaCTKDefaultFilePath = "/usr/bin/" + nvidiaCTKExecutable
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
}
|
||||
|
||||
type config struct {
|
||||
output string
|
||||
jsonMode bool
|
||||
}
|
||||
|
||||
// NewCommand constructs a generate-cdi command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
return c.build()
|
||||
}
|
||||
|
||||
// build creates the CLI command
|
||||
func (m command) build() *cli.Command {
|
||||
cfg := config{}
|
||||
|
||||
// Create the 'generate-cdi' command
|
||||
c := cli.Command{
|
||||
Name: "generate",
|
||||
Usage: "Generate CDI specifications for use with CDI-enabled runtimes",
|
||||
Action: func(c *cli.Context) error {
|
||||
return m.run(c, &cfg)
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "output",
|
||||
Usage: "Specify the file to output the generated CDI specification to. If this is '-' or '' the specification is output to STDOUT",
|
||||
Destination: &cfg.output,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "json",
|
||||
Usage: "Output the generated CDI spec in JSON mode instead of YAML",
|
||||
Destination: &cfg.jsonMode,
|
||||
},
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func (m command) run(c *cli.Context, cfg *config) error {
|
||||
spec, err := m.generateSpec()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate CDI spec: %v", err)
|
||||
}
|
||||
|
||||
var outputTo io.Writer
|
||||
if cfg.output == "" || cfg.output == "-" {
|
||||
outputTo = os.Stdout
|
||||
} else {
|
||||
outputFile, err := os.Create(cfg.output)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create output file: %v", err)
|
||||
}
|
||||
defer outputFile.Close()
|
||||
outputTo = outputFile
|
||||
}
|
||||
|
||||
if filepath.Ext(cfg.output) == ".json" {
|
||||
cfg.jsonMode = true
|
||||
} else if filepath.Ext(cfg.output) == ".yaml" || filepath.Ext(cfg.output) == ".yml" {
|
||||
cfg.jsonMode = false
|
||||
}
|
||||
|
||||
data, err := yaml.Marshal(spec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal CDI spec: %v", err)
|
||||
}
|
||||
|
||||
if cfg.jsonMode {
|
||||
data, err = yaml.YAMLToJSONStrict(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert CDI spec from YAML to JSON: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = writeToOutput(cfg.jsonMode, data, outputTo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write output: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeToOutput(jsonMode bool, data []byte, output io.Writer) error {
|
||||
if !jsonMode {
|
||||
_, err := output.Write([]byte("---\n"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write YAML separator: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
_, err := output.Write(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write data: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m command) generateSpec() (*specs.Spec, error) {
|
||||
nvmllib := nvml.New()
|
||||
if r := nvmllib.Init(); r != nvml.SUCCESS {
|
||||
return nil, r
|
||||
}
|
||||
defer nvmllib.Shutdown()
|
||||
|
||||
devicelib := device.New(device.WithNvml(nvmllib))
|
||||
|
||||
spec := specs.Spec{
|
||||
Version: "0.4.0",
|
||||
Kind: "nvidia.com/gpu",
|
||||
ContainerEdits: specs.ContainerEdits{},
|
||||
}
|
||||
err := devicelib.VisitDevices(func(i int, d device.Device) error {
|
||||
isMig, err := d.IsMigEnabled()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check whether device is MIG device: %v", err)
|
||||
}
|
||||
if isMig {
|
||||
return nil
|
||||
}
|
||||
device, err := generateEditsForDevice(newGPUDevice(i, d))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate CDI spec for device %v: %v", i, err)
|
||||
}
|
||||
|
||||
graphicsEdits, err := m.editsForGraphicsDevice(d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate CDI spec for DRM devices associated with device %v: %v", i, err)
|
||||
}
|
||||
|
||||
// We add the device nodes and hooks edits for the DRM devices; Mounts are added globally
|
||||
for _, dn := range graphicsEdits.DeviceNodes {
|
||||
device.ContainerEdits.DeviceNodes = append(device.ContainerEdits.DeviceNodes, dn)
|
||||
}
|
||||
for _, h := range graphicsEdits.Hooks {
|
||||
device.ContainerEdits.Hooks = append(device.ContainerEdits.Hooks, h)
|
||||
}
|
||||
|
||||
spec.Devices = append(spec.Devices, device)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate CDI spec for GPU devices: %v", err)
|
||||
}
|
||||
|
||||
err = devicelib.VisitMigDevices(func(i int, d device.Device, j int, m device.MigDevice) error {
|
||||
device, err := generateEditsForDevice(newMigDevice(i, j, m))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate CDI spec for device %v: %v", i, err)
|
||||
}
|
||||
|
||||
spec.Devices = append(spec.Devices, device)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("falied to generate CDI spec for MIG devices: %v", err)
|
||||
}
|
||||
|
||||
// We create an "all" device with all the discovered device nodes
|
||||
var allDeviceNodes []*specs.DeviceNode
|
||||
for _, d := range spec.Devices {
|
||||
for _, dn := range d.ContainerEdits.DeviceNodes {
|
||||
allDeviceNodes = append(allDeviceNodes, dn)
|
||||
}
|
||||
}
|
||||
all := specs.Device{
|
||||
Name: "all",
|
||||
ContainerEdits: specs.ContainerEdits{
|
||||
DeviceNodes: allDeviceNodes,
|
||||
},
|
||||
}
|
||||
|
||||
spec.Devices = append(spec.Devices, all)
|
||||
spec.ContainerEdits.DeviceNodes = m.getExistingMetaDeviceNodes()
|
||||
|
||||
libraries, err := m.findLibs(nvmllib)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to locate driver libraries: %v", err)
|
||||
}
|
||||
|
||||
binaries, err := m.findBinaries()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to locate driver binaries: %v", err)
|
||||
}
|
||||
|
||||
ipcs, err := m.findIPC()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to locate driver IPC sockets: %v", err)
|
||||
}
|
||||
|
||||
graphicsEdits, err := m.editsForGraphicsDevice(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generated edits for graphics libraries")
|
||||
}
|
||||
|
||||
libOptions := []string{
|
||||
"ro",
|
||||
"nosuid",
|
||||
"nodev",
|
||||
"bind",
|
||||
}
|
||||
ipcOptions := append(libOptions, "noexec")
|
||||
|
||||
spec.ContainerEdits.Mounts = append(
|
||||
generateMountsForPaths(libOptions, libraries, binaries),
|
||||
generateMountsForPaths(ipcOptions, ipcs)...,
|
||||
)
|
||||
|
||||
spec.ContainerEdits.Mounts = append(spec.ContainerEdits.Mounts, graphicsEdits.Mounts...)
|
||||
|
||||
ldcacheUpdateHook := m.generateUpdateLdCacheHook(libraries)
|
||||
|
||||
deviceFolderPermissionHooks, err := m.generateDeviceFolderPermissionHooks(ldcacheUpdateHook.Path, allDeviceNodes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generated permission hooks for device nodes: %v", err)
|
||||
}
|
||||
|
||||
spec.ContainerEdits.Hooks = append([]*specs.Hook{ldcacheUpdateHook}, deviceFolderPermissionHooks...)
|
||||
|
||||
return &spec, nil
|
||||
}
|
||||
|
||||
func generateEditsForDevice(name string, d deviceInfo) (specs.Device, error) {
|
||||
deviceNodePaths, err := d.GetDeviceNodes()
|
||||
if err != nil {
|
||||
return specs.Device{}, fmt.Errorf("failed to get paths for device: %v", err)
|
||||
}
|
||||
|
||||
deviceNodes := getDeviceNodesFromPaths(deviceNodePaths)
|
||||
|
||||
device := specs.Device{
|
||||
Name: name,
|
||||
ContainerEdits: specs.ContainerEdits{
|
||||
DeviceNodes: deviceNodes,
|
||||
},
|
||||
}
|
||||
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (m command) editsForGraphicsDevice(device device.Device) (*specs.ContainerEdits, error) {
|
||||
selectedDevice := image.NewVisibleDevices("none")
|
||||
if device != nil {
|
||||
uuid, ret := device.GetUUID()
|
||||
if ret != nvml.SUCCESS {
|
||||
return nil, fmt.Errorf("error getting device UUID: %v", ret)
|
||||
}
|
||||
selectedDevice = image.NewVisibleDevices(uuid)
|
||||
}
|
||||
cfg := discover.Config{
|
||||
Root: "",
|
||||
NVIDIAContainerToolkitCLIExecutablePath: "nvidia-ctk",
|
||||
}
|
||||
// Create a discoverer for the single device:
|
||||
d, err := discover.NewGraphicsDiscoverer(m.logger, selectedDevice, &cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error constructing discoverer: %v", err)
|
||||
}
|
||||
|
||||
devices, err := d.Devices()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting DRM devices: %v", err)
|
||||
}
|
||||
|
||||
var deviceNodes []*specs.DeviceNode
|
||||
for _, d := range devices {
|
||||
dn := specs.DeviceNode{
|
||||
Path: d.Path,
|
||||
HostPath: d.HostPath,
|
||||
}
|
||||
deviceNodes = append(deviceNodes, &dn)
|
||||
}
|
||||
|
||||
hooks, err := d.Hooks()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting hooks: %v", err)
|
||||
}
|
||||
|
||||
var cdiHooks []*specs.Hook
|
||||
for _, h := range hooks {
|
||||
cdiHook := specs.Hook{
|
||||
HookName: h.Lifecycle,
|
||||
Path: h.Path,
|
||||
Args: h.Args,
|
||||
}
|
||||
cdiHooks = append(cdiHooks, &cdiHook)
|
||||
}
|
||||
|
||||
mounts, err := d.Mounts()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting mounts: %v", err)
|
||||
}
|
||||
|
||||
var cdiMounts []*specs.Mount
|
||||
for _, m := range mounts {
|
||||
cdiMount := specs.Mount{
|
||||
ContainerPath: m.Path,
|
||||
HostPath: m.HostPath,
|
||||
Options: []string{
|
||||
"ro",
|
||||
"nosuid",
|
||||
"nodev",
|
||||
"bind",
|
||||
},
|
||||
Type: "bind",
|
||||
}
|
||||
cdiMounts = append(cdiMounts, &cdiMount)
|
||||
}
|
||||
|
||||
edits := specs.ContainerEdits{
|
||||
DeviceNodes: deviceNodes,
|
||||
Hooks: cdiHooks,
|
||||
Mounts: cdiMounts,
|
||||
}
|
||||
|
||||
return &edits, nil
|
||||
}
|
||||
|
||||
func (m command) getExistingMetaDeviceNodes() []*specs.DeviceNode {
|
||||
metaDeviceNodePaths := []string{
|
||||
"/dev/nvidia-modeset",
|
||||
"/dev/nvidia-uvm-tools",
|
||||
"/dev/nvidia-uvm",
|
||||
"/dev/nvidiactl",
|
||||
}
|
||||
|
||||
var existingDeviceNodePaths []string
|
||||
for _, p := range metaDeviceNodePaths {
|
||||
if _, err := os.Stat(p); err != nil {
|
||||
m.logger.Infof("Ignoring missing meta device %v", p)
|
||||
continue
|
||||
}
|
||||
existingDeviceNodePaths = append(existingDeviceNodePaths, p)
|
||||
}
|
||||
|
||||
return getDeviceNodesFromPaths(existingDeviceNodePaths)
|
||||
}
|
||||
|
||||
func getDeviceNodesFromPaths(deviceNodePaths []string) []*specs.DeviceNode {
|
||||
var deviceNodes []*specs.DeviceNode
|
||||
for _, p := range deviceNodePaths {
|
||||
deviceNode := specs.DeviceNode{
|
||||
Path: p,
|
||||
}
|
||||
deviceNodes = append(deviceNodes, &deviceNode)
|
||||
}
|
||||
|
||||
return deviceNodes
|
||||
}
|
||||
|
||||
func (m command) findLibs(nvmllib nvml.Interface) ([]string, error) {
|
||||
version, r := nvmllib.SystemGetDriverVersion()
|
||||
if r != nvml.SUCCESS {
|
||||
return nil, fmt.Errorf("failed to determine driver version: %v", r)
|
||||
}
|
||||
m.logger.Infof("Using driver version %v", version)
|
||||
|
||||
cache, err := ldcache.New(m.logger, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load ldcache: %v", err)
|
||||
}
|
||||
|
||||
libs32, libs64 := cache.List()
|
||||
|
||||
var libs []string
|
||||
for _, l := range libs64 {
|
||||
if strings.HasSuffix(l, version) {
|
||||
m.logger.Infof("found 64-bit driver lib: %v", l)
|
||||
libs = append(libs, l)
|
||||
}
|
||||
}
|
||||
|
||||
for _, l := range libs32 {
|
||||
if strings.HasSuffix(l, version) {
|
||||
m.logger.Infof("found 32-bit driver lib: %v", l)
|
||||
libs = append(libs, l)
|
||||
}
|
||||
}
|
||||
|
||||
return libs, nil
|
||||
}
|
||||
|
||||
func (m command) findBinaries() ([]string, error) {
|
||||
candidates := []string{
|
||||
"nvidia-smi", /* System management interface */
|
||||
"nvidia-debugdump", /* GPU coredump utility */
|
||||
"nvidia-persistenced", /* Persistence mode utility */
|
||||
"nvidia-cuda-mps-control", /* Multi process service CLI */
|
||||
"nvidia-cuda-mps-server", /* Multi process service server */
|
||||
}
|
||||
|
||||
locator := lookup.NewExecutableLocator(m.logger, "")
|
||||
|
||||
var binaries []string
|
||||
for _, c := range candidates {
|
||||
targets, err := locator.Locate(c)
|
||||
if err != nil {
|
||||
m.logger.Warningf("skipping %v: %v", c, err)
|
||||
continue
|
||||
}
|
||||
|
||||
binaries = append(binaries, targets[0])
|
||||
}
|
||||
return binaries, nil
|
||||
}
|
||||
|
||||
func (m command) findIPC() ([]string, error) {
|
||||
candidates := []string{
|
||||
"/var/run/nvidia-persistenced/socket",
|
||||
"/var/run/nvidia-fabricmanager/socket",
|
||||
// TODO: This can be controlled by the NV_MPS_PIPE_DIR envvar
|
||||
"/tmp/nvidia-mps",
|
||||
}
|
||||
|
||||
locator := lookup.NewFileLocator(m.logger, "")
|
||||
|
||||
var ipcs []string
|
||||
for _, c := range candidates {
|
||||
targets, err := locator.Locate(c)
|
||||
if err != nil {
|
||||
m.logger.Warningf("skipping %v: %v", c, err)
|
||||
continue
|
||||
}
|
||||
|
||||
ipcs = append(ipcs, targets[0])
|
||||
}
|
||||
return ipcs, nil
|
||||
}
|
||||
|
||||
func generateMountsForPaths(options []string, pathSets ...[]string) []*specs.Mount {
|
||||
var mounts []*specs.Mount
|
||||
for _, paths := range pathSets {
|
||||
for _, p := range paths {
|
||||
mount := specs.Mount{
|
||||
HostPath: p,
|
||||
// We may want to adjust the container path
|
||||
ContainerPath: p,
|
||||
Type: "bind",
|
||||
Options: options,
|
||||
}
|
||||
mounts = append(mounts, &mount)
|
||||
}
|
||||
}
|
||||
return mounts
|
||||
}
|
||||
|
||||
func (m command) generateUpdateLdCacheHook(libraries []string) *specs.Hook {
|
||||
locator := lookup.NewExecutableLocator(m.logger, "")
|
||||
|
||||
hook := discover.CreateLDCacheUpdateHook(
|
||||
m.logger,
|
||||
locator,
|
||||
nvidiaCTKExecutable,
|
||||
nvidiaCTKDefaultFilePath,
|
||||
libraries,
|
||||
)
|
||||
return &specs.Hook{
|
||||
HookName: hook.Lifecycle,
|
||||
Path: hook.Path,
|
||||
Args: hook.Args,
|
||||
}
|
||||
}
|
||||
|
||||
func (m command) generateDeviceFolderPermissionHooks(nvidiaCTKPath string, deviceNodes []*specs.DeviceNode) ([]*specs.Hook, error) {
|
||||
var deviceFolders []string
|
||||
seen := make(map[string]bool)
|
||||
|
||||
for _, dn := range deviceNodes {
|
||||
if !strings.HasPrefix(dn.Path, "/dev") {
|
||||
m.logger.Warningf("Skipping unexpected device folder path for device %v", dn.Path)
|
||||
continue
|
||||
}
|
||||
for df := filepath.Dir(dn.Path); df != "/dev"; df = filepath.Dir(df) {
|
||||
if seen[df] {
|
||||
continue
|
||||
}
|
||||
deviceFolders = append(deviceFolders, df)
|
||||
seen[df] = true
|
||||
}
|
||||
}
|
||||
|
||||
foldersByMode := make(map[string][]string)
|
||||
for _, p := range deviceFolders {
|
||||
info, err := os.Stat(p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get info for path %v: %v", p, err)
|
||||
}
|
||||
mode := fmt.Sprintf("%o", info.Mode().Perm())
|
||||
foldersByMode[mode] = append(foldersByMode[mode], p)
|
||||
}
|
||||
|
||||
var hooks []*specs.Hook
|
||||
for mode, folders := range foldersByMode {
|
||||
args := []string{filepath.Base(nvidiaCTKPath), "hook", "chmod", "--mode", mode}
|
||||
for _, folder := range folders {
|
||||
args = append(args, "--path", folder)
|
||||
}
|
||||
hook := specs.Hook{
|
||||
HookName: cdi.CreateContainerHook,
|
||||
Path: nvidiaCTKPath,
|
||||
Args: args,
|
||||
}
|
||||
|
||||
hooks = append(hooks, &hook)
|
||||
}
|
||||
|
||||
return hooks, nil
|
||||
}
|
||||
123
cmd/nvidia-ctk/cdi/generate/nvml_devices.go
Normal file
123
cmd/nvidia-ctk/cdi/generate/nvml_devices.go
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 Type, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/nvcaps"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/device"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvml"
|
||||
)
|
||||
|
||||
// nvmlDevice wraps an nvml.Device with more functions.
|
||||
type nvmlDevice struct {
|
||||
nvml.Device
|
||||
}
|
||||
|
||||
// nvmlMigDevice allows for specific functions of nvmlDevice to be overridden.
|
||||
type nvmlMigDevice nvmlDevice
|
||||
|
||||
// deviceInfo defines the information the required to construct a Device
|
||||
type deviceInfo interface {
|
||||
GetUUID() (string, error)
|
||||
GetDeviceNodes() ([]string, error)
|
||||
}
|
||||
|
||||
var _ deviceInfo = (*nvmlDevice)(nil)
|
||||
var _ deviceInfo = (*nvmlMigDevice)(nil)
|
||||
|
||||
func newGPUDevice(i int, gpu device.Device) (string, nvmlDevice) {
|
||||
return fmt.Sprintf("gpu%v", i), nvmlDevice{gpu}
|
||||
}
|
||||
|
||||
func newMigDevice(i int, j int, mig device.MigDevice) (string, nvmlMigDevice) {
|
||||
return fmt.Sprintf("mig%v:%v", i, j), nvmlMigDevice{mig}
|
||||
}
|
||||
|
||||
// GetUUID returns the UUID of the device
|
||||
func (d nvmlDevice) GetUUID() (string, error) {
|
||||
uuid, ret := d.Device.GetUUID()
|
||||
if ret != nvml.SUCCESS {
|
||||
return "", ret
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// GetUUID returns the UUID of the device
|
||||
func (d nvmlMigDevice) GetUUID() (string, error) {
|
||||
return nvmlDevice(d).GetUUID()
|
||||
}
|
||||
|
||||
// GetDeviceNodes returns the device node paths for a GPU device
|
||||
func (d nvmlDevice) GetDeviceNodes() ([]string, error) {
|
||||
minor, ret := d.GetMinorNumber()
|
||||
if ret != nvml.SUCCESS {
|
||||
return nil, fmt.Errorf("error getting GPU device minor number: %v", ret)
|
||||
}
|
||||
path := fmt.Sprintf("/dev/nvidia%d", minor)
|
||||
|
||||
return []string{path}, nil
|
||||
}
|
||||
|
||||
// GetDeviceNodes returns the device node paths for a MIG device
|
||||
func (d nvmlMigDevice) GetDeviceNodes() ([]string, error) {
|
||||
parent, ret := d.GetDeviceHandleFromMigDeviceHandle()
|
||||
if ret != nvml.SUCCESS {
|
||||
return nil, fmt.Errorf("error getting parent device: %v", ret)
|
||||
}
|
||||
minor, ret := parent.GetMinorNumber()
|
||||
if ret != nvml.SUCCESS {
|
||||
return nil, fmt.Errorf("error getting GPU device minor number: %v", ret)
|
||||
}
|
||||
parentPath := fmt.Sprintf("/dev/nvidia%d", minor)
|
||||
|
||||
migCaps, err := nvcaps.NewMigCaps()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting MIG capability device paths: %v", err)
|
||||
}
|
||||
|
||||
gi, ret := d.GetGpuInstanceId()
|
||||
if ret != nvml.SUCCESS {
|
||||
return nil, fmt.Errorf("error getting GPU Instance ID: %v", ret)
|
||||
}
|
||||
|
||||
ci, ret := d.GetComputeInstanceId()
|
||||
if ret != nvml.SUCCESS {
|
||||
return nil, fmt.Errorf("error getting Compute Instance ID: %v", ret)
|
||||
}
|
||||
|
||||
giCap := nvcaps.NewGPUInstanceCap(minor, gi)
|
||||
giCapDevicePath, err := migCaps.GetCapDevicePath(giCap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get GI cap device path: %v", err)
|
||||
}
|
||||
|
||||
ciCap := nvcaps.NewComputeInstanceCap(minor, gi, ci)
|
||||
ciCapDevicePath, err := migCaps.GetCapDevicePath(ciCap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get CI cap device path: %v", err)
|
||||
}
|
||||
|
||||
devicePaths := []string{
|
||||
parentPath,
|
||||
giCapDevicePath,
|
||||
ciCapDevicePath,
|
||||
}
|
||||
|
||||
return devicePaths, nil
|
||||
}
|
||||
140
cmd/nvidia-ctk/hook/chmod/chmod.go
Normal file
140
cmd/nvidia-ctk/hook/chmod/chmod.go
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
# 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 chmod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
type config struct {
|
||||
paths cli.StringSlice
|
||||
mode string
|
||||
containerSpec string
|
||||
}
|
||||
|
||||
// NewCommand constructs a chmod command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
return c.build()
|
||||
}
|
||||
|
||||
// build the chmod command
|
||||
func (m command) build() *cli.Command {
|
||||
cfg := config{}
|
||||
|
||||
// Create the 'chmod' command
|
||||
c := cli.Command{
|
||||
Name: "chmod",
|
||||
Usage: "Set the permissions of folders in the container by running chmod. The container root is prefixed to the specified paths.",
|
||||
Before: func(c *cli.Context) error {
|
||||
return validateFlags(c, &cfg)
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return m.run(c, &cfg)
|
||||
},
|
||||
}
|
||||
|
||||
c.Flags = []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "path",
|
||||
Usage: "Specifiy a path to apply the specified mode to",
|
||||
Destination: &cfg.paths,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "mode",
|
||||
Usage: "Specify the file mode",
|
||||
Destination: &cfg.mode,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "container-spec",
|
||||
Usage: "Specify the path to the OCI container spec. If empty or '-' the spec will be read from STDIN",
|
||||
Destination: &cfg.containerSpec,
|
||||
},
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func validateFlags(c *cli.Context, cfg *config) error {
|
||||
if strings.TrimSpace(cfg.mode) == "" {
|
||||
return fmt.Errorf("a non-empty mode must be specified")
|
||||
}
|
||||
|
||||
for _, p := range cfg.paths.Value() {
|
||||
if strings.TrimSpace(p) == "" {
|
||||
return fmt.Errorf("paths must not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m command) run(c *cli.Context, cfg *config) error {
|
||||
s, err := oci.LoadContainerState(cfg.containerSpec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load container state: %v", err)
|
||||
}
|
||||
|
||||
containerRoot, err := s.GetContainerRoot()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determined container root: %v", err)
|
||||
}
|
||||
if containerRoot == "" {
|
||||
return fmt.Errorf("empty container root detected")
|
||||
}
|
||||
|
||||
paths := m.getPaths(containerRoot, cfg.paths.Value())
|
||||
if len(paths) == 0 {
|
||||
m.logger.Debugf("No paths specified; exiting")
|
||||
return nil
|
||||
}
|
||||
|
||||
locator := lookup.NewExecutableLocator(m.logger, "")
|
||||
targets, err := locator.Locate("chmod")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to locate chmod: %v", err)
|
||||
}
|
||||
chmodPath := targets[0]
|
||||
|
||||
args := append([]string{filepath.Base(chmodPath), cfg.mode}, paths...)
|
||||
|
||||
return syscall.Exec(chmodPath, args, nil)
|
||||
}
|
||||
|
||||
// getPaths updates the specified paths relative to the root.
|
||||
func (m command) getPaths(root string, paths []string) []string {
|
||||
var pathsInRoot []string
|
||||
for _, f := range paths {
|
||||
pathsInRoot = append(pathsInRoot, filepath.Join(root, f))
|
||||
}
|
||||
|
||||
return pathsInRoot
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func (m command) build() *cli.Command {
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "link",
|
||||
Usage: "Specify a specific link to create. The link is specified as source:target",
|
||||
Usage: "Specify a specific link to create. The link is specified as target::link",
|
||||
Destination: &cfg.links,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
@@ -145,7 +145,7 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
||||
|
||||
links := cfg.links.Value()
|
||||
for _, l := range links {
|
||||
parts := strings.Split(l, ":")
|
||||
parts := strings.Split(l, "::")
|
||||
if len(parts) != 2 {
|
||||
m.logger.Warnf("Invalid link specification %v", l)
|
||||
continue
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package hook
|
||||
|
||||
import (
|
||||
chmod "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/chmod"
|
||||
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"
|
||||
@@ -46,6 +47,7 @@ func (m hookCommand) build() *cli.Command {
|
||||
hook.Subcommands = []*cli.Command{
|
||||
ldcache.NewCommand(m.logger),
|
||||
symlinks.NewCommand(m.logger),
|
||||
chmod.NewCommand(m.logger),
|
||||
}
|
||||
|
||||
return &hook
|
||||
|
||||
47
cmd/nvidia-ctk/info/info.go
Normal file
47
cmd/nvidia-ctk/info/info.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
# 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 info
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
logger *logrus.Logger
|
||||
}
|
||||
|
||||
// NewCommand constructs an info command with the specified logger
|
||||
func NewCommand(logger *logrus.Logger) *cli.Command {
|
||||
c := command{
|
||||
logger: logger,
|
||||
}
|
||||
return c.build()
|
||||
}
|
||||
|
||||
// build
|
||||
func (m command) build() *cli.Command {
|
||||
// Create the 'hook' command
|
||||
hook := cli.Command{
|
||||
Name: "info",
|
||||
Usage: "Provide information about the system",
|
||||
}
|
||||
|
||||
hook.Subcommands = []*cli.Command{}
|
||||
|
||||
return &hook
|
||||
}
|
||||
@@ -19,9 +19,12 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/cdi"
|
||||
"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/internal/info"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
cli "github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -72,6 +75,8 @@ func main() {
|
||||
c.Commands = []*cli.Command{
|
||||
hook.NewCommand(logger),
|
||||
runtime.NewCommand(logger),
|
||||
infoCLI.NewCommand(logger),
|
||||
cdi.NewCommand(logger),
|
||||
}
|
||||
|
||||
// Run the CLI
|
||||
|
||||
@@ -22,7 +22,9 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/runtime/nvidia"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/crio"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/docker"
|
||||
"github.com/pelletier/go-toml"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -31,6 +33,7 @@ const (
|
||||
defaultRuntime = "docker"
|
||||
|
||||
defaultDockerConfigFilePath = "/etc/docker/daemon.json"
|
||||
defaultCrioConfigFilePath = "/etc/crio/crio.conf"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
@@ -75,7 +78,7 @@ func (m command) build() *cli.Command {
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "the target runtime engine. One of [docker]",
|
||||
Usage: "the target runtime engine. One of [crio, docker]",
|
||||
Value: defaultRuntime,
|
||||
Destination: &config.runtime,
|
||||
},
|
||||
@@ -108,6 +111,8 @@ func (m command) build() *cli.Command {
|
||||
|
||||
func (m command) configureWrapper(c *cli.Context, config *config) error {
|
||||
switch config.runtime {
|
||||
case "crio":
|
||||
return m.configureCrio(c, config)
|
||||
case "docker":
|
||||
return m.configureDocker(c, config)
|
||||
}
|
||||
@@ -127,9 +132,12 @@ func (m command) configureDocker(c *cli.Context, config *config) error {
|
||||
return fmt.Errorf("unable to load config: %v", err)
|
||||
}
|
||||
|
||||
defaultRuntime := config.nvidiaOptions.DefaultRuntime()
|
||||
runtimeConfig := config.nvidiaOptions.Runtime().DockerRuntimesConfig()
|
||||
err = docker.UpdateConfig(cfg, defaultRuntime, runtimeConfig)
|
||||
err = docker.UpdateConfig(
|
||||
cfg,
|
||||
config.nvidiaOptions.RuntimeName,
|
||||
config.nvidiaOptions.RuntimePath,
|
||||
config.nvidiaOptions.SetAsDefault,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update config: %v", err)
|
||||
}
|
||||
@@ -152,3 +160,44 @@ func (m command) configureDocker(c *cli.Context, config *config) error {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
cfg, err := crio.LoadConfig(configFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load config: %v", err)
|
||||
}
|
||||
|
||||
err = crio.UpdateConfig(
|
||||
cfg,
|
||||
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
|
||||
}
|
||||
err = crio.FlushConfig(configFilePath, cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to flush config: %v", err)
|
||||
}
|
||||
|
||||
m.logger.Infof("Wrote updated config to %v", configFilePath)
|
||||
m.logger.Infof("It is recommended that the cri-o daemon be restarted.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -78,4 +78,4 @@ RUN dch --create --package="${PKG_NAME}" \
|
||||
CMD export DISTRIB="$(lsb_release -cs)" && \
|
||||
debuild -eDISTRIB -eSECTION -eLIBNVIDIA_CONTAINER_TOOLS_VERSION -eVERSION="${REVISION}" \
|
||||
--dpkg-buildpackage-hook='sh debian/prepare' -i -us -uc -b && \
|
||||
mv /tmp/nvidia-container-toolkit_*.deb /dist
|
||||
mv /tmp/*.deb /dist
|
||||
|
||||
43
go.mod
43
go.mod
@@ -1,24 +1,41 @@
|
||||
module github.com/NVIDIA/nvidia-container-toolkit
|
||||
|
||||
go 1.14
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.0.0
|
||||
github.com/NVIDIA/go-nvml v0.11.6-0.0.20220715143214-a79f46f2a6f7
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.4.1-0.20220614144320-dc973e22f674
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/opencontainers/runc v1.1.3
|
||||
github.com/NVIDIA/go-nvml v0.11.6-0.0.20220823120812-7e2082095e82
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.2
|
||||
github.com/opencontainers/runc v1.1.4
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20220110225228-7e2d60f1e41f // indirect
|
||||
github.com/pelletier/go-toml v1.9.4
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/urfave/cli v1.22.4 // indirect
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20220725232003-c7f47cb02a33
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20220922133427-1049a7fa76a9
|
||||
golang.org/x/mod v0.5.0
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
golang.org/x/sys v0.0.0-20220927170352-d9d178bc13c6
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20220110225228-7e2d60f1e41f // indirect
|
||||
github.com/opencontainers/selinux v1.10.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // 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
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
||||
580
go.sum
580
go.sum
@@ -1,75 +1,18 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
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/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/NVIDIA/go-nvml v0.11.6-0.0.20220614115128-31f8b89eb740/go.mod h1:hy7HYeQy335x6nEss0Ne3PYqleRa6Ct+VKD9RQ4nyFs=
|
||||
github.com/NVIDIA/go-nvml v0.11.6-0.0.20220715143214-a79f46f2a6f7 h1:yl06QAxbf3g3VZX5/7CaZfTUZqFztdZZvlq0TfAvQrk=
|
||||
github.com/NVIDIA/go-nvml v0.11.6-0.0.20220715143214-a79f46f2a6f7/go.mod h1:hy7HYeQy335x6nEss0Ne3PYqleRa6Ct+VKD9RQ4nyFs=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
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/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.4.1-0.20220614144320-dc973e22f674 h1:fLkFha0Ck6uy0HW7c0jht0HPBtE8EJGSFBANnga1QtY=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.4.1-0.20220614144320-dc973e22f674/go.mod h1:ZToWfSyUH5l9Rk7/bjkUUkNLz4b1mE+CVUVafuikDPY=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.2 h1:Bf/Zq8UBhbSBtB+pFBVIQ2Rh7sNK/x2ZEr6uW5YjNv8=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.5.2/go.mod h1:ZToWfSyUH5l9Rk7/bjkUUkNLz4b1mE+CVUVafuikDPY=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
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.0/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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -78,586 +21,107 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
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/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
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/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
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/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/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||
github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
|
||||
github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
|
||||
github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
|
||||
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.20201121164853-7413a7f753e1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
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.20211214071223-8958f93039ab h1:YQZXa3elcHgKXAa2GjVFC9M3JeP7ZPyFD1YByDx/dgQ=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20220110225228-7e2d60f1e41f h1:MMcsVl0FAVEahmXTy+uXoDTw3yJq7nGrK8ITs/kkreo=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20220110225228-7e2d60f1e41f/go.mod h1:/tgP02fPXGHkU3/qKK1Y0Db4yqNyGm03vLq/mzHzcS4=
|
||||
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU=
|
||||
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/opencontainers/selinux v1.10.1 h1:09LIPVRP3uuZGQvgR+SgMSNBd1Eb3vlRbGqQpoHsF8w=
|
||||
github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
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/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||
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 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
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/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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
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 v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
|
||||
github.com/urfave/cli v1.22.4/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-20190809123943-df4f5c81cb3b h1:6cLsL+2FW6dRAdl5iMtHgRogVCff0QpRi9653YmdcJA=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b/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=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
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=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20220725232003-c7f47cb02a33 h1:YnWOCWHjoQtpzKUo/ihqs0ldj+GJ2qJ4QhLctMwzcKk=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20220725232003-c7f47cb02a33/go.mod h1:SIbXUP9E8o3uWK6MMfX6Oi9ABkUqhPSX8W8VdVWkYI4=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20220922133427-1049a7fa76a9 h1:3C1cK0/n1HGfH0MPCCPRntK8xPNlrVq9OWR4RA72jW0=
|
||||
gitlab.com/nvidia/cloud-native/go-nvlib v0.0.0-20220922133427-1049a7fa76a9/go.mod h1:GStidGxhaqJhYFW1YpOnLvYCbL2EsM0od7IW4u7+JgU=
|
||||
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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/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.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
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.2.8/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=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
||||
125
internal/config/crio/crio.go
Normal file
125
internal/config/crio/crio.go
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
# 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 crio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/pelletier/go-toml"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// LoadConfig loads the cri-o config from disk
|
||||
func LoadConfig(config string) (*toml.Tree, error) {
|
||||
log.Infof("Loading config: %v", config)
|
||||
|
||||
info, err := os.Stat(config)
|
||||
if os.IsExist(err) && info.IsDir() {
|
||||
return nil, fmt.Errorf("config file is a directory")
|
||||
}
|
||||
|
||||
configFile := config
|
||||
if os.IsNotExist(err) {
|
||||
configFile = "/dev/null"
|
||||
log.Infof("Config file does not exist, creating new one")
|
||||
}
|
||||
|
||||
cfg, err := toml.LoadFile(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("Successfully loaded config")
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// UpdateConfig updates the cri-o config to include the NVIDIA Container Runtime
|
||||
func UpdateConfig(config *toml.Tree, runtimeClass string, runtimePath string, setAsDefault bool) error {
|
||||
switch runc := config.Get("crio.runtime.runtimes.runc").(type) {
|
||||
case *toml.Tree:
|
||||
runc, _ = toml.Load(runc.String())
|
||||
config.SetPath([]string{"crio", "runtime", "runtimes", runtimeClass}, runc)
|
||||
}
|
||||
|
||||
config.SetPath([]string{"crio", "runtime", "runtimes", runtimeClass, "runtime_path"}, runtimePath)
|
||||
config.SetPath([]string{"crio", "runtime", "runtimes", runtimeClass, "runtime_type"}, "oci")
|
||||
|
||||
if setAsDefault {
|
||||
config.SetPath([]string{"crio", "runtime", "default_runtime"}, runtimeClass)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RevertConfig reverts the cri-o config to remove the NVIDIA Container Runtime
|
||||
func RevertConfig(config *toml.Tree, runtimeClass string) error {
|
||||
if runtime, ok := config.GetPath([]string{"crio", "runtime", "default_runtime"}).(string); ok {
|
||||
if runtimeClass == runtime {
|
||||
config.DeletePath([]string{"crio", "runtime", "default_runtime"})
|
||||
}
|
||||
}
|
||||
|
||||
runtimeClassPath := []string{"crio", "runtime", "runtimes", runtimeClass}
|
||||
config.DeletePath(runtimeClassPath)
|
||||
for i := 0; i < len(runtimeClassPath); i++ {
|
||||
remainingPath := runtimeClassPath[:len(runtimeClassPath)-i]
|
||||
if entry, ok := config.GetPath(remainingPath).(*toml.Tree); ok {
|
||||
if len(entry.Keys()) != 0 {
|
||||
break
|
||||
}
|
||||
config.DeletePath(remainingPath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FlushConfig flushes the updated/reverted config out to disk
|
||||
func FlushConfig(config string, cfg *toml.Tree) error {
|
||||
log.Infof("Flushing config")
|
||||
|
||||
output, err := cfg.ToTomlString()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to convert to TOML: %v", err)
|
||||
}
|
||||
|
||||
switch len(output) {
|
||||
case 0:
|
||||
err := os.Remove(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to remove empty file: %v", err)
|
||||
}
|
||||
log.Infof("Config empty, removing file")
|
||||
default:
|
||||
f, err := os.Create(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to open '%v' for writing: %v", config, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString(output)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write output: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Successfully flushed config")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -57,11 +57,7 @@ func LoadConfig(configFilePath string) (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
// UpdateConfig updates the docker config to include the nvidia runtimes
|
||||
func UpdateConfig(config map[string]interface{}, defaultRuntime string, newRuntimes map[string]interface{}) error {
|
||||
if defaultRuntime != "" {
|
||||
config["default-runtime"] = defaultRuntime
|
||||
}
|
||||
|
||||
func UpdateConfig(config map[string]interface{}, runtimeName string, runtimePath string, setAsDefault bool) error {
|
||||
// Read the existing runtimes
|
||||
runtimes := make(map[string]interface{})
|
||||
if _, exists := config["runtimes"]; exists {
|
||||
@@ -69,14 +65,20 @@ func UpdateConfig(config map[string]interface{}, defaultRuntime string, newRunti
|
||||
}
|
||||
|
||||
// Add / update the runtime definitions
|
||||
for name, rt := range newRuntimes {
|
||||
runtimes[name] = rt
|
||||
runtimes[runtimeName] = map[string]interface{}{
|
||||
"path": runtimePath,
|
||||
"args": []string{},
|
||||
}
|
||||
|
||||
// Update the runtimes definition
|
||||
if len(runtimes) > 0 {
|
||||
config["runtimes"] = runtimes
|
||||
}
|
||||
|
||||
if setAsDefault {
|
||||
config["default-runtime"] = runtimeName
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,30 +27,33 @@ import (
|
||||
func TestUpdateConfigDefaultRuntime(t *testing.T) {
|
||||
testCases := []struct {
|
||||
config map[string]interface{}
|
||||
defaultRuntime string
|
||||
runtimeName string
|
||||
setAsDefault bool
|
||||
expectedDefaultRuntimeName interface{}
|
||||
}{
|
||||
{
|
||||
defaultRuntime: "",
|
||||
setAsDefault: false,
|
||||
expectedDefaultRuntimeName: nil,
|
||||
},
|
||||
{
|
||||
defaultRuntime: "NAME",
|
||||
runtimeName: "NAME",
|
||||
setAsDefault: true,
|
||||
expectedDefaultRuntimeName: "NAME",
|
||||
},
|
||||
{
|
||||
config: map[string]interface{}{
|
||||
"default-runtime": "ALREADY_SET",
|
||||
},
|
||||
defaultRuntime: "",
|
||||
runtimeName: "NAME",
|
||||
setAsDefault: false,
|
||||
expectedDefaultRuntimeName: "ALREADY_SET",
|
||||
},
|
||||
{
|
||||
config: map[string]interface{}{
|
||||
"default-runtime": "ALREADY_SET",
|
||||
},
|
||||
defaultRuntime: "NAME",
|
||||
runtimeName: "NAME",
|
||||
setAsDefault: true,
|
||||
expectedDefaultRuntimeName: "NAME",
|
||||
},
|
||||
}
|
||||
@@ -60,7 +63,7 @@ func TestUpdateConfigDefaultRuntime(t *testing.T) {
|
||||
if tc.config == nil {
|
||||
tc.config = make(map[string]interface{})
|
||||
}
|
||||
err := UpdateConfig(tc.config, tc.defaultRuntime, nil)
|
||||
err := UpdateConfig(tc.config, tc.runtimeName, "", tc.setAsDefault)
|
||||
require.NoError(t, err)
|
||||
|
||||
defaultRuntimeName := tc.config["default-runtime"]
|
||||
@@ -72,20 +75,14 @@ func TestUpdateConfigDefaultRuntime(t *testing.T) {
|
||||
func TestUpdateConfigRuntimes(t *testing.T) {
|
||||
testCases := []struct {
|
||||
config map[string]interface{}
|
||||
runtimes map[string]interface{}
|
||||
runtimes map[string]string
|
||||
expectedConfig map[string]interface{}
|
||||
}{
|
||||
{
|
||||
config: map[string]interface{}{},
|
||||
runtimes: map[string]interface{}{
|
||||
"runtime1": map[string]interface{}{
|
||||
"path": "/test/runtime/dir/runtime1",
|
||||
"args": []string{},
|
||||
},
|
||||
"runtime2": map[string]interface{}{
|
||||
"path": "/test/runtime/dir/runtime2",
|
||||
"args": []string{},
|
||||
},
|
||||
runtimes: map[string]string{
|
||||
"runtime1": "/test/runtime/dir/runtime1",
|
||||
"runtime2": "/test/runtime/dir/runtime2",
|
||||
},
|
||||
expectedConfig: map[string]interface{}{
|
||||
"runtimes": map[string]interface{}{
|
||||
@@ -109,15 +106,9 @@ func TestUpdateConfigRuntimes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
runtimes: map[string]interface{}{
|
||||
"runtime1": map[string]interface{}{
|
||||
"path": "/test/runtime/dir/runtime1",
|
||||
"args": []string{},
|
||||
},
|
||||
"runtime2": map[string]interface{}{
|
||||
"path": "/test/runtime/dir/runtime2",
|
||||
"args": []string{},
|
||||
},
|
||||
runtimes: map[string]string{
|
||||
"runtime1": "/test/runtime/dir/runtime1",
|
||||
"runtime2": "/test/runtime/dir/runtime2",
|
||||
},
|
||||
expectedConfig: map[string]interface{}{
|
||||
"runtimes": map[string]interface{}{
|
||||
@@ -141,11 +132,8 @@ func TestUpdateConfigRuntimes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
runtimes: map[string]interface{}{
|
||||
"runtime1": map[string]interface{}{
|
||||
"path": "/test/runtime/dir/runtime1",
|
||||
"args": []string{},
|
||||
},
|
||||
runtimes: map[string]string{
|
||||
"runtime1": "/test/runtime/dir/runtime1",
|
||||
},
|
||||
expectedConfig: map[string]interface{}{
|
||||
"runtimes": map[string]interface{}{
|
||||
@@ -169,11 +157,8 @@ func TestUpdateConfigRuntimes(t *testing.T) {
|
||||
},
|
||||
"storage-driver": "overlay2",
|
||||
},
|
||||
runtimes: map[string]interface{}{
|
||||
"runtime1": map[string]interface{}{
|
||||
"path": "/test/runtime/dir/runtime1",
|
||||
"args": []string{},
|
||||
},
|
||||
runtimes: map[string]string{
|
||||
"runtime1": "/test/runtime/dir/runtime1",
|
||||
},
|
||||
expectedConfig: map[string]interface{}{
|
||||
"exec-opts": []string{"native.cgroupdriver=systemd"},
|
||||
@@ -212,8 +197,10 @@ func TestUpdateConfigRuntimes(t *testing.T) {
|
||||
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("test case %d", i), func(t *testing.T) {
|
||||
err := UpdateConfig(tc.config, "", tc.runtimes)
|
||||
require.NoError(t, err)
|
||||
for runtimeName, runtimePath := range tc.runtimes {
|
||||
err := UpdateConfig(tc.config, runtimeName, runtimePath, false)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
configContent, err := json.MarshalIndent(tc.config, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
54
internal/config/image/capabilities.go
Normal file
54
internal/config/image/capabilities.go
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
# 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 image
|
||||
|
||||
// DriverCapability represents the possible values of NVIDIA_DRIVER_CAPABILITIES
|
||||
type DriverCapability string
|
||||
|
||||
// Constants for the supported driver capabilities
|
||||
const (
|
||||
DriverCapabilityAll DriverCapability = "all"
|
||||
DriverCapabilityCompat32 DriverCapability = "compat32"
|
||||
DriverCapabilityCompute DriverCapability = "compute"
|
||||
DriverCapabilityDisplay DriverCapability = "display"
|
||||
DriverCapabilityGraphics DriverCapability = "graphics"
|
||||
DriverCapabilityNgx DriverCapability = "ngx"
|
||||
DriverCapabilityUtility DriverCapability = "utility"
|
||||
DriverCapabilityVideo DriverCapability = "video"
|
||||
)
|
||||
|
||||
// DriverCapabilities represents the NVIDIA_DRIVER_CAPABILITIES set for the specified image.
|
||||
type DriverCapabilities map[DriverCapability]bool
|
||||
|
||||
// Has check whether the specified capability is selected.
|
||||
func (c DriverCapabilities) Has(capability DriverCapability) bool {
|
||||
if c[DriverCapabilityAll] {
|
||||
return true
|
||||
}
|
||||
return c[capability]
|
||||
}
|
||||
|
||||
// Any checks whether any of the specified capabilites are set
|
||||
func (c DriverCapabilities) Any(capabilities ...DriverCapability) bool {
|
||||
for _, cap := range capabilities {
|
||||
if c.Has(cap) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -26,11 +26,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
envCUDAVersion = "CUDA_VERSION"
|
||||
envNVRequirePrefix = "NVIDIA_REQUIRE_"
|
||||
envNVRequireCUDA = envNVRequirePrefix + "CUDA"
|
||||
envNVRequireJetpack = envNVRequirePrefix + "JETPACK"
|
||||
envNVDisableRequire = "NVIDIA_DISABLE_REQUIRE"
|
||||
envCUDAVersion = "CUDA_VERSION"
|
||||
envNVRequirePrefix = "NVIDIA_REQUIRE_"
|
||||
envNVRequireCUDA = envNVRequirePrefix + "CUDA"
|
||||
envNVRequireJetpack = envNVRequirePrefix + "JETPACK"
|
||||
envNVDisableRequire = "NVIDIA_DISABLE_REQUIRE"
|
||||
envNVDriverCapabilities = "NVIDIA_DRIVER_CAPABILITIES"
|
||||
)
|
||||
|
||||
// CUDA represents a CUDA image that can be used for GPU computing. This wraps
|
||||
@@ -113,33 +114,48 @@ func (i CUDA) HasDisableRequire() bool {
|
||||
}
|
||||
|
||||
// DevicesFromEnvvars returns the devices requested by the image through environment variables
|
||||
func (i CUDA) DevicesFromEnvvars(envVars ...string) []string {
|
||||
// Grab a reference to devices from the first envvar
|
||||
// in the list that actually exists in the environment.
|
||||
var devices *string
|
||||
func (i CUDA) DevicesFromEnvvars(envVars ...string) VisibleDevices {
|
||||
// We concantenate all the devices from the specified envvars.
|
||||
var isSet bool
|
||||
var devices []string
|
||||
requested := make(map[string]bool)
|
||||
for _, envVar := range envVars {
|
||||
if devs, ok := i[envVar]; ok {
|
||||
devices = &devs
|
||||
break
|
||||
isSet = true
|
||||
for _, d := range strings.Split(devs, ",") {
|
||||
trimmed := strings.TrimSpace(d)
|
||||
if len(trimmed) == 0 {
|
||||
continue
|
||||
}
|
||||
devices = append(devices, trimmed)
|
||||
requested[trimmed] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Environment variable unset with legacy image: default to "all".
|
||||
if devices == nil && i.IsLegacy() {
|
||||
return []string{"all"}
|
||||
if !isSet && len(devices) == 0 && i.IsLegacy() {
|
||||
return NewVisibleDevices("all")
|
||||
}
|
||||
|
||||
// Environment variable unset or empty or "void": return nil
|
||||
if devices == nil || len(*devices) == 0 || *devices == "void" {
|
||||
return nil
|
||||
if len(devices) == 0 || requested["void"] {
|
||||
return NewVisibleDevices("void")
|
||||
}
|
||||
|
||||
// Environment variable set to "none": reset to "".
|
||||
if *devices == "none" {
|
||||
return []string{""}
|
||||
return NewVisibleDevices(devices...)
|
||||
}
|
||||
|
||||
// GetDriverCapabilities returns the requested driver capabilities.
|
||||
func (i CUDA) GetDriverCapabilities() DriverCapabilities {
|
||||
env := i[envNVDriverCapabilities]
|
||||
|
||||
capabilites := make(DriverCapabilities)
|
||||
for _, c := range strings.Split(env, ",") {
|
||||
capabilites[DriverCapability(c)] = true
|
||||
}
|
||||
|
||||
return strings.Split(*devices, ",")
|
||||
return capabilites
|
||||
}
|
||||
|
||||
func (i CUDA) legacyVersion() (string, error) {
|
||||
|
||||
127
internal/config/image/devices.go
Normal file
127
internal/config/image/devices.go
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
# 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 image
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// VisibleDevices represents the devices selected in a container image
|
||||
// through the NVIDIA_VISIBLE_DEVICES or other environment variables
|
||||
type VisibleDevices interface {
|
||||
List() []string
|
||||
Has(string) bool
|
||||
}
|
||||
|
||||
var _ VisibleDevices = (*all)(nil)
|
||||
var _ VisibleDevices = (*none)(nil)
|
||||
var _ VisibleDevices = (*void)(nil)
|
||||
var _ VisibleDevices = (*devices)(nil)
|
||||
|
||||
// NewVisibleDevices creates a VisibleDevices based on the value of the specified envvar.
|
||||
func NewVisibleDevices(envvars ...string) VisibleDevices {
|
||||
for _, envvar := range envvars {
|
||||
if envvar == "all" {
|
||||
return all{}
|
||||
}
|
||||
if envvar == "none" {
|
||||
return none{}
|
||||
}
|
||||
if envvar == "" || envvar == "void" {
|
||||
return void{}
|
||||
}
|
||||
}
|
||||
|
||||
return newDevices(envvars...)
|
||||
}
|
||||
|
||||
type all struct{}
|
||||
|
||||
// List returns ["all"] for all devices
|
||||
func (a all) List() []string {
|
||||
return []string{"all"}
|
||||
}
|
||||
|
||||
// Has for all devices is true for any id except the empty ID
|
||||
func (a all) Has(id string) bool {
|
||||
return id != ""
|
||||
}
|
||||
|
||||
type none struct{}
|
||||
|
||||
// List returns [""] for the none devices
|
||||
func (n none) List() []string {
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
// Has for none devices is false for any id
|
||||
func (n none) Has(id string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type void struct {
|
||||
none
|
||||
}
|
||||
|
||||
// List returns nil for the void devices
|
||||
func (v void) List() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type devices struct {
|
||||
len int
|
||||
lookup map[string]int
|
||||
}
|
||||
|
||||
func newDevices(idOrCommaSeparated ...string) devices {
|
||||
lookup := make(map[string]int)
|
||||
|
||||
i := 0
|
||||
for _, commaSeparated := range idOrCommaSeparated {
|
||||
for _, id := range strings.Split(commaSeparated, ",") {
|
||||
lookup[id] = i
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
d := devices{
|
||||
len: i,
|
||||
lookup: lookup,
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// List returns the list of requested devices
|
||||
func (d devices) List() []string {
|
||||
list := make([]string, d.len)
|
||||
|
||||
for id, i := range d.lookup {
|
||||
list[i] = id
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// Has checks whether the specified ID is in the set of requested devices
|
||||
func (d devices) Has(id string) bool {
|
||||
if id == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
_, exist := d.lookup[id]
|
||||
return exist
|
||||
}
|
||||
62
internal/discover/filter.go
Normal file
62
internal/discover/filter.go
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
# 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 discover
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// Filter defines an interface for filtering discovered entities
|
||||
type Filter interface {
|
||||
DeviceIsSelected(device Device) bool
|
||||
}
|
||||
|
||||
// filtered represents a filtered discoverer
|
||||
type filtered struct {
|
||||
Discover
|
||||
logger *logrus.Logger
|
||||
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 {
|
||||
return filtered{
|
||||
Discover: applyTo,
|
||||
logger: logger,
|
||||
filter: filter,
|
||||
}
|
||||
}
|
||||
|
||||
// Devices returns a filtered list of devices based on the specified filter.
|
||||
func (d filtered) Devices() ([]Device, error) {
|
||||
devices, err := d.Discover.Devices()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if d.filter == nil {
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
var selected []Device
|
||||
for _, device := range devices {
|
||||
if d.filter.DeviceIsSelected(device) {
|
||||
selected = append(selected, device)
|
||||
}
|
||||
d.logger.Debugf("skipping device %v", device)
|
||||
}
|
||||
|
||||
return selected, nil
|
||||
}
|
||||
254
internal/discover/graphics.go
Normal file
254
internal/discover/graphics.go
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
# 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 discover
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"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/lookup"
|
||||
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
"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) {
|
||||
root := cfg.Root
|
||||
|
||||
locator, err := lookup.NewLibraryLocator(logger, root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct library locator: %v", err)
|
||||
}
|
||||
libraries := NewMounts(
|
||||
logger,
|
||||
locator,
|
||||
root,
|
||||
[]string{
|
||||
"libnvidia-egl-gbm.so",
|
||||
},
|
||||
)
|
||||
|
||||
jsonMounts := NewMounts(
|
||||
logger,
|
||||
lookup.NewFileLocator(logger, root),
|
||||
root,
|
||||
[]string{
|
||||
// TODO: We should handle this more cleanly
|
||||
"/etc/glvnd/egl_vendor.d/10_nvidia.json",
|
||||
"/etc/vulkan/icd.d/nvidia_icd.json",
|
||||
"/etc/vulkan/implicit_layer.d/nvidia_layers.json",
|
||||
"/usr/share/glvnd/egl_vendor.d/10_nvidia.json",
|
||||
"/usr/share/vulkan/icd.d/nvidia_icd.json",
|
||||
"/usr/share/vulkan/implicit_layer.d/nvidia_layers.json",
|
||||
"/usr/share/egl/egl_external_platform.d/15_nvidia_gbm.json",
|
||||
},
|
||||
)
|
||||
|
||||
drmDeviceNodes, err := newDRMDeviceDiscoverer(logger, devices, root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create DRM device discoverer: %v", err)
|
||||
}
|
||||
|
||||
drmByPathSymlinks := newCreateDRMByPathSymlinks(logger, drmDeviceNodes, cfg)
|
||||
|
||||
discover := Merge(
|
||||
Merge(drmDeviceNodes, drmByPathSymlinks),
|
||||
libraries,
|
||||
jsonMounts,
|
||||
)
|
||||
|
||||
return discover, nil
|
||||
}
|
||||
|
||||
type drmDevicesByPath struct {
|
||||
None
|
||||
logger *logrus.Logger
|
||||
lookup lookup.Locator
|
||||
nvidiaCTKExecutablePath string
|
||||
root 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 {
|
||||
d := drmDevicesByPath{
|
||||
logger: logger,
|
||||
lookup: lookup.NewExecutableLocator(logger, cfg.Root),
|
||||
nvidiaCTKExecutablePath: cfg.NVIDIAContainerToolkitCLIExecutablePath,
|
||||
root: cfg.Root,
|
||||
devicesFrom: devices,
|
||||
}
|
||||
|
||||
return &d
|
||||
}
|
||||
|
||||
// Hooks returns a hook to create the symlinks from the required CSV files
|
||||
func (d drmDevicesByPath) Hooks() ([]Hook, error) {
|
||||
devices, err := d.devicesFrom.Devices()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to discover devices for by-path symlinks: %v", err)
|
||||
}
|
||||
if len(devices) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hookPath := nvidiaCTKDefaultFilePath
|
||||
targets, err := d.lookup.Locate(d.nvidiaCTKExecutablePath)
|
||||
if err != nil {
|
||||
d.logger.Warnf("Failed to locate %v: %v", d.nvidiaCTKExecutablePath, err)
|
||||
} else if len(targets) == 0 {
|
||||
d.logger.Warnf("%v not found", d.nvidiaCTKExecutablePath)
|
||||
} else {
|
||||
d.logger.Debugf("Found %v candidates: %v", d.nvidiaCTKExecutablePath, targets)
|
||||
hookPath = targets[0]
|
||||
}
|
||||
d.logger.Debugf("Using NVIDIA Container Toolkit CLI path %v", hookPath)
|
||||
|
||||
args := []string{hookPath, "hook", "create-symlinks"}
|
||||
links, err := d.getSpecificLinkArgs(devices)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to determine specific links: %v", err)
|
||||
}
|
||||
for _, l := range links {
|
||||
args = append(args, "--link", l)
|
||||
}
|
||||
|
||||
h := Hook{
|
||||
Lifecycle: cdi.CreateContainerHook,
|
||||
Path: hookPath,
|
||||
Args: args,
|
||||
}
|
||||
|
||||
return []Hook{h}, nil
|
||||
}
|
||||
|
||||
// getSpecificLinkArgs returns the required specic links that need to be created
|
||||
func (d drmDevicesByPath) getSpecificLinkArgs(devices []Device) ([]string, error) {
|
||||
selectedDevices := make(map[string]bool)
|
||||
for _, d := range devices {
|
||||
selectedDevices[filepath.Base(d.HostPath)] = true
|
||||
}
|
||||
|
||||
linkLocator := lookup.NewFileLocator(d.logger, d.root)
|
||||
candidates, err := linkLocator.Locate("/dev/dri/by-path/pci-*-*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to locate devices by path: %v", err)
|
||||
}
|
||||
|
||||
var links []string
|
||||
for _, c := range candidates {
|
||||
device, err := os.Readlink(c)
|
||||
if err != nil {
|
||||
d.logger.Warningf("Failed to evaluate symlink %v; ignoring", c)
|
||||
continue
|
||||
}
|
||||
|
||||
if selectedDevices[filepath.Base(device)] {
|
||||
d.logger.Debugf("adding device symlink %v -> %v", c, device)
|
||||
links = append(links, fmt.Sprintf("%v::%v", device, c))
|
||||
}
|
||||
}
|
||||
|
||||
return links, nil
|
||||
}
|
||||
|
||||
// newDRMDeviceDiscoverer creates a discoverer for the DRM devices associated with the requested devices.
|
||||
func newDRMDeviceDiscoverer(logger *logrus.Logger, devices image.VisibleDevices, root string) (Discover, error) {
|
||||
allDevices := NewDeviceDiscoverer(
|
||||
logger,
|
||||
lookup.NewCharDeviceLocator(logger, root),
|
||||
root,
|
||||
[]string{
|
||||
"/dev/dri/card*",
|
||||
"/dev/dri/renderD*",
|
||||
},
|
||||
)
|
||||
|
||||
filter, err := newDRMDeviceFilter(logger, devices, root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct DRM device filter: %v", err)
|
||||
}
|
||||
|
||||
// We return a discoverer that applies the DRM device filter created above to all discovered DRM device nodes.
|
||||
d := newFilteredDisoverer(
|
||||
logger,
|
||||
allDevices,
|
||||
filter,
|
||||
)
|
||||
|
||||
return d, err
|
||||
}
|
||||
|
||||
// newDRMDeviceFilter creates a filter that matches DRM devices nodes for the visible devices.
|
||||
func newDRMDeviceFilter(logger *logrus.Logger, devices image.VisibleDevices, root string) (Filter, error) {
|
||||
gpuInformationPaths, err := proc.GetInformationFilePaths(root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read GPU information: %v", err)
|
||||
}
|
||||
|
||||
var selectedBusIds []string
|
||||
for _, f := range gpuInformationPaths {
|
||||
info, err := proc.ParseGPUInformationFile(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %v: %v", f, err)
|
||||
}
|
||||
uuid := info[proc.GPUInfoGPUUUID]
|
||||
busID := info[proc.GPUInfoBusLocation]
|
||||
minor := info[proc.GPUInfoDeviceMinor]
|
||||
|
||||
if devices.Has(minor) || devices.Has(uuid) || devices.Has(busID) {
|
||||
selectedBusIds = append(selectedBusIds, busID)
|
||||
}
|
||||
}
|
||||
|
||||
filter := make(selectDeviceByPath)
|
||||
for _, busID := range selectedBusIds {
|
||||
drmDeviceNodes, err := drm.GetDeviceNodesByBusID(busID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to determine DRM devices for %v: %v", busID, err)
|
||||
}
|
||||
for _, drmDeviceNode := range drmDeviceNodes {
|
||||
filter[filepath.Join(drmDeviceNode)] = true
|
||||
}
|
||||
}
|
||||
|
||||
return filter, nil
|
||||
}
|
||||
|
||||
// selectDeviceByPath is a filter that allows devices to be selected by the path
|
||||
type selectDeviceByPath map[string]bool
|
||||
|
||||
var _ Filter = (*selectDeviceByPath)(nil)
|
||||
|
||||
// DeviceIsSelected determines whether the device's path has been selected
|
||||
func (s selectDeviceByPath) DeviceIsSelected(device Device) bool {
|
||||
return s[device.Path]
|
||||
}
|
||||
|
||||
// MountIsSelected is always true
|
||||
func (s selectDeviceByPath) MountIsSelected(Mount) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// HookIsSelected is always true
|
||||
func (s selectDeviceByPath) HookIsSelected(Hook) bool {
|
||||
return true
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package discover
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
@@ -57,58 +56,50 @@ func (d ldconfig) Hooks() ([]Hook, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to discover mounts for ldcache update: %v", err)
|
||||
}
|
||||
h := CreateLDCacheUpdateHook(
|
||||
d.logger,
|
||||
d.lookup,
|
||||
d.nvidiaCTKExecutablePath,
|
||||
nvidiaCTKDefaultFilePath,
|
||||
getLibraryPaths(mounts),
|
||||
)
|
||||
return []Hook{h}, nil
|
||||
}
|
||||
|
||||
libDirs := getLibDirs(mounts)
|
||||
|
||||
hookPath := nvidiaCTKDefaultFilePath
|
||||
targets, err := d.lookup.Locate(d.nvidiaCTKExecutablePath)
|
||||
// CreateLDCacheUpdateHook locates the NVIDIA Container Toolkit CLI and creates a hook for updating the LD Cache
|
||||
func CreateLDCacheUpdateHook(logger *logrus.Logger, lookup lookup.Locator, execuable string, defaultPath string, libraries []string) Hook {
|
||||
hookPath := defaultPath
|
||||
targets, err := lookup.Locate(execuable)
|
||||
if err != nil {
|
||||
d.logger.Warnf("Failed to locate %v: %v", d.nvidiaCTKExecutablePath, err)
|
||||
logger.Warnf("Failed to locate %v: %v", execuable, err)
|
||||
} else if len(targets) == 0 {
|
||||
d.logger.Warnf("%v not found", d.nvidiaCTKExecutablePath)
|
||||
logger.Warnf("%v not found", execuable)
|
||||
} else {
|
||||
d.logger.Debugf("Found %v candidates: %v", d.nvidiaCTKExecutablePath, targets)
|
||||
logger.Debugf("Found %v candidates: %v", execuable, targets)
|
||||
hookPath = targets[0]
|
||||
}
|
||||
d.logger.Debugf("Using NVIDIA Container Toolkit CLI path %v", hookPath)
|
||||
logger.Debugf("Using NVIDIA Container Toolkit CLI path %v", hookPath)
|
||||
|
||||
args := []string{hookPath, "hook", "update-ldcache"}
|
||||
for _, f := range libDirs {
|
||||
args := []string{filepath.Base(hookPath), "hook", "update-ldcache"}
|
||||
for _, f := range uniqueFolders(libraries) {
|
||||
args = append(args, "--folder", f)
|
||||
}
|
||||
h := Hook{
|
||||
return Hook{
|
||||
Lifecycle: cdi.CreateContainerHook,
|
||||
Path: hookPath,
|
||||
Args: args,
|
||||
}
|
||||
|
||||
return []Hook{h}, nil
|
||||
}
|
||||
|
||||
// getLibDirs extracts the library dirs from the specified mounts
|
||||
func getLibDirs(mounts []Mount) []string {
|
||||
// getLibraryPaths extracts the library dirs from the specified mounts
|
||||
func getLibraryPaths(mounts []Mount) []string {
|
||||
var paths []string
|
||||
checked := make(map[string]bool)
|
||||
|
||||
for _, m := range mounts {
|
||||
dir := filepath.Dir(m.Path)
|
||||
if dir == "" {
|
||||
if !isLibName(m.Path) {
|
||||
continue
|
||||
}
|
||||
|
||||
_, exists := checked[dir]
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
checked[dir] = isLibName(m.Path)
|
||||
|
||||
if checked[dir] {
|
||||
paths = append(paths, dir)
|
||||
}
|
||||
paths = append(paths, m.Path)
|
||||
}
|
||||
|
||||
sort.Strings(paths)
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
@@ -129,3 +120,22 @@ func isLibName(filename string) bool {
|
||||
|
||||
return parts[len(parts)-1] == "" || strings.HasPrefix(parts[len(parts)-1], ".")
|
||||
}
|
||||
|
||||
// uniqueFolders returns the unique set of folders for the specified files
|
||||
func uniqueFolders(libraries []string) []string {
|
||||
var paths []string
|
||||
checked := make(map[string]bool)
|
||||
|
||||
for _, l := range libraries {
|
||||
dir := filepath.Dir(l)
|
||||
if dir == "" {
|
||||
continue
|
||||
}
|
||||
if checked[dir] {
|
||||
continue
|
||||
}
|
||||
checked[dir] = true
|
||||
paths = append(paths, dir)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
@@ -17,11 +17,110 @@
|
||||
package discover
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLDCacheUpdateHook(t *testing.T) {
|
||||
logger, _ := testlog.NewNullLogger()
|
||||
|
||||
cfg := Config{
|
||||
Root: "/",
|
||||
NVIDIAContainerToolkitCLIExecutablePath: "/foo/bar/nvidia-ctk",
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
description string
|
||||
mounts []Mount
|
||||
mountError error
|
||||
expectedError error
|
||||
expectedArgs []string
|
||||
}{
|
||||
{
|
||||
description: "empty mounts",
|
||||
expectedArgs: []string{"nvidia-ctk", "hook", "update-ldcache"},
|
||||
},
|
||||
{
|
||||
description: "mount error",
|
||||
mountError: fmt.Errorf("mountError"),
|
||||
expectedError: fmt.Errorf("mountError"),
|
||||
},
|
||||
{
|
||||
description: "library folders are added to args",
|
||||
mounts: []Mount{
|
||||
{
|
||||
Path: "/usr/local/lib/libfoo.so",
|
||||
},
|
||||
{
|
||||
Path: "/usr/bin/notlib",
|
||||
},
|
||||
{
|
||||
Path: "/usr/local/libother/libfoo.so",
|
||||
},
|
||||
{
|
||||
Path: "/usr/local/lib/libbar.so",
|
||||
},
|
||||
},
|
||||
expectedArgs: []string{"nvidia-ctk", "hook", "update-ldcache", "--folder", "/usr/local/lib", "--folder", "/usr/local/libother"},
|
||||
},
|
||||
{
|
||||
description: "host paths are ignored",
|
||||
mounts: []Mount{
|
||||
{
|
||||
HostPath: "/usr/local/other/libfoo.so",
|
||||
Path: "/usr/local/lib/libfoo.so",
|
||||
},
|
||||
},
|
||||
expectedArgs: []string{"nvidia-ctk", "hook", "update-ldcache", "--folder", "/usr/local/lib"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
mountMock := &DiscoverMock{
|
||||
MountsFunc: func() ([]Mount, error) {
|
||||
return tc.mounts, tc.mountError
|
||||
},
|
||||
}
|
||||
expectedHook := Hook{
|
||||
Path: "/usr/bin/nvidia-ctk",
|
||||
Args: tc.expectedArgs,
|
||||
Lifecycle: "createContainer",
|
||||
}
|
||||
|
||||
d, err := NewLDCacheUpdateHook(logger, mountMock, &cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
hooks, err := d.Hooks()
|
||||
require.Len(t, mountMock.MountsCalls(), 1)
|
||||
require.Len(t, mountMock.DevicesCalls(), 0)
|
||||
require.Len(t, mountMock.HooksCalls(), 0)
|
||||
if tc.expectedError != nil {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, hooks, 1)
|
||||
|
||||
require.EqualValues(t, hooks[0], expectedHook)
|
||||
|
||||
devices, err := d.Devices()
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, devices)
|
||||
|
||||
mounts, err := d.Mounts()
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, mounts)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestIsLibName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
||||
@@ -117,7 +117,7 @@ func (d symlinks) getSpecificLinkArgs() ([]string, error) {
|
||||
}
|
||||
|
||||
linkPath := filepath.Join(filepath.Dir(m.Path), link)
|
||||
links = append(links, "--link", fmt.Sprintf("%v:%v", target, linkPath))
|
||||
links = append(links, "--link", fmt.Sprintf("%v::%v", target, linkPath))
|
||||
linkProcessed[link] = true
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package info
|
||||
|
||||
import "gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvinfo"
|
||||
import "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.
|
||||
@@ -34,10 +34,12 @@ func ResolveAutoMode(logger Logger, mode string) (rmode string) {
|
||||
logger.Infof("Auto-detected mode as '%v'", rmode)
|
||||
}()
|
||||
|
||||
nvinfo := info.New()
|
||||
|
||||
isTegra, reason := nvinfo.IsTegraSystem()
|
||||
logger.Debugf("Is Tegra-based system? %v: %v", isTegra, reason)
|
||||
|
||||
hasNVML, reason := nvinfo.HasNVML()
|
||||
hasNVML, reason := nvinfo.HasNvml()
|
||||
logger.Debugf("Has NVML? %v: %v", hasNVML, reason)
|
||||
|
||||
if isTegra && !hasNVML {
|
||||
|
||||
39
internal/info/drm/drm_devices.go
Normal file
39
internal/info/drm/drm_devices.go
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
# 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 drm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// GetDeviceNodesByBusID returns the DRM devices associated with the specified PCI bus ID
|
||||
func GetDeviceNodesByBusID(busID string) ([]string, error) {
|
||||
drmRoot := filepath.Join("/sys/bus/pci/devices", busID, "drm")
|
||||
matches, err := filepath.Glob(fmt.Sprintf("%s/*", drmRoot))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var drmDeviceNodes []string
|
||||
for _, m := range matches {
|
||||
drmDeviceNode := filepath.Join("/dev/dri", filepath.Base(m))
|
||||
drmDeviceNodes = append(drmDeviceNodes, drmDeviceNode)
|
||||
}
|
||||
|
||||
return drmDeviceNodes, nil
|
||||
}
|
||||
89
internal/info/proc/information_files.go
Normal file
89
internal/info/proc/information_files.go
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
# 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 proc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GPUInfoField represents the field name for information specified in a GPU's information file
|
||||
type GPUInfoField string
|
||||
|
||||
// The following constants define the fields of interest from the GPU information file
|
||||
const (
|
||||
GPUInfoModel = GPUInfoField("Model")
|
||||
GPUInfoGPUUUID = GPUInfoField("GPU UUID")
|
||||
GPUInfoBusLocation = GPUInfoField("Bus Location")
|
||||
GPUInfoDeviceMinor = GPUInfoField("Device Minor")
|
||||
)
|
||||
|
||||
// GPUInfo stores the information for a GPU as determined from its associated information file
|
||||
type GPUInfo map[GPUInfoField]string
|
||||
|
||||
// GetInformationFilePaths returns the list of information files associated with NVIDIA GPUs.
|
||||
func GetInformationFilePaths(root string) ([]string, error) {
|
||||
return filepath.Glob(filepath.Join(root, "/proc/driver/nvidia/gpus/*/information"))
|
||||
}
|
||||
|
||||
// ParseGPUInformationFile parses the specified GPU information file and constructs a GPUInfo structure
|
||||
func ParseGPUInformationFile(path string) (GPUInfo, error) {
|
||||
infoFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open %v: %v", path, err)
|
||||
}
|
||||
defer infoFile.Close()
|
||||
|
||||
return gpuInfoFrom(infoFile), nil
|
||||
}
|
||||
|
||||
// gpuInfoFrom parses a GPUInfo struct from the specified reader
|
||||
// An information file has the following strucutre:
|
||||
// $ cat /proc/driver/nvidia/gpus/0000\:06\:00.0/information
|
||||
// Model: Tesla V100-SXM2-16GB
|
||||
// IRQ: 408
|
||||
// GPU UUID: GPU-edfee158-11c1-52b8-0517-92f30e7fac88
|
||||
// Video BIOS: 88.00.41.00.01
|
||||
// Bus Type: PCIe
|
||||
// DMA Size: 47 bits
|
||||
// DMA Mask: 0x7fffffffffff
|
||||
// Bus Location: 0000:06:00.0
|
||||
// Device Minor: 0
|
||||
// GPU Excluded: No
|
||||
func gpuInfoFrom(reader io.Reader) GPUInfo {
|
||||
info := make(GPUInfo)
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
field := GPUInfoField(parts[0])
|
||||
value := strings.TrimSpace(parts[1])
|
||||
|
||||
info[field] = value
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
292
internal/ldcache/ldcache.go
Normal file
292
internal/ldcache/ldcache.go
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
# Copyright (c) 2021-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.
|
||||
*/
|
||||
|
||||
// Adapted from https://github.com/rai-project/ldcache
|
||||
|
||||
package ldcache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const ldcachePath = "/etc/ld.so.cache"
|
||||
|
||||
const (
|
||||
magicString1 = "ld.so-1.7.0"
|
||||
magicString2 = "glibc-ld.so.cache"
|
||||
magicVersion = "1.1"
|
||||
)
|
||||
|
||||
const (
|
||||
flagTypeMask = 0x00ff
|
||||
flagTypeELF = 0x0001
|
||||
|
||||
flagArchMask = 0xff00
|
||||
flagArchI386 = 0x0000
|
||||
flagArchX8664 = 0x0300
|
||||
flagArchX32 = 0x0800
|
||||
flagArchPpc64le = 0x0500
|
||||
)
|
||||
|
||||
var errInvalidCache = errors.New("invalid ld.so.cache file")
|
||||
|
||||
type header1 struct {
|
||||
Magic [len(magicString1) + 1]byte // include null delimiter
|
||||
NLibs uint32
|
||||
}
|
||||
|
||||
type entry1 struct {
|
||||
Flags int32
|
||||
Key, Value uint32
|
||||
}
|
||||
|
||||
type header2 struct {
|
||||
Magic [len(magicString2)]byte
|
||||
Version [len(magicVersion)]byte
|
||||
NLibs uint32
|
||||
TableSize uint32
|
||||
_ [3]uint32 // unused
|
||||
_ uint64 // force 8 byte alignment
|
||||
}
|
||||
|
||||
type entry2 struct {
|
||||
Flags int32
|
||||
Key, Value uint32
|
||||
OSVersion uint32
|
||||
HWCap uint64
|
||||
}
|
||||
|
||||
// LDCache represents the interface for performing lookups into the LDCache
|
||||
type LDCache interface {
|
||||
List() ([]string, []string)
|
||||
Lookup(...string) ([]string, []string)
|
||||
}
|
||||
|
||||
type ldcache struct {
|
||||
*bytes.Reader
|
||||
|
||||
data, libs []byte
|
||||
header header2
|
||||
entries []entry2
|
||||
|
||||
root string
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// New creates a new LDCache with the specified logger and root.
|
||||
func New(logger *log.Logger, root string) (LDCache, error) {
|
||||
path := filepath.Join(root, ldcachePath)
|
||||
|
||||
logger.Debugf("Opening ld.conf at %v", path)
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d, err := syscall.Mmap(int(f.Fd()), 0, int(fi.Size()),
|
||||
syscall.PROT_READ, syscall.MAP_PRIVATE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cache := &ldcache{
|
||||
data: d,
|
||||
Reader: bytes.NewReader(d),
|
||||
root: root,
|
||||
logger: logger,
|
||||
}
|
||||
return cache, cache.parse()
|
||||
}
|
||||
|
||||
func (c *ldcache) Close() error {
|
||||
return syscall.Munmap(c.data)
|
||||
}
|
||||
|
||||
func (c *ldcache) Magic() string {
|
||||
return string(c.header.Magic[:])
|
||||
}
|
||||
|
||||
func (c *ldcache) Version() string {
|
||||
return string(c.header.Version[:])
|
||||
}
|
||||
|
||||
func strn(b []byte, n int) string {
|
||||
return string(b[:n])
|
||||
}
|
||||
|
||||
func (c *ldcache) parse() error {
|
||||
var header header1
|
||||
|
||||
// Check for the old format (< glibc-2.2)
|
||||
if c.Len() <= int(unsafe.Sizeof(header)) {
|
||||
return errInvalidCache
|
||||
}
|
||||
if strn(c.data, len(magicString1)) == magicString1 {
|
||||
if err := binary.Read(c, binary.LittleEndian, &header); err != nil {
|
||||
return err
|
||||
}
|
||||
n := int64(header.NLibs) * int64(unsafe.Sizeof(entry1{}))
|
||||
offset, err := c.Seek(n, 1) // skip old entries
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n = (-offset) & int64(unsafe.Alignof(c.header)-1)
|
||||
_, err = c.Seek(n, 1) // skip padding
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.libs = c.data[c.Size()-int64(c.Len()):] // kv offsets start here
|
||||
if err := binary.Read(c, binary.LittleEndian, &c.header); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Magic() != magicString2 || c.Version() != magicVersion {
|
||||
return errInvalidCache
|
||||
}
|
||||
c.entries = make([]entry2, c.header.NLibs)
|
||||
if err := binary.Read(c, binary.LittleEndian, &c.entries); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List creates a list of libraires in the ldcache.
|
||||
// The 32-bit and 64-bit libraries are returned separately.
|
||||
func (c *ldcache) List() ([]string, []string) {
|
||||
paths := make(map[int][]string)
|
||||
|
||||
processed := make(map[string]bool)
|
||||
|
||||
for _, e := range c.entries {
|
||||
bits := 0
|
||||
if ((e.Flags & flagTypeMask) & flagTypeELF) == 0 {
|
||||
continue
|
||||
}
|
||||
switch e.Flags & flagArchMask {
|
||||
case flagArchX8664:
|
||||
fallthrough
|
||||
case flagArchPpc64le:
|
||||
bits = 64
|
||||
case flagArchX32:
|
||||
fallthrough
|
||||
case flagArchI386:
|
||||
bits = 32
|
||||
default:
|
||||
continue
|
||||
}
|
||||
if e.Key > uint32(len(c.libs)) || e.Value > uint32(len(c.libs)) {
|
||||
continue
|
||||
}
|
||||
value := c.libs[e.Value:]
|
||||
|
||||
n := bytes.IndexByte(value, 0)
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
name := filepath.Join(c.root, strn(value, n))
|
||||
c.logger.Debugf("checking %v", string(name))
|
||||
|
||||
path, err := filepath.EvalSymlinks(name)
|
||||
if err != nil {
|
||||
c.logger.Debugf("could not resolve symlink for %v", name)
|
||||
break
|
||||
}
|
||||
if processed[path] {
|
||||
continue
|
||||
}
|
||||
paths[bits] = append(paths[bits], path)
|
||||
processed[path] = true
|
||||
}
|
||||
|
||||
return paths[32], paths[64]
|
||||
}
|
||||
|
||||
// Lookup searches the ldcache for the specified prefixes.
|
||||
// The 32-bit and 64-bit libraries matching the prefixes are returned.
|
||||
func (c *ldcache) Lookup(libs ...string) (paths32, paths64 []string) {
|
||||
c.logger.Debugf("Looking up %v in cache", libs)
|
||||
type void struct{}
|
||||
var paths *[]string
|
||||
|
||||
set := make(map[string]void)
|
||||
prefix := make([][]byte, len(libs))
|
||||
|
||||
for i := range libs {
|
||||
prefix[i] = []byte(libs[i])
|
||||
}
|
||||
for _, e := range c.entries {
|
||||
if ((e.Flags & flagTypeMask) & flagTypeELF) == 0 {
|
||||
continue
|
||||
}
|
||||
switch e.Flags & flagArchMask {
|
||||
case flagArchX8664:
|
||||
fallthrough
|
||||
case flagArchPpc64le:
|
||||
paths = &paths64
|
||||
case flagArchX32:
|
||||
fallthrough
|
||||
case flagArchI386:
|
||||
paths = &paths32
|
||||
default:
|
||||
continue
|
||||
}
|
||||
if e.Key > uint32(len(c.libs)) || e.Value > uint32(len(c.libs)) {
|
||||
continue
|
||||
}
|
||||
lib := c.libs[e.Key:]
|
||||
value := c.libs[e.Value:]
|
||||
|
||||
for _, p := range prefix {
|
||||
if bytes.HasPrefix(lib, p) {
|
||||
n := bytes.IndexByte(value, 0)
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
name := filepath.Join(c.root, strn(value, n))
|
||||
c.logger.Debugf("checking %v", string(name))
|
||||
|
||||
path, err := filepath.EvalSymlinks(name)
|
||||
if err != nil {
|
||||
c.logger.Debugf("could not resolve symlink for %v", name)
|
||||
break
|
||||
}
|
||||
if _, ok := set[path]; ok {
|
||||
break
|
||||
}
|
||||
set[path] = void{}
|
||||
*paths = append(*paths, path)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
68
internal/lookup/library.go
Normal file
68
internal/lookup/library.go
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
# Copyright (c) 2021, 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 lookup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type library struct {
|
||||
logger *log.Logger
|
||||
symlink Locator
|
||||
cache ldcache.LDCache
|
||||
}
|
||||
|
||||
var _ Locator = (*library)(nil)
|
||||
|
||||
// NewLibraryLocator creates a library locator using the specified logger.
|
||||
func NewLibraryLocator(logger *log.Logger, root string) (Locator, error) {
|
||||
cache, err := ldcache.New(logger, root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading ldcache: %v", err)
|
||||
}
|
||||
|
||||
l := library{
|
||||
symlink: NewSymlinkLocator(logger, root),
|
||||
cache: cache,
|
||||
}
|
||||
|
||||
return &l, nil
|
||||
}
|
||||
|
||||
// Locate finds the specified libraryname.
|
||||
// If the input is a library name, the ldcache is searched otherwise the
|
||||
// provided path is resolved as a symlink.
|
||||
func (l library) Locate(libname string) ([]string, error) {
|
||||
if strings.Contains(libname, "/") {
|
||||
return l.symlink.Locate(libname)
|
||||
}
|
||||
|
||||
paths32, paths64 := l.cache.Lookup(libname)
|
||||
if len(paths32) > 0 {
|
||||
l.logger.Warnf("Ignoring 32-bit libraries for %v: %v", libname, paths32)
|
||||
}
|
||||
|
||||
if len(paths64) == 0 {
|
||||
return nil, fmt.Errorf("64-bit library %v not found", libname)
|
||||
}
|
||||
|
||||
return paths64, nil
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func getDevicesFromSpec(ociSpec oci.Spec) ([]string, error) {
|
||||
}
|
||||
|
||||
uniqueDevices := make(map[string]struct{})
|
||||
for _, name := range append(envDevices, annotationDevices...) {
|
||||
for _, name := range append(envDevices.List(), annotationDevices...) {
|
||||
if !cdi.IsQualifiedName(name) {
|
||||
name = cdi.QualifiedName("nvidia.com", "gpu", name)
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func NewCSVModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if devices := image.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices) == 0 {
|
||||
if devices := image.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices.List()) == 0 {
|
||||
logger.Infof("No modification required; no devices requested")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func NewGDSModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spec)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if devices := image.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices) == 0 {
|
||||
if devices := image.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices.List()) == 0 {
|
||||
logger.Infof("No modification required; no devices requested")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
74
internal/modifier/graphics.go
Normal file
74
internal/modifier/graphics.go
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
# 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 modifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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/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
|
||||
}
|
||||
|
||||
if required, reason := requiresGraphicsModifier(image); !required {
|
||||
logger.Infof("No graphics modifier required: %v", reason)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
config := &discover.Config{
|
||||
Root: cfg.NVIDIAContainerCLIConfig.Root,
|
||||
NVIDIAContainerToolkitCLIExecutablePath: cfg.NVIDIACTKConfig.Path,
|
||||
}
|
||||
d, err := discover.NewGraphicsDiscoverer(
|
||||
logger,
|
||||
image.DevicesFromEnvvars(visibleDevicesEnvvar),
|
||||
config,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct discoverer: %v", err)
|
||||
}
|
||||
|
||||
return NewModifierFromDiscoverer(logger, d)
|
||||
}
|
||||
|
||||
// requiresGraphicsModifier determines whether a graphics modifier is required.
|
||||
func requiresGraphicsModifier(cudaImage image.CUDA) (bool, string) {
|
||||
if devices := cudaImage.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices.List()) == 0 {
|
||||
return false, "no devices requested"
|
||||
}
|
||||
|
||||
if !cudaImage.GetDriverCapabilities().Any(image.DriverCapabilityGraphics, image.DriverCapabilityDisplay) {
|
||||
return false, "no required capabilities requested"
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
96
internal/modifier/graphics_test.go
Normal file
96
internal/modifier/graphics_test.go
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
# 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 modifier
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGraphicsModifier(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
cudaImage image.CUDA
|
||||
expectedRequired bool
|
||||
}{
|
||||
{
|
||||
description: "empty image does not create modifier",
|
||||
},
|
||||
{
|
||||
description: "devices with no capabilities does not create modifier",
|
||||
cudaImage: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "all",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "devices with no non-graphics does not create modifier",
|
||||
cudaImage: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "all",
|
||||
"NVIDIA_DRIVER_CAPABILITIES": "compute",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "devices with all capabilities creates modifier",
|
||||
cudaImage: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "all",
|
||||
"NVIDIA_DRIVER_CAPABILITIES": "all",
|
||||
},
|
||||
expectedRequired: true,
|
||||
},
|
||||
{
|
||||
description: "devices with graphics capability creates modifier",
|
||||
cudaImage: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "all",
|
||||
"NVIDIA_DRIVER_CAPABILITIES": "graphics",
|
||||
},
|
||||
expectedRequired: true,
|
||||
},
|
||||
{
|
||||
description: "devices with compute,graphics capability creates modifier",
|
||||
cudaImage: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "all",
|
||||
"NVIDIA_DRIVER_CAPABILITIES": "compute,graphics",
|
||||
},
|
||||
expectedRequired: true,
|
||||
},
|
||||
{
|
||||
description: "devices with display capability creates modifier",
|
||||
cudaImage: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "all",
|
||||
"NVIDIA_DRIVER_CAPABILITIES": "display",
|
||||
},
|
||||
expectedRequired: true,
|
||||
},
|
||||
{
|
||||
description: "devices with display,graphics capability creates modifier",
|
||||
cudaImage: image.CUDA{
|
||||
"NVIDIA_VISIBLE_DEVICES": "all",
|
||||
"NVIDIA_DRIVER_CAPABILITIES": "display,graphics",
|
||||
},
|
||||
expectedRequired: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
required, _ := requiresGraphicsModifier(tc.cudaImage)
|
||||
require.EqualValues(t, tc.expectedRequired, required)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func NewMOFEDModifier(logger *logrus.Logger, cfg *config.Config, ociSpec oci.Spe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if devices := image.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices) == 0 {
|
||||
if devices := image.DevicesFromEnvvars(visibleDevicesEnvvar); len(devices.List()) == 0 {
|
||||
logger.Infof("No modification required; no devices requested")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
package modifier
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -44,21 +43,8 @@ type stableRuntimeModifier struct {
|
||||
// Modify applies the required modification to the incoming OCI spec, inserting the nvidia-container-runtime-hook
|
||||
// as a prestart hook.
|
||||
func (m stableRuntimeModifier) Modify(spec *specs.Spec) error {
|
||||
path, err := exec.LookPath(config.NVIDIAContainerRuntimeHookExecutable)
|
||||
if err != nil {
|
||||
path = filepath.Join(config.DefaultExecutableDir, config.NVIDIAContainerRuntimeHookExecutable)
|
||||
_, err = os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m.logger.Infof("Using prestart hook path: %s", path)
|
||||
|
||||
args := []string{path}
|
||||
if spec.Hooks == nil {
|
||||
spec.Hooks = &specs.Hooks{}
|
||||
} else if len(spec.Hooks.Prestart) != 0 {
|
||||
// If an NVIDIA Container Runtime Hook already exists, we don't make any modifications to the spec.
|
||||
if spec.Hooks != nil {
|
||||
for _, hook := range spec.Hooks.Prestart {
|
||||
if isNVIDIAContainerRuntimeHook(&hook) {
|
||||
m.logger.Infof("Existing nvidia prestart hook (%v) found in OCI spec", hook.Path)
|
||||
@@ -67,6 +53,21 @@ 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)
|
||||
}
|
||||
|
||||
m.logger.Infof("Using prestart hook path: %v", path)
|
||||
args := []string{path}
|
||||
if spec.Hooks == nil {
|
||||
spec.Hooks = &specs.Hooks{}
|
||||
}
|
||||
spec.Hooks.Prestart = append(spec.Hooks.Prestart, specs.Hook{
|
||||
Path: path,
|
||||
Args: append(args, "prestart"),
|
||||
|
||||
@@ -21,12 +21,12 @@ import (
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvinfo"
|
||||
"gitlab.com/nvidia/cloud-native/go-nvlib/pkg/nvlib/info"
|
||||
)
|
||||
|
||||
// NewTegraPlatformFiles creates a modifier to inject the Tegra platform files into a container.
|
||||
func NewTegraPlatformFiles(logger *logrus.Logger) (oci.SpecModifier, error) {
|
||||
isTegra, _ := nvinfo.IsTegraSystem()
|
||||
isTegra, _ := info.New().IsTegraSystem()
|
||||
if !isTegra {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
166
internal/nvcaps/nvcaps.go
Normal file
166
internal/nvcaps/nvcaps.go
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
# Copyright (c) 2021-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 nvcaps
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
nvidiaProcDriverPath = "/proc/driver/nvidia"
|
||||
nvidiaCapabilitiesPath = nvidiaProcDriverPath + "/capabilities"
|
||||
|
||||
nvcapsProcDriverPath = "/proc/driver/nvidia-caps"
|
||||
nvcapsMigMinorsPath = nvcapsProcDriverPath + "/mig-minors"
|
||||
nvcapsDevicePath = "/dev/nvidia-caps"
|
||||
)
|
||||
|
||||
// MigMinor represents the minor number of a MIG device
|
||||
type MigMinor int
|
||||
|
||||
// MigCap represents the path to a MIG cap file
|
||||
type MigCap string
|
||||
|
||||
// MigCaps stores a map of MIG cap file paths to MIG minors
|
||||
type MigCaps map[MigCap]MigMinor
|
||||
|
||||
// NewGPUInstanceCap creates a MigCap for the specified MIG GPU instance.
|
||||
// A GPU instance is uniquely defined by the GPU minor number and GI instance ID.
|
||||
func NewGPUInstanceCap(gpu, gi int) MigCap {
|
||||
return MigCap(fmt.Sprintf("gpu%d/gi%d/access", gpu, gi))
|
||||
}
|
||||
|
||||
// NewComputeInstanceCap creates a MigCap for the specified MIG Compute instance.
|
||||
// A GPU instance is uniquely defined by the GPU minor number, GI instance ID, and CI instance ID.
|
||||
func NewComputeInstanceCap(gpu, gi, ci int) MigCap {
|
||||
return MigCap(fmt.Sprintf("gpu%d/gi%d/ci%d/access", gpu, gi, ci))
|
||||
}
|
||||
|
||||
// GetCapDevicePath returns the path to the cap device for the specified cap.
|
||||
// An error is returned if the cap is invalid.
|
||||
func (m MigCaps) GetCapDevicePath(cap MigCap) (string, error) {
|
||||
minor, exists := m[cap]
|
||||
if !exists {
|
||||
return "", fmt.Errorf("invalid MIG capability path %v", cap)
|
||||
}
|
||||
return minor.DevicePath(), nil
|
||||
}
|
||||
|
||||
// NewMigCaps creates a MigCaps structure based on the contents of the MIG minors file.
|
||||
func NewMigCaps() (MigCaps, error) {
|
||||
// Open nvcapsMigMinorsPath for walking.
|
||||
// If the nvcapsMigMinorsPath does not exist, then we are not on a MIG
|
||||
// capable machine, so there is nothing to do.
|
||||
// The format of this file is discussed in:
|
||||
// https://docs.nvidia.com/datacenter/tesla/mig-user-guide/index.html#unique_1576522674
|
||||
minorsFile, err := os.Open(nvcapsMigMinorsPath)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening MIG minors file: %v", err)
|
||||
}
|
||||
defer minorsFile.Close()
|
||||
|
||||
return processMinorsFile(minorsFile), nil
|
||||
}
|
||||
|
||||
func processMinorsFile(minorsFile io.Reader) MigCaps {
|
||||
// Walk each line of nvcapsMigMinorsPath and construct a mapping of nvidia
|
||||
// capabilities path to device minor for that capability
|
||||
migCaps := make(MigCaps)
|
||||
scanner := bufio.NewScanner(minorsFile)
|
||||
for scanner.Scan() {
|
||||
cap, minor, err := processMigMinorsLine(scanner.Text())
|
||||
if err != nil {
|
||||
log.Printf("Skipping line in MIG minors file: %v", err)
|
||||
continue
|
||||
}
|
||||
migCaps[cap] = minor
|
||||
}
|
||||
return migCaps
|
||||
}
|
||||
|
||||
func processMigMinorsLine(line string) (MigCap, MigMinor, error) {
|
||||
parts := strings.Split(line, " ")
|
||||
if len(parts) != 2 {
|
||||
return "", 0, fmt.Errorf("error processing line: %v", line)
|
||||
}
|
||||
|
||||
migCap := MigCap(parts[0])
|
||||
if !migCap.isValid() {
|
||||
return "", 0, fmt.Errorf("invalid MIG minors line: '%v'", line)
|
||||
}
|
||||
|
||||
minor, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("error reading MIG minor from '%v': %v", line, err)
|
||||
}
|
||||
|
||||
return migCap, MigMinor(minor), nil
|
||||
}
|
||||
|
||||
func (m MigCap) isValid() bool {
|
||||
cap := string(m)
|
||||
switch cap {
|
||||
case "config", "monitor":
|
||||
return true
|
||||
default:
|
||||
var gpu int
|
||||
var gi int
|
||||
var ci int
|
||||
// Look for a CI access file
|
||||
n, _ := fmt.Sscanf(cap, "gpu%d/gi%d/ci%d/access", &gpu, &gi, &ci)
|
||||
if n == 3 {
|
||||
return true
|
||||
}
|
||||
// Look for a GI access file
|
||||
n, _ = fmt.Sscanf(cap, "gpu%d/gi%d/access %d", &gpu, &gi)
|
||||
if n == 2 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ProcPath returns the proc path associated with the MIG capability
|
||||
func (m MigCap) ProcPath() string {
|
||||
id := string(m)
|
||||
|
||||
var path string
|
||||
switch id {
|
||||
case "config", "monitor":
|
||||
path = "mig/" + id
|
||||
default:
|
||||
parts := strings.SplitN(id, "/", 2)
|
||||
path = strings.Join([]string{parts[0], "mig", parts[1]}, "/")
|
||||
}
|
||||
return filepath.Join(nvidiaCapabilitiesPath, path)
|
||||
}
|
||||
|
||||
// DevicePath returns the path for the nvidia-caps device with the specified
|
||||
// minor number
|
||||
func (m MigMinor) DevicePath() string {
|
||||
return fmt.Sprintf(nvcapsDevicePath+"/nvidia-cap%d", m)
|
||||
}
|
||||
100
internal/nvcaps/nvcaps_test.go
Normal file
100
internal/nvcaps/nvcaps_test.go
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
# Copyright (c) 2021-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 nvcaps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestProcessMinorsFile(t *testing.T) {
|
||||
testCases := []struct {
|
||||
lines []string
|
||||
expected MigCaps
|
||||
}{
|
||||
{[]string{}, MigCaps{}},
|
||||
{[]string{"invalidLine"}, MigCaps{}},
|
||||
{[]string{"config 1"}, MigCaps{"config": 1}},
|
||||
{[]string{"gpu0/gi0/ci0/access 4"}, MigCaps{"gpu0/gi0/ci0/access": 4}},
|
||||
{[]string{"config 1", "invalidLine"}, MigCaps{"config": 1}},
|
||||
{[]string{"config 1", "gpu0/gi0/ci0/access 4"}, MigCaps{"config": 1, "gpu0/gi0/ci0/access": 4}},
|
||||
}
|
||||
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 := processMinorsFile(contents)
|
||||
require.Equal(t, tc.expected, d)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessMigMinorsLine(t *testing.T) {
|
||||
testCases := []struct {
|
||||
line string
|
||||
cap MigCap
|
||||
minor MigMinor
|
||||
err bool
|
||||
}{
|
||||
{"config 1", "config", 1, false},
|
||||
{"monitor 2", "monitor", 2, false},
|
||||
{"gpu0/gi0/access 3", "gpu0/gi0/access", 3, false},
|
||||
{"gpu0/gi0/ci0/access 4", "gpu0/gi0/ci0/access", 4, false},
|
||||
{"notconfig 99", "", 0, true},
|
||||
{"config notanint", "", 0, true},
|
||||
{"", "", 0, true},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("testcase %d", i), func(t *testing.T) {
|
||||
cap, minor, err := processMigMinorsLine(tc.line)
|
||||
|
||||
require.Equal(t, tc.cap, cap)
|
||||
require.Equal(t, tc.minor, minor)
|
||||
if tc.err {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigCapProcPaths(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"config", "/proc/driver/nvidia/capabilities/mig/config"},
|
||||
{"monitor", "/proc/driver/nvidia/capabilities/mig/monitor"},
|
||||
{"gpu0/gi0/access", "/proc/driver/nvidia/capabilities/gpu0/mig/gi0/access"},
|
||||
{"gpu0/gi0/ci0/access", "/proc/driver/nvidia/capabilities/gpu0/mig/gi0/ci0/access"},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("testcase %d", i), func(t *testing.T) {
|
||||
m := MigCap(tc.input)
|
||||
require.Equal(t, tc.expected, m.ProcPath())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigMinorDevicePath(t *testing.T) {
|
||||
m := MigMinor(0)
|
||||
require.Equal(t, "/dev/nvidia-caps/nvidia-cap0", m.DevicePath())
|
||||
}
|
||||
@@ -56,7 +56,7 @@ install -m 644 -t %{buildroot}/usr/share/containers/oci/hooks.d oci-nvidia-hook.
|
||||
ln -sf %{_bindir}/nvidia-container-runtime-hook %{_bindir}/nvidia-container-toolkit
|
||||
|
||||
%postun
|
||||
rm -f %{_bindir}/nvidia-container-toolkit
|
||||
if [ -L %{_bindir}/nvidia-container-toolkit ] then; rm -f %{_bindir}/nvidia-container-toolkit; fi
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
function assert_usage() {
|
||||
echo "Missing argument $1"
|
||||
echo "$(basename ${BASH_SOURCE[0]}) TARGET"
|
||||
echo "$(basename "${BASH_SOURCE[0]}") TARGET"
|
||||
exit 1
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../scripts && pwd )"
|
||||
PROJECT_ROOT="$( cd ${SCRIPTS_DIR}/.. && pwd )"
|
||||
PROJECT_ROOT="$( cd "${SCRIPTS_DIR}"/.. && pwd )"
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
assert_usage "TARGET"
|
||||
@@ -36,46 +36,51 @@ fi
|
||||
|
||||
TARGET=$1
|
||||
|
||||
: ${DIST_DIR:=${PROJECT_ROOT}/dist}
|
||||
: "${DIST_DIR:=${PROJECT_ROOT}/dist}"
|
||||
export DIST_DIR
|
||||
|
||||
echo "Building ${TARGET} for all packages to ${DIST_DIR}"
|
||||
|
||||
: ${LIBNVIDIA_CONTAINER_ROOT:=${PROJECT_ROOT}/third_party/libnvidia-container}
|
||||
: ${NVIDIA_CONTAINER_TOOLKIT_ROOT:=${PROJECT_ROOT}}
|
||||
: ${NVIDIA_CONTAINER_RUNTIME_ROOT:=${PROJECT_ROOT}/third_party/nvidia-container-runtime}
|
||||
: ${NVIDIA_DOCKER_ROOT:=${PROJECT_ROOT}/third_party/nvidia-docker}
|
||||
: "${LIBNVIDIA_CONTAINER_ROOT:=${PROJECT_ROOT}/third_party/libnvidia-container}"
|
||||
: "${NVIDIA_CONTAINER_TOOLKIT_ROOT:=${PROJECT_ROOT}}"
|
||||
: "${NVIDIA_CONTAINER_RUNTIME_ROOT:=${PROJECT_ROOT}/third_party/nvidia-container-runtime}"
|
||||
: "${NVIDIA_DOCKER_ROOT:=${PROJECT_ROOT}/third_party/nvidia-docker}"
|
||||
|
||||
|
||||
${SCRIPTS_DIR}/get-component-versions.sh
|
||||
"${SCRIPTS_DIR}/get-component-versions.sh"
|
||||
|
||||
# Build libnvidia-container
|
||||
make -C ${LIBNVIDIA_CONTAINER_ROOT} -f mk/docker.mk ${TARGET}
|
||||
make -C "${LIBNVIDIA_CONTAINER_ROOT}" -f mk/docker.mk "${TARGET}"
|
||||
|
||||
if [[ -z ${NVIDIA_CONTAINER_TOOLKIT_VERSION} || -z ${LIBNVIDIA_CONTAINER_VERSION} ]]; then
|
||||
if [[ -z "${NVIDIA_CONTAINER_TOOLKIT_VERSION}" || -z "${LIBNVIDIA_CONTAINER_VERSION}" ]]; then
|
||||
eval $(${SCRIPTS_DIR}/get-component-versions.sh)
|
||||
fi
|
||||
|
||||
# Build nvidia-container-toolkit
|
||||
make -C ${NVIDIA_CONTAINER_TOOLKIT_ROOT} \
|
||||
make -C "${NVIDIA_CONTAINER_TOOLKIT_ROOT}" \
|
||||
LIBNVIDIA_CONTAINER_VERSION="${LIBNVIDIA_CONTAINER_VERSION}" \
|
||||
LIBNVIDIA_CONTAINER_TAG="${LIBNVIDIA_CONTAINER_TAG}" \
|
||||
${TARGET}
|
||||
"${TARGET}"
|
||||
|
||||
# We set the TOOLKIT_VERSION, TOOLKIT_TAG for the nvidia-container-runtime and nvidia-docker targets
|
||||
# The LIB_TAG is also overridden to match the TOOLKIT_TAG.
|
||||
# Build nvidia-container-runtime
|
||||
make -C ${NVIDIA_CONTAINER_RUNTIME_ROOT} \
|
||||
LIB_VERSION="${NVIDIA_CONTAINER_RUNTIME_VERSION}" \
|
||||
LIB_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \
|
||||
TOOLKIT_VERSION="${NVIDIA_CONTAINER_TOOLKIT_VERSION}" \
|
||||
TOOLKIT_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \
|
||||
${TARGET}
|
||||
if [[ -z ${NVIDIA_CONTAINER_TOOLKIT_TAG} ]]; then
|
||||
# We set the TOOLKIT_VERSION, TOOLKIT_TAG for the nvidia-container-runtime and nvidia-docker targets
|
||||
# The LIB_TAG is also overridden to match the TOOLKIT_TAG.
|
||||
# Build nvidia-container-runtime
|
||||
make -C ${NVIDIA_CONTAINER_RUNTIME_ROOT} \
|
||||
LIB_VERSION="${NVIDIA_CONTAINER_RUNTIME_VERSION}" \
|
||||
LIB_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \
|
||||
TOOLKIT_VERSION="${NVIDIA_CONTAINER_TOOLKIT_VERSION}" \
|
||||
TOOLKIT_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \
|
||||
${TARGET}
|
||||
|
||||
# Build nvidia-docker2
|
||||
make -C ${NVIDIA_DOCKER_ROOT} \
|
||||
LIB_VERSION="${NVIDIA_DOCKER_VERSION}" \
|
||||
LIB_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \
|
||||
TOOLKIT_VERSION="${NVIDIA_CONTAINER_TOOLKIT_VERSION}" \
|
||||
TOOLKIT_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \
|
||||
${TARGET}
|
||||
# Build nvidia-docker2
|
||||
make -C ${NVIDIA_DOCKER_ROOT} \
|
||||
LIB_VERSION="${NVIDIA_DOCKER_VERSION}" \
|
||||
LIB_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \
|
||||
TOOLKIT_VERSION="${NVIDIA_CONTAINER_TOOLKIT_VERSION}" \
|
||||
TOOLKIT_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \
|
||||
${TARGET}
|
||||
|
||||
else
|
||||
echo "Skipping nvidia-container-runtime and nvidia-docker builds for release candidate"
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2021-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.
|
||||
@@ -22,7 +22,6 @@
|
||||
set -e
|
||||
|
||||
SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../scripts && pwd )"
|
||||
PROJECT_ROOT="$( cd ${SCRIPTS_DIR}/.. && pwd )"
|
||||
|
||||
# This list represents the distribution-architecture pairs that are actually published
|
||||
# to the relevant repositories. This targets forwarded to the build-all-components script
|
||||
@@ -54,7 +53,7 @@ else
|
||||
fi
|
||||
|
||||
echo "Updating components"
|
||||
${SCRIPTS_DIR}/update-components.sh
|
||||
"${SCRIPTS_DIR}/update-components.sh"
|
||||
if [[ -n $(git status -s third_party) && ${ALLOW_LOCAL_COMPONENT_CHANGES} != "true" ]]; then
|
||||
echo "ERROR: Building with local component changes."
|
||||
echo "Commit pending changes or rerun with ALLOW_LOCAL_COMPONENT_CHANGES='true'"
|
||||
@@ -66,7 +65,7 @@ eval $(${SCRIPTS_DIR}/get-component-versions.sh)
|
||||
|
||||
if [[ -n ${NVIDIA_CONTAINER_TOOLKIT_TAG} ]]; then
|
||||
echo "Allowing mismatched versions for release candidate "
|
||||
: ${ALLOW_VERSION_MISMATCH:=true}
|
||||
: "${ALLOW_VERSION_MISMATCH:=true}"
|
||||
fi
|
||||
|
||||
if [[ "${NVIDIA_CONTAINER_TOOLKIT_PACKAGE_VERSION}" != "${LIBNVIDIA_CONTAINER_PACKAGE_VERSION}" ]]; then
|
||||
@@ -86,6 +85,6 @@ export LIBNVIDIA_CONTAINER_TAG
|
||||
export NVIDIA_CONTAINER_RUNTIME_VERSION
|
||||
export NVIDIA_DOCKER_VERSION
|
||||
|
||||
for target in ${targets[@]}; do
|
||||
${SCRIPTS_DIR}/build-all-components.sh ${target}
|
||||
for target in "${targets[@]}"; do
|
||||
"${SCRIPTS_DIR}/build-all-components.sh" "${target}"
|
||||
done
|
||||
|
||||
114
scripts/extract-packages.sh
Executable file
114
scripts/extract-packages.sh
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 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.
|
||||
|
||||
function assert_usage() {
|
||||
echo "Incorrect arguments: $*" >&2
|
||||
echo "$(basename "${BASH_SOURCE[0]}") PACKAGE_IMAGE_NAME:PACKAGE_IMAGE_TAG DIST-ARCH" >&2
|
||||
echo -e "\\tPACKAGE_IMAGE: container image holding packages [e.g. registry.gitlab.com/nvidia/container-toolkit/container-toolkit/staging/container-toolkit]" >&2
|
||||
echo -e "\\tPACKAGE_TAG: tag for container image holding packages. [e.g. 1a2b3c4-packaging]" >&2
|
||||
echo -e "\\tDIST: The distribution." >&2
|
||||
echo -e "\\tARCH: The architecture." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../scripts && pwd )"
|
||||
PROJECT_ROOT="$( cd "${SCRIPTS_DIR}/.." && pwd )"
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
PACKAGE_IMAGE=$1
|
||||
DISTARCH=$2
|
||||
DIST=${DISTARCH%-*}
|
||||
ARCH=${DISTARCH##*-}
|
||||
|
||||
if [[ -z "${DIST}" || -z "${ARCH}" ]]; then
|
||||
echo "ERROR: Distro and Architecture must be specified." >&2
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
# TODO: accept ARTIFACTS_DIR as a command-line argument
|
||||
: "${ARTIFACTS_DIR="${PROJECT_ROOT}/artifacts"}"
|
||||
|
||||
# For release-candidates we skip certain packages.
|
||||
# For example, we don't release release candidates of nvidia-container-runtime and nvidia-docker2
|
||||
# since these only bump the nvidia-container-toolkit dependency.
|
||||
function skip-for-release-candidate() {
|
||||
if [[ "${VERSION/rc./}" == "${VERSION}" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local package_name=$1
|
||||
if [[ "${package_name/"nvidia-docker2"/}" != "${package_name}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
if [[ "${package_name/"nvidia-container-runtime"/}" != "${package_name}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# extract-file copies a file from a specified image.
|
||||
# If regctl is available this is used, otherwise a docker container is run and the file is copied from
|
||||
# there.
|
||||
function copy-file() {
|
||||
local image=$1
|
||||
local path_in_image=$2
|
||||
local path_on_host=$3
|
||||
if command -v regctl; then
|
||||
regctl image get-file "${image}" "${path_in_image}" "${path_on_host}"
|
||||
else
|
||||
# Note this will only work for destinations where the `path_on_host` is in `pwd`
|
||||
docker run --rm \
|
||||
-v "$(pwd):$(pwd)" \
|
||||
-w "$(pwd)" \
|
||||
-u "$(id -u):$(id -g)" \
|
||||
--entrypoint="bash" \
|
||||
"${image}" \
|
||||
-c "cp ${path_in_image} ${path_on_host}"
|
||||
fi
|
||||
}
|
||||
|
||||
eval $(${SCRIPTS_DIR}/get-component-versions.sh)
|
||||
|
||||
# extract-all extracts all package for the specified dist-arch combination from the package image.
|
||||
# The manifest.txt file in the image is used to detemine the applicable files for the combination.
|
||||
# Files are extracted to ${ARTIFACTS_DIR}/artifacts/packages/${dist}/${arch}
|
||||
function extract-all() {
|
||||
local dist=$1
|
||||
local arch=$2
|
||||
|
||||
echo "Extracting packages for ${dist}-${arch} from ${PACKAGE_IMAGE}"
|
||||
|
||||
mkdir -p "${ARTIFACTS_DIR}"
|
||||
copy-file "${PACKAGE_IMAGE}" "/artifacts/manifest.txt" "${ARTIFACTS_DIR}/manifest.txt"
|
||||
|
||||
# Extract every file for the specified dist-arch combiniation in MANIFEST.txt
|
||||
grep "/${dist}/${arch}/" "${ARTIFACTS_DIR}/manifest.txt" | while read -r f ; do
|
||||
package_name="$(basename "$f")"
|
||||
# For release-candidates, we skip certain packages
|
||||
if skip-for-release-candidate "${package_name}"; then
|
||||
echo "Skipping $f for release-candidate ${VERSION}"
|
||||
continue
|
||||
fi
|
||||
target="${ARTIFACTS_DIR}/packages/${dist}/${arch}/${package_name}"
|
||||
mkdir -p "$(dirname "$target")"
|
||||
copy-file "${PACKAGE_IMAGE}" "${f}" "${target}"
|
||||
done
|
||||
}
|
||||
|
||||
extract-all "${DIST}" "${ARCH}"
|
||||
@@ -9,7 +9,7 @@ set -x -e
|
||||
|
||||
function deb-sign {
|
||||
local last_found
|
||||
for r in ${*}; do
|
||||
for r in "$@"; do
|
||||
if [ -f "./${r}" ]; then
|
||||
last_found=${r}
|
||||
fi
|
||||
@@ -27,12 +27,12 @@ function deb-sign {
|
||||
--no-emit-version \
|
||||
--no-comments \
|
||||
--personal-digest-preferences sha512 \
|
||||
--local-user ${GPG_LOCAL_USER} \
|
||||
--local-user "${GPG_LOCAL_USER}" \
|
||||
> InRelease
|
||||
}
|
||||
|
||||
function rpm-sign {
|
||||
for r in ${*}; do
|
||||
for r in "$@"; do
|
||||
if [ -f "./${r}" ]; then
|
||||
rpmsign --addsign --key-id A04EA552 --digest-algo=sha512 "${r}"
|
||||
fi
|
||||
@@ -42,7 +42,7 @@ function rpm-sign {
|
||||
--armor \
|
||||
--no-emit-version \
|
||||
--no-comments --personal-digest-preferences sha512 \
|
||||
--local-user ${GPG_LOCAL_USER} \
|
||||
--local-user "${GPG_LOCAL_USER}" \
|
||||
repodata/repomd.xml
|
||||
}
|
||||
|
||||
@@ -83,15 +83,15 @@ function sign() {
|
||||
return
|
||||
fi
|
||||
|
||||
cd ${dst}
|
||||
cd "${dst}"
|
||||
if [[ -f "/etc/debian_version" ]]; then
|
||||
[[ ${pkg_type} == "deb" ]] && deb-sign ${ALL_DEBS}
|
||||
[[ "${pkg_type}" == "deb" ]] && deb-sign ${ALL_DEBS}
|
||||
else
|
||||
[[ ${pkg_type} == "rpm" ]] && rpm-sign ${ALL_RPMS}
|
||||
[[ "${pkg_type}" == "rpm" ]] && rpm-sign ${ALL_RPMS}
|
||||
fi
|
||||
cd -
|
||||
}
|
||||
|
||||
for target in ${TARGETS[@]}; do
|
||||
sign ${target} $(pwd)
|
||||
for target in "${TARGETS[@]}"; do
|
||||
sign "${target}" "$(pwd)"
|
||||
done
|
||||
|
||||
216
scripts/release-kitmaker-artifactory.sh
Executable file
216
scripts/release-kitmaker-artifactory.sh
Executable file
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 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.
|
||||
|
||||
function assert_usage() {
|
||||
cat >&2 << EOF
|
||||
Incorrect arguments: $*
|
||||
$(basename "${BASH_SOURCE[0]}") DIST-ARCH ARTIFACTORY_URL
|
||||
DIST: The distribution.
|
||||
ARCH: The architecture.
|
||||
ARTIFACTORY_URL must contain repo path for package, including hostname.
|
||||
|
||||
Environment Variables
|
||||
ARTIFACTORY_TOKEN: must contain an auth token. [required]
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../scripts && pwd )"
|
||||
PROJECT_ROOT="$( cd "${SCRIPTS_DIR}/.." && pwd )"
|
||||
COMPONENT_NAME="nvidia-container-toolkit"
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
source "${SCRIPTS_DIR}"/utils.sh
|
||||
|
||||
DISTARCH=$1
|
||||
DIST=${DISTARCH%-*}
|
||||
ARCH=${DISTARCH##*-}
|
||||
ARTIFACTORY_URL=$2
|
||||
|
||||
CURL=${CURL:-curl}
|
||||
|
||||
if [[ -z "${DIST}" || -z "${ARCH}" ]]; then
|
||||
echo "ERROR: Distro and Architecture must be specified." >&2
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
# TODO: accept ARTIFACTS_DIR as a command-line argument
|
||||
: "${ARTIFACTS_DIR="${PROJECT_ROOT}/artifacts"}"
|
||||
|
||||
if [[ ! -d "${ARTIFACTS_DIR}" ]]; then
|
||||
echo "ERROR: ARTIFACTS_DIR does not exist." >&2
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
if [[ -z "${ARTIFACTORY_TOKEN}" ]]; then
|
||||
echo "ERROR: ARTIFACTORY_TOKEN must be defined." >&2
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
# TODO: accept KITMACKER_DIR as a command-line argument
|
||||
: "${KITMAKER_DIR="${PROJECT_ROOT}/artifacts/kitmaker"}"
|
||||
|
||||
eval $(${SCRIPTS_DIR}/get-component-versions.sh)
|
||||
|
||||
# Returns the key=value property if the value isn't empty
|
||||
# Prepends with ";" if needed
|
||||
set_prop_value() {
|
||||
local key=$1
|
||||
local value=$2
|
||||
if [ -n "${value}" ]; then
|
||||
if [ -z "${PROPS}" ]; then
|
||||
echo "${key}=${value}"
|
||||
else
|
||||
echo ";${key}=${value}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
process_props() {
|
||||
local dist=$1
|
||||
local arch=$2
|
||||
|
||||
PROPS+=$(set_prop_value "component_name" "${COMPONENT_NAME}")
|
||||
PROPS+=$(set_prop_value "version" "${VERSION}")
|
||||
PROPS+=$(set_prop_value "os" "${dist}")
|
||||
PROPS+=$(set_prop_value "arch" "${arch}")
|
||||
PROPS+=$(set_prop_value "platform" "${dist}-${arch}")
|
||||
# TODO: Use `git describe` to get this information if it's not available.
|
||||
PROPS+=$(set_prop_value "changelist" "${CI_COMMIT_SHA}")
|
||||
PROPS+=$(set_prop_value "branch" "${CI_COMMIT_REF_NAME}")
|
||||
|
||||
# Gitlab variables to expose
|
||||
for var in CI_PROJECT_ID CI_PIPELINE_ID CI_JOB_ID CI_JOB_URL CI_PROJECT_PATH; do
|
||||
if [ -n "${!var}" ]; then
|
||||
PROPS+=$(set_prop_value "${var}" "${!var}")
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Applying properties: ${PROPS}"
|
||||
}
|
||||
|
||||
## NOT USED:
|
||||
## can substitute this function place of upload_file to modify properties of
|
||||
## existing file instead of uploading files.
|
||||
# Sets the properties on a path
|
||||
# Relies on global variables: ARTIFACTORY_TOKEN, ARTIFACTORY_URL
|
||||
set_props() {
|
||||
local dist="$1"
|
||||
local arch="$2"
|
||||
local kitmakerfilename="$3"
|
||||
|
||||
# extract the Artifactory hostname
|
||||
artifactory_host=$(echo "${ARTIFACTORY_URL##https://}" | awk -F'/' '{print $1}')
|
||||
local image_path="${ARTIFACTORY_URL#https://${artifactory_host}/}/${dist}/${arch}/${kitmakerfilename}"
|
||||
|
||||
local PROPS
|
||||
process_props "${DIST}" "${ARCH}"
|
||||
|
||||
echo "Setting ${image_path} with properties: ${PROPS}"
|
||||
if ! ${CURL} -fs -H "X-JFrog-Art-Api: ${ARTIFACTORY_TOKEN}" \
|
||||
-X PUT \
|
||||
"https://${artifactory_host}/artifactory/api/storage/${image_path}?properties=${PROPS}&recursive=0" ; then
|
||||
echo "ERROR: set props failed: ${image_path}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Uploads file to ARTIFACTS_DIR/<os>/<arch>/<filename>
|
||||
# Relies on global variables: DIST, ARCH, ARTIFACTORY_TOKEN, ARTIFACTORY_URL
|
||||
upload_file() {
|
||||
local dist=$1
|
||||
local arch=$2
|
||||
local file=$3
|
||||
|
||||
# extract the Artifactory hostname
|
||||
artifactory_host=$(echo "${ARTIFACTORY_URL##https://}" | awk -F'/' '{print $1}')
|
||||
# get base part of the ARTIFACTORY_URL without hostname
|
||||
local image_path="${ARTIFACTORY_URL#https://${artifactory_host}/}/${dist}/${arch}/$(basename ${file})"
|
||||
|
||||
local PROPS
|
||||
process_props "${dist}" "${arch}"
|
||||
|
||||
if [ ! -r "${file}" ]; then
|
||||
echo "ERROR: File not found or not readable: ${file}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Collect sum
|
||||
SHA1_SUM=$(sha1sum -b "${file}" | awk '{ print $1 }')
|
||||
|
||||
echo "Uploading ${image_path} from ${file}"
|
||||
if ! ${CURL} -f \
|
||||
-H "X-JFrog-Art-Api: ${ARTIFACTORY_TOKEN}" \
|
||||
-H "X-Checksum-Sha1: ${SHA1_SUM}" \
|
||||
${file:+-T ${file}} -X PUT \
|
||||
"https://${artifactory_host}/${image_path};${PROPS}" ;
|
||||
then
|
||||
echo "ERROR: upload file failed: ${file}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function push-kitmaker-artifactory() {
|
||||
local dist=$1
|
||||
local arch=$2
|
||||
local archive=$3
|
||||
|
||||
upload_file "${dist}" "${arch}" "${archive}"
|
||||
}
|
||||
|
||||
# kitmakerize-distro creates a tar.gz archive for the specified dist-arch combination.
|
||||
# The archive is created at ${KITMAKER_DIR}/${name}.tar.gz (where ${name} is the third positional argument)
|
||||
function kitmakerize-distro() {
|
||||
local dist="$1"
|
||||
local arch="$2"
|
||||
local archive="$3"
|
||||
|
||||
local name=$(basename "${archive%%.tar.gz}")
|
||||
## Copy packages into directory layout for .tar.gz
|
||||
# TODO: make scratch_dir configurable
|
||||
local scratch_dir="$(dirname ${archive})/.scratch/${name}"
|
||||
local packages_dir="${scratch_dir}/.packages/"
|
||||
|
||||
mkdir -p "${packages_dir}"
|
||||
|
||||
# Copy the extracted files to the .packages directory so that a kitmaker file can be created.
|
||||
source="${ARTIFACTS_DIR}/packages/${dist}/${arch}"
|
||||
cp -r "${source}/"* "${packages_dir}/"
|
||||
|
||||
## Tar up the directory structure created above
|
||||
tar zcvf "${archive}" -C "${scratch_dir}/.." "${name}"
|
||||
echo "Created: ${archive}"
|
||||
ls -l "${archive}"
|
||||
echo "With contents:"
|
||||
tar -tzvf "${archive}"
|
||||
echo ""
|
||||
|
||||
# Clean up the scratch directories:
|
||||
rm -f "${scratch_dir}/.packages/"*
|
||||
rmdir "${scratch_dir}/.packages"
|
||||
rmdir "${scratch_dir}"
|
||||
}
|
||||
|
||||
: "${VERSION=$({NVIDIA_CONTAINER_TOOLKIT_PACKAGE_VERSION})}"
|
||||
kitmaker_name="${COMPONENT_NAME//-/_}-${DIST}-${ARCH}-${VERSION}"
|
||||
kitmaker_archive="${KITMAKER_DIR}/${kitmaker_name}.tar.gz"
|
||||
kitmakerize-distro "${DIST}" "${ARCH}" "${kitmaker_archive}"
|
||||
push-kitmaker-artifactory "${DIST}" "${ARCH}" "${kitmaker_archive}"
|
||||
189
scripts/release-packages-artifactory.sh
Executable file
189
scripts/release-packages-artifactory.sh
Executable file
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-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.
|
||||
|
||||
# Dependencies:
|
||||
# regctl
|
||||
#
|
||||
|
||||
function assert_usage() {
|
||||
cat >&2 << EOF
|
||||
Incorrect arguments: $*
|
||||
$(basename "${BASH_SOURCE[0]}") DIST-ARCH
|
||||
DIST: The distribution.
|
||||
ARCH: The architecture.
|
||||
|
||||
Environment Variables
|
||||
ARTIFACTORY_TOKEN: must contain an auth token. [required]
|
||||
LIB_TAG: optional package tag.
|
||||
CI_COMMIT_REF_NAME: provided by CI/CD system.
|
||||
CI_COMMIT_SHA: provided by CI/CD system.
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../scripts && pwd )"
|
||||
PROJECT_ROOT="$( cd "${SCRIPTS_DIR}/.." && pwd )"
|
||||
|
||||
source "${SCRIPTS_DIR}"/utils.sh
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
DISTARCH=$1
|
||||
ARTIFACTORY_PATH=$2
|
||||
DIST=${DISTARCH%-*}
|
||||
ARCH=${DISTARCH##*-}
|
||||
|
||||
CURL=${CURL:-curl}
|
||||
|
||||
if [[ -z "${DIST}" || -z "${ARCH}" ]]; then
|
||||
echo "ERROR: Distro and Architecture must be specified." >&2
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
if [[ -z "${ARTIFACTORY_PATH}" ]]; then
|
||||
echo "ERROR: Package repo must be specified." >&2
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
if [[ -z "${ARTIFACTORY_TOKEN}" ]]; then
|
||||
echo "ERROR: ARTIFACTORY_TOKEN must be defined." >&2
|
||||
assert_usage "$@"
|
||||
fi
|
||||
|
||||
# TODO: accept PACKAGES_DIR as a command-line argument
|
||||
: "${ARTIFACTS_DIR="${PROJECT_ROOT}/artifacts"}"
|
||||
: "${PACKAGES_DIR="${ARTIFACTS_DIR}/packages"}"
|
||||
|
||||
eval $(${SCRIPTS_DIR}/get-component-versions.sh)
|
||||
|
||||
# Returns the key=value property if the value isn't empty
|
||||
# Prepends with ";" if needed
|
||||
set_prop_value() {
|
||||
local key=$1
|
||||
local value=$2
|
||||
if [ -n "${value}" ]; then
|
||||
if [ -z "${PROPS}" ]; then
|
||||
echo "${key}=${value}"
|
||||
else
|
||||
echo ";${key}=${value}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
process_props() {
|
||||
local dist=$1
|
||||
local arch=$2
|
||||
local file=$3
|
||||
local component_name="${file%%.*}"
|
||||
component_name="${component_name%-*}"
|
||||
local pkg_type="$(package_type $dist)"
|
||||
|
||||
## Component owner is free to define these
|
||||
# PROPS+=$(set_prop_value "version" "${VERSION}")
|
||||
# PROPS+=$(set_prop_value "lws_version" "${LWS_VER}")
|
||||
# PROPS+=$(set_prop_value "platform" "${DISTARCH}")
|
||||
|
||||
# TODO: Use `git describe` to get this information if it's not available.
|
||||
PROPS+=$(set_prop_value "changelist" "${CI_COMMIT_SHA}")
|
||||
PROPS+=$(set_prop_value "branch" "${CI_COMMIT_REF_NAME}")
|
||||
|
||||
# PROPS+=$(set_prop_value "category" "utils")
|
||||
# PROPS+=$(set_prop_value "platform" "${DISTARCH}")
|
||||
|
||||
# Gitlab variables to expose
|
||||
for var in CI_PROJECT_ID CI_PIPELINE_ID CI_JOB_ID CI_JOB_URL CI_PROJECT_PATH; do
|
||||
if [ -n "${!var}" ]; then
|
||||
PROPS+=$(set_prop_value "${var}" "${!var}")
|
||||
fi
|
||||
done
|
||||
|
||||
# We also set the package-specific properties to allow this to be used for other artifactory repositories
|
||||
PROPS+=$(set_prop_value "${pkg_type}.distribution" "${dist}")
|
||||
PROPS+=$(set_prop_value "${pkg_type}.architecture" "${arch}")
|
||||
PROPS+=$(set_prop_value "${pkg_type}.component" "${component_name}")
|
||||
}
|
||||
|
||||
# Uploads file ARTIFACTORY_PATH
|
||||
# Relies on global variables: DIST, ARCH, ARTIFACTORY_TOKEN, ARTIFACTORY_PATH
|
||||
upload_file() {
|
||||
local dist=$1
|
||||
local arch=$2
|
||||
local file=$3
|
||||
|
||||
# TODO: These should be set by envvars
|
||||
local artifactory_host="urm.nvidia.com"
|
||||
local artifactory_repo="$(get_artifactory_repository $dist)"
|
||||
|
||||
if [ ! -r "${file}" ]; then
|
||||
echo "ERROR: File not found or not readable: ${file}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local PROPS
|
||||
process_props "${dist}" "${arch}" "${file}"
|
||||
|
||||
# Collect sum
|
||||
SHA1_SUM=$(sha1sum -b "${file}" | awk '{ print $1 }')
|
||||
|
||||
url="https://${artifactory_host}/artifactory/${artifactory_repo}/${dist}/${arch}/$(basename "${file}")"
|
||||
# NOTE: The URL to set the properties through the API is:
|
||||
# "https://${artifactory_host}/artifactory/api/storage/${artifactory_repo}/${dist}/${arch}/$(basename ${file})"
|
||||
|
||||
echo "Uploading ${file} to ${url}"
|
||||
if ! ${CURL} -f \
|
||||
-H "X-JFrog-Art-Api: ${ARTIFACTORY_TOKEN}" \
|
||||
-H "X-Checksum-Sha1: ${SHA1_SUM}" \
|
||||
${file:+-T ${file}} -X PUT \
|
||||
"${url};${PROPS}" ;
|
||||
then
|
||||
echo "ERROR: upload file failed: ${file}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function push-artifactory() {
|
||||
local dist="$1"
|
||||
local arch="$2"
|
||||
|
||||
source="${ARTIFACTS_DIR}/packages/${dist}/${arch}"
|
||||
|
||||
find "${source}" -maxdepth 1 | while read -r f ; do
|
||||
upload_file "$dist" "$arch" "$f"
|
||||
done
|
||||
}
|
||||
|
||||
# TODO: use this to adapt as a general purpose command-line tool
|
||||
# case "${COMMAND}" in
|
||||
# set)
|
||||
# set_props
|
||||
# ;;
|
||||
# upload)
|
||||
# if [ -z "${UPLOAD_FILE}" ]; then
|
||||
# echo "ERROR: Upload package filename must be set using -f"
|
||||
# usage
|
||||
# fi
|
||||
#
|
||||
# upload_file
|
||||
# ;;
|
||||
# *)
|
||||
# echo "ERROR: Invalid command ${COMMAND}"
|
||||
# usage
|
||||
# ;;
|
||||
# esac
|
||||
|
||||
push-artifactory "${DIST}" "${ARCH}"
|
||||
@@ -132,8 +132,17 @@ function sync() {
|
||||
|
||||
done
|
||||
if [[ ${REPO} == "stable" ]]; then
|
||||
cp ${src}/nvidia-container-runtime*.${pkg_type} ${dst}
|
||||
cp ${src}/nvidia-docker*.${pkg_type} ${dst}
|
||||
for f in $(ls ${src}/nvidia-container-runtime*.${pkg_type} ${src}/nvidia-docker*.${pkg_type}); do
|
||||
df=${dst}/$(basename ${f})
|
||||
df_stable=${df//"/experimental/"/"/stable/"}
|
||||
if [[ -f "${df}" ]]; then
|
||||
echo "${df} already exists; skipping"
|
||||
elif [[ ${REPO} == "experimental" && -f ${df_stable} ]]; then
|
||||
echo "${df_stable} already exists; skipping"
|
||||
else
|
||||
cp ${f} ${df}
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
36
scripts/utils.sh
Normal file
36
scripts/utils.sh
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
# package_type returns the packaging type (deb or rpm) for the specfied distribution.
|
||||
# An error is returned if the ditribution is unsupported.
|
||||
function package_type() {
|
||||
local pkg_type
|
||||
case ${1} in
|
||||
amazonlinux*) pkg_type=rpm
|
||||
;;
|
||||
centos*) pkg_type=rpm
|
||||
;;
|
||||
debian*) pkg_type=deb
|
||||
;;
|
||||
fedora*) pkg_type=rpm
|
||||
;;
|
||||
opensuse-leap*) pkg_type=rpm
|
||||
;;
|
||||
ubuntu*) pkg_type=deb
|
||||
;;
|
||||
*) exit 1
|
||||
;;
|
||||
esac
|
||||
echo "${pkg_type}"
|
||||
}
|
||||
|
||||
function get_artifactory_repository() {
|
||||
local pkg_type=$(package_type $1)
|
||||
|
||||
case ${pkg_type} in
|
||||
deb) echo "sw-gpu-cloudnative-debian-local"
|
||||
;;
|
||||
rpm) echo "sw-gpu-cloudnative-rpm-local"
|
||||
;;
|
||||
*) echo "sw-gpu-cloudnative-generic-local"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -25,7 +25,7 @@ RUN fpm -s empty \
|
||||
rm -f /tmp/docker.rpm
|
||||
|
||||
|
||||
RUN curl -s -L https://nvidia.github.io/libnvidia-container/fedora35/nvidia-container-toolkit.repo \
|
||||
RUN curl -s -L https://nvidia.github.io/libnvidia-container/fedora35/libnvidia-container.repo \
|
||||
| tee /etc/yum.repos.d/nvidia-container-toolkit.repo
|
||||
|
||||
COPY entrypoint.sh /
|
||||
|
||||
2
third_party/libnvidia-container
vendored
2
third_party/libnvidia-container
vendored
Submodule third_party/libnvidia-container updated: 2ef666498c...505dedfee8
@@ -20,23 +20,52 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/crio"
|
||||
"github.com/pelletier/go-toml"
|
||||
log "github.com/sirupsen/logrus"
|
||||
cli "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
restartModeSystemd = "systemd"
|
||||
restartModeNone = "none"
|
||||
|
||||
defaultConfigMode = "hook"
|
||||
|
||||
// Hook-based settings
|
||||
defaultHooksDir = "/usr/share/containers/oci/hooks.d"
|
||||
defaultHookFilename = "oci-nvidia-hook.json"
|
||||
|
||||
// Config-based settings
|
||||
defaultConfig = "/etc/crio/crio.conf"
|
||||
defaultRuntimeClass = "nvidia"
|
||||
defaultSetAsDefault = true
|
||||
defaultRestartMode = restartModeSystemd
|
||||
defaultHostRootMount = "/host"
|
||||
)
|
||||
|
||||
var hooksDirFlag string
|
||||
var hookFilenameFlag string
|
||||
var tooklitDirArg string
|
||||
// options stores the configuration from the command linek or environment variables
|
||||
type options struct {
|
||||
configMode string
|
||||
|
||||
hooksDir string
|
||||
hookFilename string
|
||||
runtimeDir string
|
||||
|
||||
config string
|
||||
runtimeClass string
|
||||
setAsDefault bool
|
||||
restartMode string
|
||||
hostRootMount string
|
||||
}
|
||||
|
||||
func main() {
|
||||
options := options{}
|
||||
|
||||
// Create the top-level CLI
|
||||
c := cli.NewApp()
|
||||
c.Name = "crio"
|
||||
@@ -47,17 +76,22 @@ func main() {
|
||||
// Create the 'setup' subcommand
|
||||
setup := cli.Command{}
|
||||
setup.Name = "setup"
|
||||
setup.Usage = "Create the cri-o hook required to run NVIDIA GPU containers"
|
||||
setup.Usage = "Configure cri-o for NVIDIA GPU containers"
|
||||
setup.ArgsUsage = "<toolkit_dirname>"
|
||||
setup.Action = Setup
|
||||
setup.Before = ParseArgs
|
||||
setup.Action = func(c *cli.Context) error {
|
||||
return Setup(c, &options)
|
||||
}
|
||||
setup.Before = func(c *cli.Context) error {
|
||||
return ParseArgs(c, &options)
|
||||
}
|
||||
|
||||
// Create the 'cleanup' subcommand
|
||||
cleanup := cli.Command{}
|
||||
cleanup.Name = "cleanup"
|
||||
cleanup.Usage = "Remove the NVIDIA cri-o hook"
|
||||
cleanup.Action = Cleanup
|
||||
|
||||
cleanup.Usage = "Remove the NVIDIA-specific cri-o configuration"
|
||||
cleanup.Action = func(c *cli.Context) error {
|
||||
return Cleanup(c, &options)
|
||||
}
|
||||
// Register the subcommands with the top-level CLI
|
||||
c.Commands = []*cli.Command{
|
||||
&setup,
|
||||
@@ -74,7 +108,7 @@ func main() {
|
||||
Aliases: []string{"d"},
|
||||
Usage: "path to the cri-o hooks directory",
|
||||
Value: defaultHooksDir,
|
||||
Destination: &hooksDirFlag,
|
||||
Destination: &options.hooksDir,
|
||||
EnvVars: []string{"CRIO_HOOKS_DIR"},
|
||||
DefaultText: defaultHooksDir,
|
||||
},
|
||||
@@ -83,10 +117,54 @@ func main() {
|
||||
Aliases: []string{"f"},
|
||||
Usage: "filename of the cri-o hook that will be created / removed in the hooks directory",
|
||||
Value: defaultHookFilename,
|
||||
Destination: &hookFilenameFlag,
|
||||
Destination: &options.hookFilename,
|
||||
EnvVars: []string{"CRIO_HOOK_FILENAME"},
|
||||
DefaultText: defaultHookFilename,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config-mode",
|
||||
Usage: "the configuration mode to use. One of [hook | config]",
|
||||
Value: defaultConfigMode,
|
||||
Destination: &options.configMode,
|
||||
EnvVars: []string{"CRIO_CONFIG_MODE"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Usage: "Path to the cri-o config file",
|
||||
Value: defaultConfig,
|
||||
Destination: &options.config,
|
||||
EnvVars: []string{"CRIO_CONFIG"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "runtime-class",
|
||||
Usage: "The name of the runtime class to set for the nvidia-container-runtime",
|
||||
Value: defaultRuntimeClass,
|
||||
Destination: &options.runtimeClass,
|
||||
EnvVars: []string{"CRIO_RUNTIME_CLASS"},
|
||||
},
|
||||
// The flags below are only used by the 'setup' command.
|
||||
&cli.BoolFlag{
|
||||
Name: "set-as-default",
|
||||
Usage: "Set nvidia-container-runtime as the default runtime",
|
||||
Value: defaultSetAsDefault,
|
||||
Destination: &options.setAsDefault,
|
||||
EnvVars: []string{"CRIO_SET_AS_DEFAULT"},
|
||||
Hidden: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "restart-mode",
|
||||
Usage: "Specify how cri-o should be restarted; If 'none' is selected, it will not be restarted [systemd | none]",
|
||||
Value: defaultRestartMode,
|
||||
Destination: &options.restartMode,
|
||||
EnvVars: []string{"CRIO_RESTART_MODE"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "host-root",
|
||||
Usage: "Specify the path to the host root to be used when restarting crio using systemd",
|
||||
Value: defaultHostRootMount,
|
||||
Destination: &options.hostRootMount,
|
||||
EnvVars: []string{"HOST_ROOT_MOUNT"},
|
||||
},
|
||||
}
|
||||
|
||||
// Update the subcommand flags with the common subcommand flags
|
||||
@@ -100,16 +178,30 @@ func main() {
|
||||
}
|
||||
|
||||
// Setup installs the prestart hook required to launch GPU-enabled containers
|
||||
func Setup(c *cli.Context) error {
|
||||
func Setup(c *cli.Context, o *options) error {
|
||||
log.Infof("Starting 'setup' for %v", c.App.Name)
|
||||
|
||||
err := os.MkdirAll(hooksDirFlag, 0755)
|
||||
switch o.configMode {
|
||||
case "hook":
|
||||
return setupHook(o)
|
||||
case "config":
|
||||
return setupConfig(o)
|
||||
default:
|
||||
return fmt.Errorf("invalid config-mode '%v'", o.configMode)
|
||||
}
|
||||
}
|
||||
|
||||
// setupHook installs the prestart hook required to launch GPU-enabled containers
|
||||
func setupHook(o *options) error {
|
||||
log.Infof("Installing prestart hook")
|
||||
|
||||
err := os.MkdirAll(o.hooksDir, 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating hooks directory %v: %v", hooksDirFlag, err)
|
||||
return fmt.Errorf("error creating hooks directory %v: %v", o.hooksDir, err)
|
||||
}
|
||||
|
||||
hookPath := getHookPath(hooksDirFlag, hookFilenameFlag)
|
||||
err = createHook(tooklitDirArg, hookPath)
|
||||
hookPath := getHookPath(o.hooksDir, o.hookFilename)
|
||||
err = createHook(o.runtimeDir, hookPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating hook: %v", err)
|
||||
}
|
||||
@@ -117,11 +209,52 @@ func Setup(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupConfig updates the cri-o config for the NVIDIA container runtime
|
||||
func setupConfig(o *options) error {
|
||||
log.Infof("Updating config file")
|
||||
|
||||
cfg, err := crio.LoadConfig(o.config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load config: %v", err)
|
||||
}
|
||||
|
||||
err = UpdateConfig(cfg, o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update config: %v", err)
|
||||
}
|
||||
|
||||
err = crio.FlushConfig(o.config, cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to flush config: %v", err)
|
||||
}
|
||||
|
||||
err = RestartCrio(o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to restart crio: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cleanup removes the specified prestart hook
|
||||
func Cleanup(c *cli.Context) error {
|
||||
func Cleanup(c *cli.Context, o *options) error {
|
||||
log.Infof("Starting 'cleanup' for %v", c.App.Name)
|
||||
|
||||
hookPath := getHookPath(hooksDirFlag, hookFilenameFlag)
|
||||
switch o.configMode {
|
||||
case "hook":
|
||||
return cleanupHook(o)
|
||||
case "config":
|
||||
return cleanupConfig(o)
|
||||
default:
|
||||
return fmt.Errorf("invalid config-mode '%v'", o.configMode)
|
||||
}
|
||||
}
|
||||
|
||||
// cleanupHook removes the prestart hook
|
||||
func cleanupHook(o *options) error {
|
||||
log.Infof("Removing prestart hook")
|
||||
|
||||
hookPath := getHookPath(o.hooksDir, o.hookFilename)
|
||||
err := os.Remove(hookPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error removing hook '%v': %v", hookPath, err)
|
||||
@@ -130,15 +263,42 @@ func Cleanup(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// cleanupConfig removes the NVIDIA container runtime from the cri-o config
|
||||
func cleanupConfig(o *options) error {
|
||||
log.Infof("Reverting config file modifications")
|
||||
|
||||
cfg, err := crio.LoadConfig(o.config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load config: %v", err)
|
||||
}
|
||||
|
||||
err = RevertConfig(cfg, o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update config: %v", err)
|
||||
}
|
||||
|
||||
err = crio.FlushConfig(o.config, cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to flush config: %v", err)
|
||||
}
|
||||
|
||||
err = RestartCrio(o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to restart crio: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseArgs parses the command line arguments to the CLI
|
||||
func ParseArgs(c *cli.Context) error {
|
||||
func ParseArgs(c *cli.Context, o *options) error {
|
||||
args := c.Args()
|
||||
|
||||
log.Infof("Parsing arguments: %v", args.Slice())
|
||||
if c.NArg() != 1 {
|
||||
return fmt.Errorf("incorrect number of arguments")
|
||||
}
|
||||
tooklitDirArg = args.Get(0)
|
||||
o.runtimeDir = args.Get(0)
|
||||
log.Infof("Successfully parsed arguments")
|
||||
|
||||
return nil
|
||||
@@ -152,7 +312,7 @@ func createHook(toolkitDir string, hookPath string) error {
|
||||
defer hook.Close()
|
||||
|
||||
encoder := json.NewEncoder(hook)
|
||||
err = encoder.Encode(generateOciHook(tooklitDirArg))
|
||||
err = encoder.Encode(generateOciHook(toolkitDir))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing hook file '%v': %v", hookPath, err)
|
||||
}
|
||||
@@ -183,3 +343,45 @@ func generateOciHook(toolkitDir string) podmanHook {
|
||||
}
|
||||
return hook
|
||||
}
|
||||
|
||||
// UpdateConfig updates the cri-o config to include the NVIDIA Container Runtime
|
||||
func UpdateConfig(config *toml.Tree, o *options) error {
|
||||
runtimePath := filepath.Join(o.runtimeDir, "nvidia-container-runtime")
|
||||
return crio.UpdateConfig(config, o.runtimeClass, runtimePath, o.setAsDefault)
|
||||
}
|
||||
|
||||
// RevertConfig reverts the cri-o config to remove the NVIDIA Container Runtime
|
||||
func RevertConfig(config *toml.Tree, o *options) error {
|
||||
return crio.RevertConfig(config, o.runtimeClass)
|
||||
}
|
||||
|
||||
// RestartCrio restarts crio depending on the value of restartModeFlag
|
||||
func RestartCrio(o *options) error {
|
||||
switch o.restartMode {
|
||||
case restartModeNone:
|
||||
log.Warnf("Skipping restart of crio due to --restart-mode=%v", o.restartMode)
|
||||
return nil
|
||||
case restartModeSystemd:
|
||||
return RestartCrioSystemd(o.hostRootMount)
|
||||
default:
|
||||
return fmt.Errorf("invalid restart mode specified: %v", o.restartMode)
|
||||
}
|
||||
}
|
||||
|
||||
// RestartCrioSystemd restarts cri-o using systemctl
|
||||
func RestartCrioSystemd(hostRootMount string) error {
|
||||
log.Infof("Restarting cri-o using systemd and host root mounted at %v", hostRootMount)
|
||||
|
||||
command := "chroot"
|
||||
args := []string{hostRootMount, "systemctl", "restart", "crio"}
|
||||
|
||||
cmd := exec.Command(command, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error restarting crio using systemd: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -250,10 +250,15 @@ func LoadConfig(config string) (map[string]interface{}, error) {
|
||||
|
||||
// UpdateConfig updates the docker config to include the nvidia runtimes
|
||||
func UpdateConfig(config map[string]interface{}, o *options) error {
|
||||
defaultRuntime := o.getDefaultRuntime()
|
||||
runtimes := o.runtimes()
|
||||
for runtimeName, runtimePath := range o.getRuntimeBinaries() {
|
||||
setAsDefault := runtimeName == o.getDefaultRuntime()
|
||||
err := docker.UpdateConfig(config, runtimeName, runtimePath, setAsDefault)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update runtime %q: %v", runtimeName, err)
|
||||
}
|
||||
}
|
||||
|
||||
return docker.UpdateConfig(config, defaultRuntime, runtimes)
|
||||
return nil
|
||||
}
|
||||
|
||||
//RevertConfig reverts the docker config to remove the nvidia runtime
|
||||
@@ -392,19 +397,6 @@ func (o options) getDefaultRuntime() string {
|
||||
return o.runtimeName
|
||||
}
|
||||
|
||||
// runtimes returns the docker runtime definitions for the supported nvidia runtimes
|
||||
// for the given options. This includes the path with the options runtimeDir applied
|
||||
func (o options) runtimes() map[string]interface{} {
|
||||
runtimes := make(map[string]interface{})
|
||||
for r, bin := range o.getRuntimeBinaries() {
|
||||
runtimes[r] = map[string]interface{}{
|
||||
"path": bin,
|
||||
"args": []string{},
|
||||
}
|
||||
}
|
||||
return runtimes
|
||||
}
|
||||
|
||||
// getRuntimeBinaries returns a map of runtime names to binary paths. This includes the
|
||||
// renaming of the `nvidia` runtime as per the --runtime-class command line flag.
|
||||
func (o options) getRuntimeBinaries() map[string]string {
|
||||
|
||||
@@ -30,23 +30,35 @@ var availableRuntimes = map[string]struct{}{"docker": {}, "crio": {}, "container
|
||||
var waitingForSignal = make(chan bool, 1)
|
||||
var signalReceived = make(chan bool, 1)
|
||||
|
||||
var destinationArg string
|
||||
var noDaemonFlag bool
|
||||
var runtimeFlag string
|
||||
var runtimeArgsFlag string
|
||||
// options stores the command line arguments
|
||||
type options struct {
|
||||
noDaemon bool
|
||||
runtime string
|
||||
runtimeArgs string
|
||||
root string
|
||||
}
|
||||
|
||||
// Version defines the CLI version. This is set at build time using LD FLAGS
|
||||
var Version = "development"
|
||||
|
||||
func main() {
|
||||
remainingArgs, root, err := ParseArgs(os.Args)
|
||||
if err != nil {
|
||||
log.Errorf("Error: unable to parse arguments: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
options := options{}
|
||||
// Create the top-level CLI
|
||||
c := cli.NewApp()
|
||||
c.Name = "nvidia-toolkit"
|
||||
c.Usage = "Install the nvidia-container-toolkit for use by a given runtime"
|
||||
c.UsageText = "DESTINATION [-n | --no-daemon] [-r | --runtime] [-u | --runtime-args]"
|
||||
c.UsageText = "[DESTINATION] [-n | --no-daemon] [-r | --runtime] [-u | --runtime-args]"
|
||||
c.Description = "DESTINATION points to the host path underneath which the nvidia-container-toolkit should be installed.\nIt will be installed at ${DESTINATION}/toolkit"
|
||||
c.Version = Version
|
||||
c.Action = Run
|
||||
c.Action = func(ctx *cli.Context) error {
|
||||
return Run(ctx, &options)
|
||||
}
|
||||
|
||||
// Setup flags for the CLI
|
||||
c.Flags = []cli.Flag{
|
||||
@@ -54,7 +66,7 @@ func main() {
|
||||
Name: "no-daemon",
|
||||
Aliases: []string{"n"},
|
||||
Usage: "terminate immediatly after setting up the runtime. Note that no cleanup will be performed",
|
||||
Destination: &noDaemonFlag,
|
||||
Destination: &options.noDaemon,
|
||||
EnvVars: []string{"NO_DAEMON"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
@@ -62,7 +74,7 @@ func main() {
|
||||
Aliases: []string{"r"},
|
||||
Usage: "the runtime to setup on this node. One of {'docker', 'crio', 'containerd'}",
|
||||
Value: defaultRuntime,
|
||||
Destination: &runtimeFlag,
|
||||
Destination: &options.runtime,
|
||||
EnvVars: []string{"RUNTIME"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
@@ -70,20 +82,20 @@ func main() {
|
||||
Aliases: []string{"u"},
|
||||
Usage: "arguments to pass to 'docker', 'crio', or 'containerd' setup command",
|
||||
Value: defaultRuntimeArgs,
|
||||
Destination: &runtimeArgsFlag,
|
||||
Destination: &options.runtimeArgs,
|
||||
EnvVars: []string{"RUNTIME_ARGS"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "root",
|
||||
Value: root,
|
||||
Usage: "the folder where the NVIDIA Container Toolkit is to be installed. It will be installed to `ROOT`/toolkit",
|
||||
Destination: &options.root,
|
||||
EnvVars: []string{"ROOT"},
|
||||
},
|
||||
}
|
||||
|
||||
// Run the CLI
|
||||
log.Infof("Starting %v", c.Name)
|
||||
|
||||
remainingArgs, err := ParseArgs(os.Args)
|
||||
if err != nil {
|
||||
log.Errorf("Error: unable to parse arguments: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := c.Run(remainingArgs); err != nil {
|
||||
log.Errorf("error running nvidia-toolkit: %v", err)
|
||||
os.Exit(1)
|
||||
@@ -93,8 +105,8 @@ func main() {
|
||||
}
|
||||
|
||||
// Run runs the core logic of the CLI
|
||||
func Run(c *cli.Context) error {
|
||||
err := verifyFlags()
|
||||
func Run(c *cli.Context, o *options) error {
|
||||
err := verifyFlags(o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to verify flags: %v", err)
|
||||
}
|
||||
@@ -105,23 +117,23 @@ func Run(c *cli.Context) error {
|
||||
}
|
||||
defer shutdown()
|
||||
|
||||
err = installToolkit()
|
||||
err = installToolkit(o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to install toolkit: %v", err)
|
||||
}
|
||||
|
||||
err = setupRuntime()
|
||||
err = setupRuntime(o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to setup runtime: %v", err)
|
||||
}
|
||||
|
||||
if !noDaemonFlag {
|
||||
if !o.noDaemon {
|
||||
err = waitForSignal()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to wait for signal: %v", err)
|
||||
}
|
||||
|
||||
err = cleanupRuntime()
|
||||
err = cleanupRuntime(o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to cleanup runtime: %v", err)
|
||||
}
|
||||
@@ -130,46 +142,42 @@ func Run(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseArgs parses the command line arguments and returns the remaining arguments
|
||||
func ParseArgs(args []string) ([]string, error) {
|
||||
// ParseArgs checks if a single positional argument was defined and extracts this the root.
|
||||
// If no positional arguments are defined, the it is assumed that the root is specified as a flag.
|
||||
func ParseArgs(args []string) ([]string, string, error) {
|
||||
log.Infof("Parsing arguments")
|
||||
|
||||
numPositionalArgs := 2 // Includes command itself
|
||||
|
||||
if len(args) < numPositionalArgs {
|
||||
return nil, fmt.Errorf("missing arguments")
|
||||
if len(args) < 2 {
|
||||
return args, "", nil
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
if arg == "--help" || arg == "-h" {
|
||||
return []string{args[0], arg}, nil
|
||||
}
|
||||
if arg == "--version" || arg == "-v" {
|
||||
return []string{args[0], arg}, nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, arg := range args[:numPositionalArgs] {
|
||||
var lastPositionalArg int
|
||||
for i, arg := range args {
|
||||
if strings.HasPrefix(arg, "-") {
|
||||
return nil, fmt.Errorf("unexpected flag where argument should be")
|
||||
break
|
||||
}
|
||||
lastPositionalArg = i
|
||||
}
|
||||
|
||||
for _, arg := range args[numPositionalArgs:] {
|
||||
if !strings.HasPrefix(arg, "-") {
|
||||
return nil, fmt.Errorf("unexpected argument where flag should be")
|
||||
}
|
||||
if lastPositionalArg == 0 {
|
||||
return args, "", nil
|
||||
}
|
||||
|
||||
destinationArg = args[1]
|
||||
if lastPositionalArg == 1 {
|
||||
return append([]string{args[0]}, args[2:]...), args[1], nil
|
||||
}
|
||||
|
||||
return append([]string{args[0]}, args[numPositionalArgs:]...), nil
|
||||
return nil, "", fmt.Errorf("unexpected positional argument(s) %v", args[2:lastPositionalArg+1])
|
||||
}
|
||||
|
||||
func verifyFlags() error {
|
||||
func verifyFlags(o *options) error {
|
||||
log.Infof("Verifying Flags")
|
||||
if _, exists := availableRuntimes[runtimeFlag]; !exists {
|
||||
return fmt.Errorf("unknown runtime: %v", runtimeFlag)
|
||||
if o.root == "" {
|
||||
return fmt.Errorf("the install root must be specified")
|
||||
}
|
||||
|
||||
if _, exists := availableRuntimes[o.runtime]; !exists {
|
||||
return fmt.Errorf("unknown runtime: %v", o.runtime)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -211,14 +219,14 @@ func initialize() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func installToolkit() error {
|
||||
func installToolkit(o *options) error {
|
||||
log.Infof("Installing toolkit")
|
||||
|
||||
cmdline := []string{
|
||||
toolkitCommand,
|
||||
"install",
|
||||
"--toolkit-root",
|
||||
filepath.Join(destinationArg, toolkitSubDir),
|
||||
filepath.Join(o.root, toolkitSubDir),
|
||||
}
|
||||
|
||||
cmd := exec.Command("sh", "-c", strings.Join(cmdline, " "))
|
||||
@@ -232,19 +240,19 @@ func installToolkit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupRuntime() error {
|
||||
toolkitDir := filepath.Join(destinationArg, toolkitSubDir)
|
||||
func setupRuntime(o *options) error {
|
||||
toolkitDir := filepath.Join(o.root, toolkitSubDir)
|
||||
|
||||
log.Infof("Setting up runtime")
|
||||
|
||||
cmdline := fmt.Sprintf("%v setup %v %v\n", runtimeFlag, runtimeArgsFlag, toolkitDir)
|
||||
cmdline := fmt.Sprintf("%v setup %v %v\n", o.runtime, o.runtimeArgs, toolkitDir)
|
||||
|
||||
cmd := exec.Command("sh", "-c", cmdline)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error running %v command: %v", runtimeFlag, err)
|
||||
return fmt.Errorf("error running %v command: %v", o.runtime, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -257,19 +265,19 @@ func waitForSignal() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanupRuntime() error {
|
||||
toolkitDir := filepath.Join(destinationArg, toolkitSubDir)
|
||||
func cleanupRuntime(o *options) error {
|
||||
toolkitDir := filepath.Join(o.root, toolkitSubDir)
|
||||
|
||||
log.Infof("Cleaning up Runtime")
|
||||
|
||||
cmdline := fmt.Sprintf("%v cleanup %v %v\n", runtimeFlag, runtimeArgsFlag, toolkitDir)
|
||||
cmdline := fmt.Sprintf("%v cleanup %v %v\n", o.runtime, o.runtimeArgs, toolkitDir)
|
||||
|
||||
cmd := exec.Command("sh", "-c", cmdline)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error running %v command: %v", runtimeFlag, err)
|
||||
return fmt.Errorf("error running %v command: %v", o.runtime, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
84
tools/container/nvidia-toolkit/run_test.go
Normal file
84
tools/container/nvidia-toolkit/run_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
# 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseArgs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
args []string
|
||||
expectedRemaining []string
|
||||
expectedRoot string
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
args: []string{},
|
||||
expectedRemaining: []string{},
|
||||
expectedRoot: "",
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
args: []string{"app"},
|
||||
expectedRemaining: []string{"app"},
|
||||
},
|
||||
{
|
||||
args: []string{"app", "root"},
|
||||
expectedRemaining: []string{"app"},
|
||||
expectedRoot: "root",
|
||||
},
|
||||
{
|
||||
args: []string{"app", "--flag"},
|
||||
expectedRemaining: []string{"app", "--flag"},
|
||||
},
|
||||
{
|
||||
args: []string{"app", "root", "--flag"},
|
||||
expectedRemaining: []string{"app", "--flag"},
|
||||
expectedRoot: "root",
|
||||
},
|
||||
{
|
||||
args: []string{"app", "root", "not-root", "--flag"},
|
||||
expectedError: fmt.Errorf("unexpected positional argument(s) [not-root]"),
|
||||
},
|
||||
{
|
||||
args: []string{"app", "root", "not-root"},
|
||||
expectedError: fmt.Errorf("unexpected positional argument(s) [not-root]"),
|
||||
},
|
||||
{
|
||||
args: []string{"app", "root", "not-root", "also"},
|
||||
expectedError: fmt.Errorf("unexpected positional argument(s) [not-root also]"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
remaining, root, err := ParseArgs(tc.args)
|
||||
if tc.expectedError != nil {
|
||||
require.EqualError(t, err, tc.expectedError.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
require.ElementsMatch(t, tc.expectedRemaining, remaining)
|
||||
require.Equal(t, tc.expectedRoot, root)
|
||||
})
|
||||
}
|
||||
}
|
||||
3
vendor/github.com/BurntSushi/toml/go.mod
generated
vendored
3
vendor/github.com/BurntSushi/toml/go.mod
generated
vendored
@@ -1,3 +0,0 @@
|
||||
module github.com/BurntSushi/toml
|
||||
|
||||
go 1.16
|
||||
64
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/cgo_helpers.go
generated
vendored
Normal file
64
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/cgo_helpers.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2020, 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 nvml
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
import "C"
|
||||
|
||||
var cgoAllocsUnknown = new(struct{})
|
||||
|
||||
type stringHeader struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
}
|
||||
|
||||
func clen(n []byte) int {
|
||||
for i := 0; i < len(n); i++ {
|
||||
if n[i] == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return len(n)
|
||||
}
|
||||
|
||||
func uint32SliceToIntSlice(s []uint32) []int {
|
||||
ret := make([]int, len(s))
|
||||
for i := range s {
|
||||
ret[i] = int(s[i])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// packPCharString creates a Go string backed by *C.char and avoids copying.
|
||||
func packPCharString(p *C.char) (raw string) {
|
||||
if p != nil && *p != 0 {
|
||||
h := (*stringHeader)(unsafe.Pointer(&raw))
|
||||
h.Data = unsafe.Pointer(p)
|
||||
for *p != 0 {
|
||||
p = (*C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1)) // p++
|
||||
}
|
||||
h.Len = int(uintptr(unsafe.Pointer(p)) - uintptr(h.Data))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// unpackPCharString represents the data from Go string as *C.char and avoids copying.
|
||||
func unpackPCharString(str string) (*C.char, *struct{}) {
|
||||
h := (*stringHeader)(unsafe.Pointer(&str))
|
||||
return (*C.char)(h.Data), cgoAllocsUnknown
|
||||
}
|
||||
23
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/cgo_helpers.h
generated
vendored
Normal file
23
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/cgo_helpers.h
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2020, 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.
|
||||
|
||||
// WARNING: THIS FILE WAS AUTOMATICALLY GENERATED.
|
||||
// Code generated by https://git.io/c-for-go. DO NOT EDIT.
|
||||
|
||||
#include "nvml.h"
|
||||
#include <stdlib.h>
|
||||
#pragma once
|
||||
|
||||
#define __CGOGEN 1
|
||||
|
||||
1139
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/const.go
generated
vendored
Normal file
1139
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/const.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
27
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/const_gen.go
generated
vendored
Normal file
27
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/const_gen.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2021, 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 nvml
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
SYSTEM_PROCESS_NAME_BUFFER_SIZE = 256
|
||||
)
|
||||
|
||||
func STRUCT_VERSION(data interface{}, version uint32) uint32 {
|
||||
return uint32(uint32(reflect.Indirect(reflect.ValueOf(data)).Type().Size()) | (version << uint32(24)))
|
||||
}
|
||||
2288
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/device.go
generated
vendored
Normal file
2288
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/device.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/doc.go
generated
vendored
Normal file
21
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/doc.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2020, 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.
|
||||
|
||||
// WARNING: THIS FILE WAS AUTOMATICALLY GENERATED.
|
||||
// Code generated by https://git.io/c-for-go. DO NOT EDIT.
|
||||
|
||||
/*
|
||||
Package NVML bindings
|
||||
*/
|
||||
package nvml
|
||||
42
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/event_set.go
generated
vendored
Normal file
42
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/event_set.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2020, 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 nvml
|
||||
|
||||
// nvml.EventSetCreate()
|
||||
func EventSetCreate() (EventSet, Return) {
|
||||
var Set EventSet
|
||||
ret := nvmlEventSetCreate(&Set)
|
||||
return Set, ret
|
||||
}
|
||||
|
||||
// nvml.EventSetWait()
|
||||
func EventSetWait(Set EventSet, Timeoutms uint32) (EventData, Return) {
|
||||
var Data EventData
|
||||
ret := nvmlEventSetWait(Set, &Data, Timeoutms)
|
||||
return Data, ret
|
||||
}
|
||||
|
||||
func (Set EventSet) Wait(Timeoutms uint32) (EventData, Return) {
|
||||
return EventSetWait(Set, Timeoutms)
|
||||
}
|
||||
|
||||
// nvml.EventSetFree()
|
||||
func EventSetFree(Set EventSet) Return {
|
||||
return nvmlEventSetFree(Set)
|
||||
}
|
||||
|
||||
func (Set EventSet) Free() Return {
|
||||
return EventSetFree(Set)
|
||||
}
|
||||
218
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/init.go
generated
vendored
Normal file
218
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/init.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
// Copyright (c) 2020, 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 nvml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NVIDIA/go-nvml/pkg/dl"
|
||||
)
|
||||
|
||||
import "C"
|
||||
|
||||
const (
|
||||
nvmlLibraryName = "libnvidia-ml.so.1"
|
||||
nvmlLibraryLoadFlags = dl.RTLD_LAZY | dl.RTLD_GLOBAL
|
||||
)
|
||||
|
||||
var nvml *dl.DynamicLibrary
|
||||
|
||||
// nvml.Init()
|
||||
func Init() Return {
|
||||
lib := dl.New(nvmlLibraryName, nvmlLibraryLoadFlags)
|
||||
err := lib.Open()
|
||||
if err != nil {
|
||||
return ERROR_LIBRARY_NOT_FOUND
|
||||
}
|
||||
|
||||
nvml = lib
|
||||
updateVersionedSymbols()
|
||||
|
||||
return nvmlInit()
|
||||
}
|
||||
|
||||
// nvml.InitWithFlags()
|
||||
func InitWithFlags(Flags uint32) Return {
|
||||
lib := dl.New(nvmlLibraryName, nvmlLibraryLoadFlags)
|
||||
err := lib.Open()
|
||||
if err != nil {
|
||||
return ERROR_LIBRARY_NOT_FOUND
|
||||
}
|
||||
|
||||
nvml = lib
|
||||
|
||||
return nvmlInitWithFlags(Flags)
|
||||
}
|
||||
|
||||
// nvml.Shutdown()
|
||||
func Shutdown() Return {
|
||||
ret := nvmlShutdown()
|
||||
if ret != SUCCESS {
|
||||
return ret
|
||||
}
|
||||
|
||||
err := nvml.Close()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error closing %s: %v", nvmlLibraryName, err))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Default all versioned APIs to v1 (to infer the types)
|
||||
var nvmlInit = nvmlInit_v1
|
||||
var nvmlDeviceGetPciInfo = nvmlDeviceGetPciInfo_v1
|
||||
var nvmlDeviceGetCount = nvmlDeviceGetCount_v1
|
||||
var nvmlDeviceGetHandleByIndex = nvmlDeviceGetHandleByIndex_v1
|
||||
var nvmlDeviceGetHandleByPciBusId = nvmlDeviceGetHandleByPciBusId_v1
|
||||
var nvmlDeviceGetNvLinkRemotePciInfo = nvmlDeviceGetNvLinkRemotePciInfo_v1
|
||||
var nvmlDeviceRemoveGpu = nvmlDeviceRemoveGpu_v1
|
||||
var nvmlDeviceGetGridLicensableFeatures = nvmlDeviceGetGridLicensableFeatures_v1
|
||||
var nvmlEventSetWait = nvmlEventSetWait_v1
|
||||
var nvmlDeviceGetAttributes = nvmlDeviceGetAttributes_v1
|
||||
var nvmlComputeInstanceGetInfo = nvmlComputeInstanceGetInfo_v1
|
||||
var DeviceGetComputeRunningProcesses = deviceGetComputeRunningProcesses_v1
|
||||
var DeviceGetGraphicsRunningProcesses = deviceGetGraphicsRunningProcesses_v1
|
||||
var DeviceGetMPSComputeRunningProcesses = deviceGetMPSComputeRunningProcesses_v1
|
||||
var GetBlacklistDeviceCount = GetExcludedDeviceCount
|
||||
var GetBlacklistDeviceInfoByIndex = GetExcludedDeviceInfoByIndex
|
||||
var nvmlDeviceGetGpuInstancePossiblePlacements = nvmlDeviceGetGpuInstancePossiblePlacements_v1
|
||||
var nvmlVgpuInstanceGetLicenseInfo = nvmlVgpuInstanceGetLicenseInfo_v1
|
||||
|
||||
type BlacklistDeviceInfo = ExcludedDeviceInfo
|
||||
type ProcessInfo_v1Slice []ProcessInfo_v1
|
||||
type ProcessInfo_v2Slice []ProcessInfo_v2
|
||||
|
||||
func (pis ProcessInfo_v1Slice) ToProcessInfoSlice() []ProcessInfo {
|
||||
var newInfos []ProcessInfo
|
||||
for _, pi := range pis {
|
||||
info := ProcessInfo{
|
||||
Pid: pi.Pid,
|
||||
UsedGpuMemory: pi.UsedGpuMemory,
|
||||
GpuInstanceId: 0xFFFFFFFF, // GPU instance ID is invalid in v1
|
||||
ComputeInstanceId: 0xFFFFFFFF, // Compute instance ID is invalid in v1
|
||||
}
|
||||
newInfos = append(newInfos, info)
|
||||
}
|
||||
return newInfos
|
||||
}
|
||||
|
||||
func (pis ProcessInfo_v2Slice) ToProcessInfoSlice() []ProcessInfo {
|
||||
var newInfos []ProcessInfo
|
||||
for _, pi := range pis {
|
||||
info := ProcessInfo{
|
||||
Pid: pi.Pid,
|
||||
UsedGpuMemory: pi.UsedGpuMemory,
|
||||
GpuInstanceId: pi.GpuInstanceId,
|
||||
ComputeInstanceId: pi.ComputeInstanceId,
|
||||
}
|
||||
newInfos = append(newInfos, info)
|
||||
}
|
||||
return newInfos
|
||||
}
|
||||
|
||||
// updateVersionedSymbols()
|
||||
func updateVersionedSymbols() {
|
||||
err := nvml.Lookup("nvmlInit_v2")
|
||||
if err == nil {
|
||||
nvmlInit = nvmlInit_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetPciInfo_v2")
|
||||
if err == nil {
|
||||
nvmlDeviceGetPciInfo = nvmlDeviceGetPciInfo_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetPciInfo_v3")
|
||||
if err == nil {
|
||||
nvmlDeviceGetPciInfo = nvmlDeviceGetPciInfo_v3
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetCount_v2")
|
||||
if err == nil {
|
||||
nvmlDeviceGetCount = nvmlDeviceGetCount_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetHandleByIndex_v2")
|
||||
if err == nil {
|
||||
nvmlDeviceGetHandleByIndex = nvmlDeviceGetHandleByIndex_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetHandleByPciBusId_v2")
|
||||
if err == nil {
|
||||
nvmlDeviceGetHandleByPciBusId = nvmlDeviceGetHandleByPciBusId_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetNvLinkRemotePciInfo_v2")
|
||||
if err == nil {
|
||||
nvmlDeviceGetNvLinkRemotePciInfo = nvmlDeviceGetNvLinkRemotePciInfo_v2
|
||||
}
|
||||
// Unable to overwrite nvmlDeviceRemoveGpu() because the v2 function takes
|
||||
// a different set of parameters than the v1 function.
|
||||
//err = nvml.Lookup("nvmlDeviceRemoveGpu_v2")
|
||||
//if err == nil {
|
||||
// nvmlDeviceRemoveGpu = nvmlDeviceRemoveGpu_v2
|
||||
//}
|
||||
err = nvml.Lookup("nvmlDeviceGetGridLicensableFeatures_v2")
|
||||
if err == nil {
|
||||
nvmlDeviceGetGridLicensableFeatures = nvmlDeviceGetGridLicensableFeatures_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetGridLicensableFeatures_v3")
|
||||
if err == nil {
|
||||
nvmlDeviceGetGridLicensableFeatures = nvmlDeviceGetGridLicensableFeatures_v3
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetGridLicensableFeatures_v4")
|
||||
if err == nil {
|
||||
nvmlDeviceGetGridLicensableFeatures = nvmlDeviceGetGridLicensableFeatures_v4
|
||||
}
|
||||
err = nvml.Lookup("nvmlEventSetWait_v2")
|
||||
if err == nil {
|
||||
nvmlEventSetWait = nvmlEventSetWait_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetAttributes_v2")
|
||||
if err == nil {
|
||||
nvmlDeviceGetAttributes = nvmlDeviceGetAttributes_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlComputeInstanceGetInfo_v2")
|
||||
if err == nil {
|
||||
nvmlComputeInstanceGetInfo = nvmlComputeInstanceGetInfo_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetComputeRunningProcesses_v2")
|
||||
if err == nil {
|
||||
DeviceGetComputeRunningProcesses = deviceGetComputeRunningProcesses_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetComputeRunningProcesses_v3")
|
||||
if err == nil {
|
||||
DeviceGetComputeRunningProcesses = deviceGetComputeRunningProcesses_v3
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetGraphicsRunningProcesses_v2")
|
||||
if err == nil {
|
||||
DeviceGetGraphicsRunningProcesses = deviceGetGraphicsRunningProcesses_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetGraphicsRunningProcesses_v3")
|
||||
if err == nil {
|
||||
DeviceGetGraphicsRunningProcesses = deviceGetGraphicsRunningProcesses_v3
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetMPSComputeRunningProcesses_v2")
|
||||
if err == nil {
|
||||
DeviceGetMPSComputeRunningProcesses = deviceGetMPSComputeRunningProcesses_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetMPSComputeRunningProcesses_v3")
|
||||
if err == nil {
|
||||
DeviceGetMPSComputeRunningProcesses = deviceGetMPSComputeRunningProcesses_v3
|
||||
}
|
||||
err = nvml.Lookup("nvmlDeviceGetGpuInstancePossiblePlacements_v2")
|
||||
if err == nil {
|
||||
nvmlDeviceGetGpuInstancePossiblePlacements = nvmlDeviceGetGpuInstancePossiblePlacements_v2
|
||||
}
|
||||
err = nvml.Lookup("nvmlVgpuInstanceGetLicenseInfo_v2")
|
||||
if err == nil {
|
||||
nvmlVgpuInstanceGetLicenseInfo = nvmlVgpuInstanceGetLicenseInfo_v2
|
||||
}
|
||||
}
|
||||
2583
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/nvml.go
generated
vendored
Normal file
2583
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/nvml.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8459
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/nvml.h
generated
vendored
Normal file
8459
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/nvml.h
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
20
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/return.go
generated
vendored
Normal file
20
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/return.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2020, 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 nvml
|
||||
|
||||
// nvml.ErrorString()
|
||||
func ErrorString(Result Return) string {
|
||||
return nvmlErrorString(Result)
|
||||
}
|
||||
81
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/system.go
generated
vendored
Normal file
81
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/system.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2020, 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 nvml
|
||||
|
||||
// nvml.SystemGetDriverVersion()
|
||||
func SystemGetDriverVersion() (string, Return) {
|
||||
Version := make([]byte, SYSTEM_DRIVER_VERSION_BUFFER_SIZE)
|
||||
ret := nvmlSystemGetDriverVersion(&Version[0], SYSTEM_DRIVER_VERSION_BUFFER_SIZE)
|
||||
return string(Version[:clen(Version)]), ret
|
||||
}
|
||||
|
||||
// nvml.SystemGetNVMLVersion()
|
||||
func SystemGetNVMLVersion() (string, Return) {
|
||||
Version := make([]byte, SYSTEM_NVML_VERSION_BUFFER_SIZE)
|
||||
ret := nvmlSystemGetNVMLVersion(&Version[0], SYSTEM_NVML_VERSION_BUFFER_SIZE)
|
||||
return string(Version[:clen(Version)]), ret
|
||||
}
|
||||
|
||||
// nvml.SystemGetCudaDriverVersion()
|
||||
func SystemGetCudaDriverVersion() (int, Return) {
|
||||
var CudaDriverVersion int32
|
||||
ret := nvmlSystemGetCudaDriverVersion(&CudaDriverVersion)
|
||||
return int(CudaDriverVersion), ret
|
||||
}
|
||||
|
||||
// nvml.SystemGetCudaDriverVersion_v2()
|
||||
func SystemGetCudaDriverVersion_v2() (int, Return) {
|
||||
var CudaDriverVersion int32
|
||||
ret := nvmlSystemGetCudaDriverVersion_v2(&CudaDriverVersion)
|
||||
return int(CudaDriverVersion), ret
|
||||
}
|
||||
|
||||
// nvml.SystemGetProcessName()
|
||||
func SystemGetProcessName(Pid int) (string, Return) {
|
||||
Name := make([]byte, SYSTEM_PROCESS_NAME_BUFFER_SIZE)
|
||||
ret := nvmlSystemGetProcessName(uint32(Pid), &Name[0], SYSTEM_PROCESS_NAME_BUFFER_SIZE)
|
||||
return string(Name[:clen(Name)]), ret
|
||||
}
|
||||
|
||||
// nvml.SystemGetHicVersion()
|
||||
func SystemGetHicVersion() ([]HwbcEntry, Return) {
|
||||
var HwbcCount uint32 = 1 // Will be reduced upon returning
|
||||
for {
|
||||
HwbcEntries := make([]HwbcEntry, HwbcCount)
|
||||
ret := nvmlSystemGetHicVersion(&HwbcCount, &HwbcEntries[0])
|
||||
if ret == SUCCESS {
|
||||
return HwbcEntries[:HwbcCount], ret
|
||||
}
|
||||
if ret != ERROR_INSUFFICIENT_SIZE {
|
||||
return nil, ret
|
||||
}
|
||||
HwbcCount *= 2
|
||||
}
|
||||
}
|
||||
|
||||
// nvml.SystemGetTopologyGpuSet()
|
||||
func SystemGetTopologyGpuSet(CpuNumber int) ([]Device, Return) {
|
||||
var Count uint32
|
||||
ret := nvmlSystemGetTopologyGpuSet(uint32(CpuNumber), &Count, nil)
|
||||
if ret != SUCCESS {
|
||||
return nil, ret
|
||||
}
|
||||
if Count == 0 {
|
||||
return []Device{}, ret
|
||||
}
|
||||
DeviceArray := make([]Device, Count)
|
||||
ret = nvmlSystemGetTopologyGpuSet(uint32(CpuNumber), &Count, &DeviceArray[0])
|
||||
return DeviceArray, ret
|
||||
}
|
||||
445
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/types_gen.go
generated
vendored
Normal file
445
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/types_gen.go
generated
vendored
Normal file
@@ -0,0 +1,445 @@
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs types.go
|
||||
|
||||
package nvml
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type Device struct {
|
||||
Handle *_Ctype_struct_nvmlDevice_st
|
||||
}
|
||||
|
||||
type PciInfo struct {
|
||||
BusIdLegacy [16]int8
|
||||
Domain uint32
|
||||
Bus uint32
|
||||
Device uint32
|
||||
PciDeviceId uint32
|
||||
PciSubSystemId uint32
|
||||
BusId [32]int8
|
||||
}
|
||||
|
||||
type EccErrorCounts struct {
|
||||
L1Cache uint64
|
||||
L2Cache uint64
|
||||
DeviceMemory uint64
|
||||
RegisterFile uint64
|
||||
}
|
||||
|
||||
type Utilization struct {
|
||||
Gpu uint32
|
||||
Memory uint32
|
||||
}
|
||||
|
||||
type Memory struct {
|
||||
Total uint64
|
||||
Free uint64
|
||||
Used uint64
|
||||
}
|
||||
|
||||
type Memory_v2 struct {
|
||||
Version uint32
|
||||
Total uint64
|
||||
Reserved uint64
|
||||
Free uint64
|
||||
Used uint64
|
||||
}
|
||||
|
||||
type BAR1Memory struct {
|
||||
Bar1Total uint64
|
||||
Bar1Free uint64
|
||||
Bar1Used uint64
|
||||
}
|
||||
|
||||
type ProcessInfo_v1 struct {
|
||||
Pid uint32
|
||||
UsedGpuMemory uint64
|
||||
}
|
||||
|
||||
type ProcessInfo_v2 struct {
|
||||
Pid uint32
|
||||
UsedGpuMemory uint64
|
||||
GpuInstanceId uint32
|
||||
ComputeInstanceId uint32
|
||||
}
|
||||
|
||||
type ProcessInfo struct {
|
||||
Pid uint32
|
||||
UsedGpuMemory uint64
|
||||
GpuInstanceId uint32
|
||||
ComputeInstanceId uint32
|
||||
}
|
||||
|
||||
type DeviceAttributes struct {
|
||||
MultiprocessorCount uint32
|
||||
SharedCopyEngineCount uint32
|
||||
SharedDecoderCount uint32
|
||||
SharedEncoderCount uint32
|
||||
SharedJpegCount uint32
|
||||
SharedOfaCount uint32
|
||||
GpuInstanceSliceCount uint32
|
||||
ComputeInstanceSliceCount uint32
|
||||
MemorySizeMB uint64
|
||||
}
|
||||
|
||||
type RowRemapperHistogramValues struct {
|
||||
Max uint32
|
||||
High uint32
|
||||
Partial uint32
|
||||
Low uint32
|
||||
None uint32
|
||||
}
|
||||
|
||||
type NvLinkUtilizationControl struct {
|
||||
Units uint32
|
||||
Pktfilter uint32
|
||||
}
|
||||
|
||||
type BridgeChipInfo struct {
|
||||
Type uint32
|
||||
FwVersion uint32
|
||||
}
|
||||
|
||||
type BridgeChipHierarchy struct {
|
||||
BridgeCount uint8
|
||||
BridgeChipInfo [128]BridgeChipInfo
|
||||
}
|
||||
|
||||
const sizeofValue = unsafe.Sizeof([8]byte{})
|
||||
|
||||
type Value [sizeofValue]byte
|
||||
|
||||
type Sample struct {
|
||||
TimeStamp uint64
|
||||
SampleValue [8]byte
|
||||
}
|
||||
|
||||
type ViolationTime struct {
|
||||
ReferenceTime uint64
|
||||
ViolationTime uint64
|
||||
}
|
||||
|
||||
type ClkMonFaultInfo struct {
|
||||
ClkApiDomain uint32
|
||||
ClkDomainFaultMask uint32
|
||||
}
|
||||
|
||||
type ClkMonStatus struct {
|
||||
BGlobalStatus uint32
|
||||
ClkMonListSize uint32
|
||||
ClkMonList [32]ClkMonFaultInfo
|
||||
}
|
||||
|
||||
type VgpuTypeId uint32
|
||||
|
||||
type VgpuInstance uint32
|
||||
|
||||
type VgpuInstanceUtilizationSample struct {
|
||||
VgpuInstance uint32
|
||||
TimeStamp uint64
|
||||
SmUtil [8]byte
|
||||
MemUtil [8]byte
|
||||
EncUtil [8]byte
|
||||
DecUtil [8]byte
|
||||
}
|
||||
|
||||
type VgpuProcessUtilizationSample struct {
|
||||
VgpuInstance uint32
|
||||
Pid uint32
|
||||
ProcessName [64]int8
|
||||
TimeStamp uint64
|
||||
SmUtil uint32
|
||||
MemUtil uint32
|
||||
EncUtil uint32
|
||||
DecUtil uint32
|
||||
}
|
||||
|
||||
type VgpuLicenseExpiry struct {
|
||||
Year uint32
|
||||
Month uint16
|
||||
Day uint16
|
||||
Hour uint16
|
||||
Min uint16
|
||||
Sec uint16
|
||||
Status uint8
|
||||
Pad_cgo_0 [1]byte
|
||||
}
|
||||
|
||||
type VgpuLicenseInfo struct {
|
||||
IsLicensed uint8
|
||||
LicenseExpiry VgpuLicenseExpiry
|
||||
CurrentState uint32
|
||||
}
|
||||
|
||||
type ProcessUtilizationSample struct {
|
||||
Pid uint32
|
||||
TimeStamp uint64
|
||||
SmUtil uint32
|
||||
MemUtil uint32
|
||||
EncUtil uint32
|
||||
DecUtil uint32
|
||||
}
|
||||
|
||||
type GridLicenseExpiry struct {
|
||||
Year uint32
|
||||
Month uint16
|
||||
Day uint16
|
||||
Hour uint16
|
||||
Min uint16
|
||||
Sec uint16
|
||||
Status uint8
|
||||
Pad_cgo_0 [1]byte
|
||||
}
|
||||
|
||||
type GridLicensableFeature struct {
|
||||
FeatureCode uint32
|
||||
FeatureState uint32
|
||||
LicenseInfo [128]int8
|
||||
ProductName [128]int8
|
||||
FeatureEnabled uint32
|
||||
LicenseExpiry GridLicenseExpiry
|
||||
}
|
||||
|
||||
type GridLicensableFeatures struct {
|
||||
IsGridLicenseSupported int32
|
||||
LicensableFeaturesCount uint32
|
||||
GridLicensableFeatures [3]GridLicensableFeature
|
||||
}
|
||||
|
||||
type DeviceArchitecture uint32
|
||||
|
||||
type BusType uint32
|
||||
|
||||
type PowerSource uint32
|
||||
|
||||
type FieldValue struct {
|
||||
FieldId uint32
|
||||
ScopeId uint32
|
||||
Timestamp int64
|
||||
LatencyUsec int64
|
||||
ValueType uint32
|
||||
NvmlReturn uint32
|
||||
Value [8]byte
|
||||
}
|
||||
|
||||
type Unit struct {
|
||||
Handle *_Ctype_struct_nvmlUnit_st
|
||||
}
|
||||
|
||||
type HwbcEntry struct {
|
||||
HwbcId uint32
|
||||
FirmwareVersion [32]int8
|
||||
}
|
||||
|
||||
type LedState struct {
|
||||
Cause [256]int8
|
||||
Color uint32
|
||||
}
|
||||
|
||||
type UnitInfo struct {
|
||||
Name [96]int8
|
||||
Id [96]int8
|
||||
Serial [96]int8
|
||||
FirmwareVersion [96]int8
|
||||
}
|
||||
|
||||
type PSUInfo struct {
|
||||
State [256]int8
|
||||
Current uint32
|
||||
Voltage uint32
|
||||
Power uint32
|
||||
}
|
||||
|
||||
type UnitFanInfo struct {
|
||||
Speed uint32
|
||||
State uint32
|
||||
}
|
||||
|
||||
type UnitFanSpeeds struct {
|
||||
Fans [24]UnitFanInfo
|
||||
Count uint32
|
||||
}
|
||||
|
||||
type EventSet struct {
|
||||
Handle *_Ctype_struct_nvmlEventSet_st
|
||||
}
|
||||
|
||||
type EventData struct {
|
||||
Device Device
|
||||
EventType uint64
|
||||
EventData uint64
|
||||
GpuInstanceId uint32
|
||||
ComputeInstanceId uint32
|
||||
}
|
||||
|
||||
type AccountingStats struct {
|
||||
GpuUtilization uint32
|
||||
MemoryUtilization uint32
|
||||
MaxMemoryUsage uint64
|
||||
Time uint64
|
||||
StartTime uint64
|
||||
IsRunning uint32
|
||||
Reserved [5]uint32
|
||||
}
|
||||
|
||||
type EncoderSessionInfo struct {
|
||||
SessionId uint32
|
||||
Pid uint32
|
||||
VgpuInstance uint32
|
||||
CodecType uint32
|
||||
HResolution uint32
|
||||
VResolution uint32
|
||||
AverageFps uint32
|
||||
AverageLatency uint32
|
||||
}
|
||||
|
||||
type FBCStats struct {
|
||||
SessionsCount uint32
|
||||
AverageFPS uint32
|
||||
AverageLatency uint32
|
||||
}
|
||||
|
||||
type FBCSessionInfo struct {
|
||||
SessionId uint32
|
||||
Pid uint32
|
||||
VgpuInstance uint32
|
||||
DisplayOrdinal uint32
|
||||
SessionType uint32
|
||||
SessionFlags uint32
|
||||
HMaxResolution uint32
|
||||
VMaxResolution uint32
|
||||
HResolution uint32
|
||||
VResolution uint32
|
||||
AverageFPS uint32
|
||||
AverageLatency uint32
|
||||
}
|
||||
|
||||
type AffinityScope uint32
|
||||
|
||||
type VgpuVersion struct {
|
||||
MinVersion uint32
|
||||
MaxVersion uint32
|
||||
}
|
||||
|
||||
type nvmlVgpuMetadata struct {
|
||||
Version uint32
|
||||
Revision uint32
|
||||
GuestInfoState uint32
|
||||
GuestDriverVersion [80]int8
|
||||
HostDriverVersion [80]int8
|
||||
Reserved [6]uint32
|
||||
VgpuVirtualizationCaps uint32
|
||||
GuestVgpuVersion uint32
|
||||
OpaqueDataSize uint32
|
||||
OpaqueData [4]int8
|
||||
}
|
||||
|
||||
type nvmlVgpuPgpuMetadata struct {
|
||||
Version uint32
|
||||
Revision uint32
|
||||
HostDriverVersion [80]int8
|
||||
PgpuVirtualizationCaps uint32
|
||||
Reserved [5]uint32
|
||||
HostSupportedVgpuRange VgpuVersion
|
||||
OpaqueDataSize uint32
|
||||
OpaqueData [4]int8
|
||||
}
|
||||
|
||||
type VgpuPgpuCompatibility struct {
|
||||
VgpuVmCompatibility uint32
|
||||
CompatibilityLimitCode uint32
|
||||
}
|
||||
|
||||
type ExcludedDeviceInfo struct {
|
||||
PciInfo PciInfo
|
||||
Uuid [80]int8
|
||||
}
|
||||
|
||||
type GpuInstancePlacement struct {
|
||||
Start uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
type GpuInstanceProfileInfo struct {
|
||||
Id uint32
|
||||
IsP2pSupported uint32
|
||||
SliceCount uint32
|
||||
InstanceCount uint32
|
||||
MultiprocessorCount uint32
|
||||
CopyEngineCount uint32
|
||||
DecoderCount uint32
|
||||
EncoderCount uint32
|
||||
JpegCount uint32
|
||||
OfaCount uint32
|
||||
MemorySizeMB uint64
|
||||
}
|
||||
|
||||
type GpuInstanceProfileInfo_v2 struct {
|
||||
Version uint32
|
||||
Id uint32
|
||||
IsP2pSupported uint32
|
||||
SliceCount uint32
|
||||
InstanceCount uint32
|
||||
MultiprocessorCount uint32
|
||||
CopyEngineCount uint32
|
||||
DecoderCount uint32
|
||||
EncoderCount uint32
|
||||
JpegCount uint32
|
||||
OfaCount uint32
|
||||
MemorySizeMB uint64
|
||||
Name [96]int8
|
||||
}
|
||||
|
||||
type GpuInstanceInfo struct {
|
||||
Device Device
|
||||
Id uint32
|
||||
ProfileId uint32
|
||||
Placement GpuInstancePlacement
|
||||
}
|
||||
|
||||
type GpuInstance struct {
|
||||
Handle *_Ctype_struct_nvmlGpuInstance_st
|
||||
}
|
||||
|
||||
type ComputeInstancePlacement struct {
|
||||
Start uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
type ComputeInstanceProfileInfo struct {
|
||||
Id uint32
|
||||
SliceCount uint32
|
||||
InstanceCount uint32
|
||||
MultiprocessorCount uint32
|
||||
SharedCopyEngineCount uint32
|
||||
SharedDecoderCount uint32
|
||||
SharedEncoderCount uint32
|
||||
SharedJpegCount uint32
|
||||
SharedOfaCount uint32
|
||||
}
|
||||
|
||||
type ComputeInstanceProfileInfo_v2 struct {
|
||||
Version uint32
|
||||
Id uint32
|
||||
SliceCount uint32
|
||||
InstanceCount uint32
|
||||
MultiprocessorCount uint32
|
||||
SharedCopyEngineCount uint32
|
||||
SharedDecoderCount uint32
|
||||
SharedEncoderCount uint32
|
||||
SharedJpegCount uint32
|
||||
SharedOfaCount uint32
|
||||
Name [96]int8
|
||||
}
|
||||
|
||||
type ComputeInstanceInfo struct {
|
||||
Device Device
|
||||
GpuInstance GpuInstance
|
||||
Id uint32
|
||||
ProfileId uint32
|
||||
Placement ComputeInstancePlacement
|
||||
}
|
||||
|
||||
type ComputeInstance struct {
|
||||
Handle *_Ctype_struct_nvmlComputeInstance_st
|
||||
}
|
||||
113
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/unit.go
generated
vendored
Normal file
113
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/unit.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2020, 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 nvml
|
||||
|
||||
// nvml.UnitGetCount()
|
||||
func UnitGetCount() (int, Return) {
|
||||
var UnitCount uint32
|
||||
ret := nvmlUnitGetCount(&UnitCount)
|
||||
return int(UnitCount), ret
|
||||
}
|
||||
|
||||
// nvml.UnitGetHandleByIndex()
|
||||
func UnitGetHandleByIndex(Index int) (Unit, Return) {
|
||||
var Unit Unit
|
||||
ret := nvmlUnitGetHandleByIndex(uint32(Index), &Unit)
|
||||
return Unit, ret
|
||||
}
|
||||
|
||||
// nvml.UnitGetUnitInfo()
|
||||
func UnitGetUnitInfo(Unit Unit) (UnitInfo, Return) {
|
||||
var Info UnitInfo
|
||||
ret := nvmlUnitGetUnitInfo(Unit, &Info)
|
||||
return Info, ret
|
||||
}
|
||||
|
||||
func (Unit Unit) GetUnitInfo() (UnitInfo, Return) {
|
||||
return UnitGetUnitInfo(Unit)
|
||||
}
|
||||
|
||||
// nvml.UnitGetLedState()
|
||||
func UnitGetLedState(Unit Unit) (LedState, Return) {
|
||||
var State LedState
|
||||
ret := nvmlUnitGetLedState(Unit, &State)
|
||||
return State, ret
|
||||
}
|
||||
|
||||
func (Unit Unit) GetLedState() (LedState, Return) {
|
||||
return UnitGetLedState(Unit)
|
||||
}
|
||||
|
||||
// nvml.UnitGetPsuInfo()
|
||||
func UnitGetPsuInfo(Unit Unit) (PSUInfo, Return) {
|
||||
var Psu PSUInfo
|
||||
ret := nvmlUnitGetPsuInfo(Unit, &Psu)
|
||||
return Psu, ret
|
||||
}
|
||||
|
||||
func (Unit Unit) GetPsuInfo() (PSUInfo, Return) {
|
||||
return UnitGetPsuInfo(Unit)
|
||||
}
|
||||
|
||||
// nvml.UnitGetTemperature()
|
||||
func UnitGetTemperature(Unit Unit, Type int) (uint32, Return) {
|
||||
var Temp uint32
|
||||
ret := nvmlUnitGetTemperature(Unit, uint32(Type), &Temp)
|
||||
return Temp, ret
|
||||
}
|
||||
|
||||
func (Unit Unit) GetTemperature(Type int) (uint32, Return) {
|
||||
return UnitGetTemperature(Unit, Type)
|
||||
}
|
||||
|
||||
// nvml.UnitGetFanSpeedInfo()
|
||||
func UnitGetFanSpeedInfo(Unit Unit) (UnitFanSpeeds, Return) {
|
||||
var FanSpeeds UnitFanSpeeds
|
||||
ret := nvmlUnitGetFanSpeedInfo(Unit, &FanSpeeds)
|
||||
return FanSpeeds, ret
|
||||
}
|
||||
|
||||
func (Unit Unit) GetFanSpeedInfo() (UnitFanSpeeds, Return) {
|
||||
return UnitGetFanSpeedInfo(Unit)
|
||||
}
|
||||
|
||||
// nvml.UnitGetDevices()
|
||||
func UnitGetDevices(Unit Unit) ([]Device, Return) {
|
||||
var DeviceCount uint32 = 1 // Will be reduced upon returning
|
||||
for {
|
||||
Devices := make([]Device, DeviceCount)
|
||||
ret := nvmlUnitGetDevices(Unit, &DeviceCount, &Devices[0])
|
||||
if ret == SUCCESS {
|
||||
return Devices[:DeviceCount], ret
|
||||
}
|
||||
if ret != ERROR_INSUFFICIENT_SIZE {
|
||||
return nil, ret
|
||||
}
|
||||
DeviceCount *= 2
|
||||
}
|
||||
}
|
||||
|
||||
func (Unit Unit) GetDevices() ([]Device, Return) {
|
||||
return UnitGetDevices(Unit)
|
||||
}
|
||||
|
||||
// nvml.UnitSetLedState()
|
||||
func UnitSetLedState(Unit Unit, Color LedColor) Return {
|
||||
return nvmlUnitSetLedState(Unit, Color)
|
||||
}
|
||||
|
||||
func (Unit Unit) SetLedState(Color LedColor) Return {
|
||||
return UnitSetLedState(Unit, Color)
|
||||
}
|
||||
462
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/vgpu.go
generated
vendored
Normal file
462
vendor/github.com/NVIDIA/go-nvml/pkg/nvml/vgpu.go
generated
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
// Copyright (c) 2020, 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 nvml
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// nvml.VgpuMetadata
|
||||
type VgpuMetadata struct {
|
||||
nvmlVgpuMetadata
|
||||
OpaqueData []byte
|
||||
}
|
||||
|
||||
// nvml.VgpuPgpuMetadata
|
||||
type VgpuPgpuMetadata struct {
|
||||
nvmlVgpuPgpuMetadata
|
||||
OpaqueData []byte
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetClass()
|
||||
func VgpuTypeGetClass(VgpuTypeId VgpuTypeId) (string, Return) {
|
||||
var Size uint32 = DEVICE_NAME_BUFFER_SIZE
|
||||
VgpuTypeClass := make([]byte, DEVICE_NAME_BUFFER_SIZE)
|
||||
ret := nvmlVgpuTypeGetClass(VgpuTypeId, &VgpuTypeClass[0], &Size)
|
||||
return string(VgpuTypeClass[:clen(VgpuTypeClass)]), ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetClass() (string, Return) {
|
||||
return VgpuTypeGetClass(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetName()
|
||||
func VgpuTypeGetName(VgpuTypeId VgpuTypeId) (string, Return) {
|
||||
var Size uint32 = DEVICE_NAME_BUFFER_SIZE
|
||||
VgpuTypeName := make([]byte, DEVICE_NAME_BUFFER_SIZE)
|
||||
ret := nvmlVgpuTypeGetName(VgpuTypeId, &VgpuTypeName[0], &Size)
|
||||
return string(VgpuTypeName[:clen(VgpuTypeName)]), ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetName() (string, Return) {
|
||||
return VgpuTypeGetName(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetGpuInstanceProfileId()
|
||||
func VgpuTypeGetGpuInstanceProfileId(VgpuTypeId VgpuTypeId) (uint32, Return) {
|
||||
var Size uint32
|
||||
ret := nvmlVgpuTypeGetGpuInstanceProfileId(VgpuTypeId, &Size)
|
||||
return Size, ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetGpuInstanceProfileId() (uint32, Return) {
|
||||
return VgpuTypeGetGpuInstanceProfileId(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetDeviceID()
|
||||
func VgpuTypeGetDeviceID(VgpuTypeId VgpuTypeId) (uint64, uint64, Return) {
|
||||
var DeviceID, SubsystemID uint64
|
||||
ret := nvmlVgpuTypeGetDeviceID(VgpuTypeId, &DeviceID, &SubsystemID)
|
||||
return DeviceID, SubsystemID, ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetDeviceID() (uint64, uint64, Return) {
|
||||
return VgpuTypeGetDeviceID(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetFramebufferSize()
|
||||
func VgpuTypeGetFramebufferSize(VgpuTypeId VgpuTypeId) (uint64, Return) {
|
||||
var FbSize uint64
|
||||
ret := nvmlVgpuTypeGetFramebufferSize(VgpuTypeId, &FbSize)
|
||||
return FbSize, ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetFramebufferSize() (uint64, Return) {
|
||||
return VgpuTypeGetFramebufferSize(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetNumDisplayHeads()
|
||||
func VgpuTypeGetNumDisplayHeads(VgpuTypeId VgpuTypeId) (int, Return) {
|
||||
var NumDisplayHeads uint32
|
||||
ret := nvmlVgpuTypeGetNumDisplayHeads(VgpuTypeId, &NumDisplayHeads)
|
||||
return int(NumDisplayHeads), ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetNumDisplayHeads() (int, Return) {
|
||||
return VgpuTypeGetNumDisplayHeads(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetResolution()
|
||||
func VgpuTypeGetResolution(VgpuTypeId VgpuTypeId, DisplayIndex int) (uint32, uint32, Return) {
|
||||
var Xdim, Ydim uint32
|
||||
ret := nvmlVgpuTypeGetResolution(VgpuTypeId, uint32(DisplayIndex), &Xdim, &Ydim)
|
||||
return Xdim, Ydim, ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetResolution(DisplayIndex int) (uint32, uint32, Return) {
|
||||
return VgpuTypeGetResolution(VgpuTypeId, DisplayIndex)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetLicense()
|
||||
func VgpuTypeGetLicense(VgpuTypeId VgpuTypeId) (string, Return) {
|
||||
VgpuTypeLicenseString := make([]byte, GRID_LICENSE_BUFFER_SIZE)
|
||||
ret := nvmlVgpuTypeGetLicense(VgpuTypeId, &VgpuTypeLicenseString[0], GRID_LICENSE_BUFFER_SIZE)
|
||||
return string(VgpuTypeLicenseString[:clen(VgpuTypeLicenseString)]), ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetLicense() (string, Return) {
|
||||
return VgpuTypeGetLicense(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetFrameRateLimit()
|
||||
func VgpuTypeGetFrameRateLimit(VgpuTypeId VgpuTypeId) (uint32, Return) {
|
||||
var FrameRateLimit uint32
|
||||
ret := nvmlVgpuTypeGetFrameRateLimit(VgpuTypeId, &FrameRateLimit)
|
||||
return FrameRateLimit, ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetFrameRateLimit() (uint32, Return) {
|
||||
return VgpuTypeGetFrameRateLimit(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetMaxInstances()
|
||||
func VgpuTypeGetMaxInstances(Device Device, VgpuTypeId VgpuTypeId) (int, Return) {
|
||||
var VgpuInstanceCount uint32
|
||||
ret := nvmlVgpuTypeGetMaxInstances(Device, VgpuTypeId, &VgpuInstanceCount)
|
||||
return int(VgpuInstanceCount), ret
|
||||
}
|
||||
|
||||
func (Device Device) VgpuTypeGetMaxInstances(VgpuTypeId VgpuTypeId) (int, Return) {
|
||||
return VgpuTypeGetMaxInstances(Device, VgpuTypeId)
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetMaxInstances(Device Device) (int, Return) {
|
||||
return VgpuTypeGetMaxInstances(Device, VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuTypeGetMaxInstancesPerVm()
|
||||
func VgpuTypeGetMaxInstancesPerVm(VgpuTypeId VgpuTypeId) (int, Return) {
|
||||
var VgpuInstanceCountPerVm uint32
|
||||
ret := nvmlVgpuTypeGetMaxInstancesPerVm(VgpuTypeId, &VgpuInstanceCountPerVm)
|
||||
return int(VgpuInstanceCountPerVm), ret
|
||||
}
|
||||
|
||||
func (VgpuTypeId VgpuTypeId) GetMaxInstancesPerVm() (int, Return) {
|
||||
return VgpuTypeGetMaxInstancesPerVm(VgpuTypeId)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetVmID()
|
||||
func VgpuInstanceGetVmID(VgpuInstance VgpuInstance) (string, VgpuVmIdType, Return) {
|
||||
var VmIdType VgpuVmIdType
|
||||
VmId := make([]byte, DEVICE_UUID_BUFFER_SIZE)
|
||||
ret := nvmlVgpuInstanceGetVmID(VgpuInstance, &VmId[0], DEVICE_UUID_BUFFER_SIZE, &VmIdType)
|
||||
return string(VmId[:clen(VmId)]), VmIdType, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetVmID() (string, VgpuVmIdType, Return) {
|
||||
return VgpuInstanceGetVmID(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetUUID()
|
||||
func VgpuInstanceGetUUID(VgpuInstance VgpuInstance) (string, Return) {
|
||||
Uuid := make([]byte, DEVICE_UUID_BUFFER_SIZE)
|
||||
ret := nvmlVgpuInstanceGetUUID(VgpuInstance, &Uuid[0], DEVICE_UUID_BUFFER_SIZE)
|
||||
return string(Uuid[:clen(Uuid)]), ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetUUID() (string, Return) {
|
||||
return VgpuInstanceGetUUID(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetVmDriverVersion()
|
||||
func VgpuInstanceGetVmDriverVersion(VgpuInstance VgpuInstance) (string, Return) {
|
||||
Version := make([]byte, SYSTEM_DRIVER_VERSION_BUFFER_SIZE)
|
||||
ret := nvmlVgpuInstanceGetVmDriverVersion(VgpuInstance, &Version[0], SYSTEM_DRIVER_VERSION_BUFFER_SIZE)
|
||||
return string(Version[:clen(Version)]), ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetVmDriverVersion() (string, Return) {
|
||||
return VgpuInstanceGetVmDriverVersion(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetFbUsage()
|
||||
func VgpuInstanceGetFbUsage(VgpuInstance VgpuInstance) (uint64, Return) {
|
||||
var FbUsage uint64
|
||||
ret := nvmlVgpuInstanceGetFbUsage(VgpuInstance, &FbUsage)
|
||||
return FbUsage, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetFbUsage() (uint64, Return) {
|
||||
return VgpuInstanceGetFbUsage(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetLicenseInfo()
|
||||
func VgpuInstanceGetLicenseInfo(VgpuInstance VgpuInstance) (VgpuLicenseInfo, Return) {
|
||||
var LicenseInfo VgpuLicenseInfo
|
||||
ret := nvmlVgpuInstanceGetLicenseInfo(VgpuInstance, &LicenseInfo)
|
||||
return LicenseInfo, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetLicenseInfo() (VgpuLicenseInfo, Return) {
|
||||
return VgpuInstanceGetLicenseInfo(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetLicenseStatus()
|
||||
func VgpuInstanceGetLicenseStatus(VgpuInstance VgpuInstance) (int, Return) {
|
||||
var Licensed uint32
|
||||
ret := nvmlVgpuInstanceGetLicenseStatus(VgpuInstance, &Licensed)
|
||||
return int(Licensed), ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetLicenseStatus() (int, Return) {
|
||||
return VgpuInstanceGetLicenseStatus(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetType()
|
||||
func VgpuInstanceGetType(VgpuInstance VgpuInstance) (VgpuTypeId, Return) {
|
||||
var VgpuTypeId VgpuTypeId
|
||||
ret := nvmlVgpuInstanceGetType(VgpuInstance, &VgpuTypeId)
|
||||
return VgpuTypeId, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetType() (VgpuTypeId, Return) {
|
||||
return VgpuInstanceGetType(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetFrameRateLimit()
|
||||
func VgpuInstanceGetFrameRateLimit(VgpuInstance VgpuInstance) (uint32, Return) {
|
||||
var FrameRateLimit uint32
|
||||
ret := nvmlVgpuInstanceGetFrameRateLimit(VgpuInstance, &FrameRateLimit)
|
||||
return FrameRateLimit, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetFrameRateLimit() (uint32, Return) {
|
||||
return VgpuInstanceGetFrameRateLimit(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetEccMode()
|
||||
func VgpuInstanceGetEccMode(VgpuInstance VgpuInstance) (EnableState, Return) {
|
||||
var EccMode EnableState
|
||||
ret := nvmlVgpuInstanceGetEccMode(VgpuInstance, &EccMode)
|
||||
return EccMode, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetEccMode() (EnableState, Return) {
|
||||
return VgpuInstanceGetEccMode(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetEncoderCapacity()
|
||||
func VgpuInstanceGetEncoderCapacity(VgpuInstance VgpuInstance) (int, Return) {
|
||||
var EncoderCapacity uint32
|
||||
ret := nvmlVgpuInstanceGetEncoderCapacity(VgpuInstance, &EncoderCapacity)
|
||||
return int(EncoderCapacity), ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetEncoderCapacity() (int, Return) {
|
||||
return VgpuInstanceGetEncoderCapacity(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceSetEncoderCapacity()
|
||||
func VgpuInstanceSetEncoderCapacity(VgpuInstance VgpuInstance, EncoderCapacity int) Return {
|
||||
return nvmlVgpuInstanceSetEncoderCapacity(VgpuInstance, uint32(EncoderCapacity))
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) SetEncoderCapacity(EncoderCapacity int) Return {
|
||||
return VgpuInstanceSetEncoderCapacity(VgpuInstance, EncoderCapacity)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetEncoderStats()
|
||||
func VgpuInstanceGetEncoderStats(VgpuInstance VgpuInstance) (int, uint32, uint32, Return) {
|
||||
var SessionCount, AverageFps, AverageLatency uint32
|
||||
ret := nvmlVgpuInstanceGetEncoderStats(VgpuInstance, &SessionCount, &AverageFps, &AverageLatency)
|
||||
return int(SessionCount), AverageFps, AverageLatency, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetEncoderStats() (int, uint32, uint32, Return) {
|
||||
return VgpuInstanceGetEncoderStats(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetEncoderSessions()
|
||||
func VgpuInstanceGetEncoderSessions(VgpuInstance VgpuInstance) (int, EncoderSessionInfo, Return) {
|
||||
var SessionCount uint32
|
||||
var SessionInfo EncoderSessionInfo
|
||||
ret := nvmlVgpuInstanceGetEncoderSessions(VgpuInstance, &SessionCount, &SessionInfo)
|
||||
return int(SessionCount), SessionInfo, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetEncoderSessions() (int, EncoderSessionInfo, Return) {
|
||||
return VgpuInstanceGetEncoderSessions(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetFBCStats()
|
||||
func VgpuInstanceGetFBCStats(VgpuInstance VgpuInstance) (FBCStats, Return) {
|
||||
var FbcStats FBCStats
|
||||
ret := nvmlVgpuInstanceGetFBCStats(VgpuInstance, &FbcStats)
|
||||
return FbcStats, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetFBCStats() (FBCStats, Return) {
|
||||
return VgpuInstanceGetFBCStats(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetFBCSessions()
|
||||
func VgpuInstanceGetFBCSessions(VgpuInstance VgpuInstance) (int, FBCSessionInfo, Return) {
|
||||
var SessionCount uint32
|
||||
var SessionInfo FBCSessionInfo
|
||||
ret := nvmlVgpuInstanceGetFBCSessions(VgpuInstance, &SessionCount, &SessionInfo)
|
||||
return int(SessionCount), SessionInfo, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetFBCSessions() (int, FBCSessionInfo, Return) {
|
||||
return VgpuInstanceGetFBCSessions(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetGpuInstanceId()
|
||||
func VgpuInstanceGetGpuInstanceId(VgpuInstance VgpuInstance) (int, Return) {
|
||||
var gpuInstanceId uint32
|
||||
ret := nvmlVgpuInstanceGetGpuInstanceId(VgpuInstance, &gpuInstanceId)
|
||||
return int(gpuInstanceId), ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetGpuInstanceId() (int, Return) {
|
||||
return VgpuInstanceGetGpuInstanceId(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetGpuPciId()
|
||||
func VgpuInstanceGetGpuPciId(VgpuInstance VgpuInstance) (string, Return) {
|
||||
var Length uint32 = 1 // Will be reduced upon returning
|
||||
for {
|
||||
VgpuPciId := make([]byte, Length)
|
||||
ret := nvmlVgpuInstanceGetGpuPciId(VgpuInstance, &VgpuPciId[0], &Length)
|
||||
if ret == SUCCESS {
|
||||
return string(VgpuPciId[:clen(VgpuPciId)]), ret
|
||||
}
|
||||
if ret != ERROR_INSUFFICIENT_SIZE {
|
||||
return "", ret
|
||||
}
|
||||
Length *= 2
|
||||
}
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetGpuPciId() (string, Return) {
|
||||
return VgpuInstanceGetGpuPciId(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetMetadata()
|
||||
func VgpuInstanceGetMetadata(VgpuInstance VgpuInstance) (VgpuMetadata, Return) {
|
||||
var VgpuMetadata VgpuMetadata
|
||||
OpaqueDataSize := unsafe.Sizeof(VgpuMetadata.nvmlVgpuMetadata.OpaqueData)
|
||||
VgpuMetadataSize := unsafe.Sizeof(VgpuMetadata.nvmlVgpuMetadata) - OpaqueDataSize
|
||||
for {
|
||||
BufferSize := uint32(VgpuMetadataSize + OpaqueDataSize)
|
||||
Buffer := make([]byte, BufferSize)
|
||||
nvmlVgpuMetadataPtr := (*nvmlVgpuMetadata)(unsafe.Pointer(&Buffer[0]))
|
||||
ret := nvmlVgpuInstanceGetMetadata(VgpuInstance, nvmlVgpuMetadataPtr, &BufferSize)
|
||||
if ret == SUCCESS {
|
||||
VgpuMetadata.nvmlVgpuMetadata = *nvmlVgpuMetadataPtr
|
||||
VgpuMetadata.OpaqueData = Buffer[VgpuMetadataSize:BufferSize]
|
||||
return VgpuMetadata, ret
|
||||
}
|
||||
if ret != ERROR_INSUFFICIENT_SIZE {
|
||||
return VgpuMetadata, ret
|
||||
}
|
||||
OpaqueDataSize = 2 * OpaqueDataSize
|
||||
}
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetMetadata() (VgpuMetadata, Return) {
|
||||
return VgpuInstanceGetMetadata(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetAccountingMode()
|
||||
func VgpuInstanceGetAccountingMode(VgpuInstance VgpuInstance) (EnableState, Return) {
|
||||
var Mode EnableState
|
||||
ret := nvmlVgpuInstanceGetAccountingMode(VgpuInstance, &Mode)
|
||||
return Mode, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetAccountingMode() (EnableState, Return) {
|
||||
return VgpuInstanceGetAccountingMode(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetAccountingPids()
|
||||
func VgpuInstanceGetAccountingPids(VgpuInstance VgpuInstance) ([]int, Return) {
|
||||
var Count uint32 = 1 // Will be reduced upon returning
|
||||
for {
|
||||
Pids := make([]uint32, Count)
|
||||
ret := nvmlVgpuInstanceGetAccountingPids(VgpuInstance, &Count, &Pids[0])
|
||||
if ret == SUCCESS {
|
||||
return uint32SliceToIntSlice(Pids[:Count]), ret
|
||||
}
|
||||
if ret != ERROR_INSUFFICIENT_SIZE {
|
||||
return nil, ret
|
||||
}
|
||||
Count *= 2
|
||||
}
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetAccountingPids() ([]int, Return) {
|
||||
return VgpuInstanceGetAccountingPids(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetAccountingStats()
|
||||
func VgpuInstanceGetAccountingStats(VgpuInstance VgpuInstance, Pid int) (AccountingStats, Return) {
|
||||
var Stats AccountingStats
|
||||
ret := nvmlVgpuInstanceGetAccountingStats(VgpuInstance, uint32(Pid), &Stats)
|
||||
return Stats, ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetAccountingStats(Pid int) (AccountingStats, Return) {
|
||||
return VgpuInstanceGetAccountingStats(VgpuInstance, Pid)
|
||||
}
|
||||
|
||||
// nvml.GetVgpuCompatibility()
|
||||
func GetVgpuCompatibility(nvmlVgpuMetadata *nvmlVgpuMetadata, PgpuMetadata *nvmlVgpuPgpuMetadata) (VgpuPgpuCompatibility, Return) {
|
||||
var CompatibilityInfo VgpuPgpuCompatibility
|
||||
ret := nvmlGetVgpuCompatibility(nvmlVgpuMetadata, PgpuMetadata, &CompatibilityInfo)
|
||||
return CompatibilityInfo, ret
|
||||
}
|
||||
|
||||
// nvml.GetVgpuVersion()
|
||||
func GetVgpuVersion() (VgpuVersion, VgpuVersion, Return) {
|
||||
var Supported, Current VgpuVersion
|
||||
ret := nvmlGetVgpuVersion(&Supported, &Current)
|
||||
return Supported, Current, ret
|
||||
}
|
||||
|
||||
// nvml.SetVgpuVersion()
|
||||
func SetVgpuVersion(VgpuVersion *VgpuVersion) Return {
|
||||
return SetVgpuVersion(VgpuVersion)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceClearAccountingPids()
|
||||
func VgpuInstanceClearAccountingPids(VgpuInstance VgpuInstance) Return {
|
||||
return nvmlVgpuInstanceClearAccountingPids(VgpuInstance)
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) ClearAccountingPids() Return {
|
||||
return VgpuInstanceClearAccountingPids(VgpuInstance)
|
||||
}
|
||||
|
||||
// nvml.VgpuInstanceGetMdevUUID()
|
||||
func VgpuInstanceGetMdevUUID(VgpuInstance VgpuInstance) (string, Return) {
|
||||
MdevUuid := make([]byte, DEVICE_UUID_BUFFER_SIZE)
|
||||
ret := nvmlVgpuInstanceGetMdevUUID(VgpuInstance, &MdevUuid[0], DEVICE_UUID_BUFFER_SIZE)
|
||||
return string(MdevUuid[:clen(MdevUuid)]), ret
|
||||
}
|
||||
|
||||
func (VgpuInstance VgpuInstance) GetMdevUUID() (string, Return) {
|
||||
return VgpuInstanceGetMdevUUID(VgpuInstance)
|
||||
}
|
||||
@@ -446,7 +446,7 @@ func (w *watch) setup(dirs []string, dirErrors map[string]error) {
|
||||
|
||||
// Start watching Spec directories for relevant changes.
|
||||
func (w *watch) start(m *sync.Mutex, refresh func() error, dirErrors map[string]error) {
|
||||
go w.watch(m, refresh, dirErrors)
|
||||
go w.watch(w.watcher, m, refresh, dirErrors)
|
||||
}
|
||||
|
||||
// Stop watching directories.
|
||||
@@ -460,8 +460,8 @@ func (w *watch) stop() {
|
||||
}
|
||||
|
||||
// Watch Spec directory changes, triggering a refresh if necessary.
|
||||
func (w *watch) watch(m *sync.Mutex, refresh func() error, dirErrors map[string]error) {
|
||||
watch := w.watcher
|
||||
func (w *watch) watch(fsw *fsnotify.Watcher, m *sync.Mutex, refresh func() error, dirErrors map[string]error) {
|
||||
watch := fsw
|
||||
if watch == nil {
|
||||
return
|
||||
}
|
||||
|
||||
26
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_unix.go
generated
vendored
Normal file
26
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_unix.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
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 cdi
|
||||
|
||||
import "syscall"
|
||||
|
||||
func osSync() {
|
||||
syscall.Sync()
|
||||
}
|
||||
22
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_windows.go
generated
vendored
Normal file
22
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_windows.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
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 cdi
|
||||
|
||||
func osSync() {}
|
||||
@@ -27,8 +27,6 @@ import (
|
||||
"github.com/container-orchestrated-devices/container-device-interface/specs-go"
|
||||
oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
ocigen "github.com/opencontainers/runtime-tools/generate"
|
||||
|
||||
runc "github.com/opencontainers/runc/libcontainer/devices"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -85,11 +83,13 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
|
||||
}
|
||||
|
||||
for _, d := range e.DeviceNodes {
|
||||
dev := d.ToOCI()
|
||||
if err := fillMissingInfo(&dev); err != nil {
|
||||
dn := DeviceNode{d}
|
||||
|
||||
err := dn.fillMissingInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dev := d.ToOCI()
|
||||
if dev.UID == nil && spec.Process != nil {
|
||||
if uid := spec.Process.User.UID; uid > 0 {
|
||||
dev.UID = &uid
|
||||
@@ -287,32 +287,6 @@ func ensureOCIHooks(spec *oci.Spec) {
|
||||
}
|
||||
}
|
||||
|
||||
// fillMissingInfo fills in missing mandatory attributes from the host device.
|
||||
func fillMissingInfo(dev *oci.LinuxDevice) error {
|
||||
if dev.Type != "" && (dev.Major != 0 || dev.Type == "p") {
|
||||
return nil
|
||||
}
|
||||
hostDev, err := runc.DeviceFromPath(dev.Path, "rwm")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to stat CDI host device %q", dev.Path)
|
||||
}
|
||||
|
||||
if dev.Type == "" {
|
||||
dev.Type = string(hostDev.Type)
|
||||
} else {
|
||||
if dev.Type != string(hostDev.Type) {
|
||||
return errors.Errorf("CDI device %q, host type mismatch (%s, %s)",
|
||||
dev.Path, dev.Type, string(hostDev.Type))
|
||||
}
|
||||
}
|
||||
if dev.Major == 0 && dev.Type != "p" {
|
||||
dev.Major = hostDev.Major
|
||||
dev.Minor = hostDev.Minor
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sortMounts sorts the mounts in the given OCI Spec.
|
||||
func sortMounts(specgen *ocigen.Generator) {
|
||||
mounts := specgen.Mounts()
|
||||
|
||||
56
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_unix.go
generated
vendored
Normal file
56
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_unix.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
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 cdi
|
||||
|
||||
import (
|
||||
runc "github.com/opencontainers/runc/libcontainer/devices"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// fillMissingInfo fills in missing mandatory attributes from the host device.
|
||||
func (d *DeviceNode) fillMissingInfo() error {
|
||||
if d.HostPath == "" {
|
||||
d.HostPath = d.Path
|
||||
}
|
||||
|
||||
if d.Type != "" && (d.Major != 0 || d.Type == "p") {
|
||||
return nil
|
||||
}
|
||||
|
||||
hostDev, err := runc.DeviceFromPath(d.HostPath, "rwm")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to stat CDI host device %q", d.HostPath)
|
||||
}
|
||||
|
||||
if d.Type == "" {
|
||||
d.Type = string(hostDev.Type)
|
||||
} else {
|
||||
if d.Type != string(hostDev.Type) {
|
||||
return errors.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)",
|
||||
d.Path, d.HostPath, d.Type, string(hostDev.Type))
|
||||
}
|
||||
}
|
||||
if d.Major == 0 && d.Type != "p" {
|
||||
d.Major = hostDev.Major
|
||||
d.Minor = hostDev.Minor
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
27
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_windows.go
generated
vendored
Normal file
27
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_windows.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
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 cdi
|
||||
|
||||
import "fmt"
|
||||
|
||||
// fillMissingInfo fills in missing mandatory attributes from the host device.
|
||||
func (d *DeviceNode) fillMissingInfo() error {
|
||||
return fmt.Errorf("unimplemented")
|
||||
}
|
||||
@@ -130,7 +130,7 @@ func ValidateVendorName(vendor string) error {
|
||||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(vendor[len(vendor)-1])) {
|
||||
return errors.Errorf("invalid vendor %q, should end with letter", vendor)
|
||||
return errors.Errorf("invalid vendor %q, should end with a letter or digit", vendor)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -158,7 +158,7 @@ func ValidateClassName(class string) error {
|
||||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(class[len(class)-1])) {
|
||||
return errors.Errorf("invalid class %q, should end with letter", class)
|
||||
return errors.Errorf("invalid class %q, should end with a letter or digit", class)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -172,8 +172,11 @@ func ValidateDeviceName(name string) error {
|
||||
if name == "" {
|
||||
return errors.Errorf("invalid (empty) device name")
|
||||
}
|
||||
if !isLetter(rune(name[0])) {
|
||||
return errors.Errorf("invalid name %q, should start with letter", name)
|
||||
if !isAlphaNumeric(rune(name[0])) {
|
||||
return errors.Errorf("invalid class %q, should start with a letter or digit", name)
|
||||
}
|
||||
if len(name) == 1 {
|
||||
return nil
|
||||
}
|
||||
for _, c := range string(name[1 : len(name)-1]) {
|
||||
switch {
|
||||
@@ -185,7 +188,7 @@ func ValidateDeviceName(name string) error {
|
||||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(name[len(name)-1])) {
|
||||
return errors.Errorf("invalid name %q, should start with letter", name)
|
||||
return errors.Errorf("invalid name %q, should end with a letter or digit", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -79,6 +79,9 @@ func scanSpecDirs(dirs []string, scanFn scanSpecFunc) error {
|
||||
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
// for initial stat failure Walk calls us with nil info
|
||||
if info == nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
// first call from Walk is for dir itself, others we skip
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
@@ -36,10 +37,12 @@ var (
|
||||
"0.2.0": {},
|
||||
"0.3.0": {},
|
||||
"0.4.0": {},
|
||||
"0.5.0": {},
|
||||
}
|
||||
|
||||
// Externally set CDI Spec validation function.
|
||||
specValidator func(*cdi.Spec) error
|
||||
validatorLock sync.RWMutex
|
||||
)
|
||||
|
||||
// Spec represents a single CDI Spec. It is usually loaded from a
|
||||
@@ -248,11 +251,16 @@ func ParseSpec(data []byte) (*cdi.Spec, error) {
|
||||
// is used for extra CDI Spec content validation whenever a Spec file
|
||||
// loaded (using ReadSpec() or NewSpec()) or written (Spec.Write()).
|
||||
func SetSpecValidator(fn func(*cdi.Spec) error) {
|
||||
validatorLock.Lock()
|
||||
defer validatorLock.Unlock()
|
||||
specValidator = fn
|
||||
}
|
||||
|
||||
// validateSpec validates the Spec using the extneral validator.
|
||||
func validateSpec(raw *cdi.Spec) error {
|
||||
validatorLock.RLock()
|
||||
defer validatorLock.RUnlock()
|
||||
|
||||
if specValidator == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package specs
|
||||
import "os"
|
||||
|
||||
// CurrentVersion is the current version of the Spec.
|
||||
const CurrentVersion = "0.4.0"
|
||||
const CurrentVersion = "0.5.0"
|
||||
|
||||
// Spec is the base configuration for CDI
|
||||
type Spec struct {
|
||||
@@ -31,6 +31,7 @@ type ContainerEdits struct {
|
||||
// DeviceNode represents a device node that needs to be added to the OCI spec.
|
||||
type DeviceNode struct {
|
||||
Path string `json:"path"`
|
||||
HostPath string `json:"hostPath,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Major int64 `json:"major,omitempty"`
|
||||
Minor int64 `json:"minor,omitempty"`
|
||||
|
||||
20
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
20
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
@@ -7,9 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.5.4] - 2022-04-25
|
||||
|
||||
* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447)
|
||||
* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444)
|
||||
* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443)
|
||||
|
||||
## [1.5.3] - 2022-04-22
|
||||
|
||||
* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445)
|
||||
|
||||
## [1.5.2] - 2022-04-21
|
||||
|
||||
* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374)
|
||||
* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361)
|
||||
* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424)
|
||||
* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406)
|
||||
* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416)
|
||||
|
||||
## [1.5.1] - 2021-08-24
|
||||
|
||||
* Revert Add AddRaw to not follow symlinks
|
||||
* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394)
|
||||
|
||||
## [1.5.0] - 2021-08-20
|
||||
|
||||
|
||||
17
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
17
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
@@ -48,18 +48,6 @@ fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Win
|
||||
|
||||
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
|
||||
|
||||
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
|
||||
|
||||
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
|
||||
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
|
||||
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
|
||||
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
|
||||
* When you're done, you will want to halt or destroy the Vagrant boxes.
|
||||
|
||||
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
|
||||
|
||||
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
|
||||
|
||||
### Maintainers
|
||||
|
||||
Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
@@ -67,11 +55,6 @@ Help maintaining fsnotify is welcome. To be a maintainer:
|
||||
* Submit a pull request and sign the CLA as above.
|
||||
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||
|
||||
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
|
||||
|
||||
All code changes should be internal pull requests.
|
||||
|
||||
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||
|
||||
[hub]: https://github.com/github/hub
|
||||
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
||||
|
||||
24
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
24
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
@@ -1,12 +1,8 @@
|
||||
# File system notifications for Go
|
||||
|
||||
[](https://godoc.org/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
|
||||
[](https://pkg.go.dev/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [](https://github.com/fsnotify/fsnotify/issues/413)
|
||||
|
||||
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
|
||||
|
||||
```console
|
||||
go get -u golang.org/x/sys/...
|
||||
```
|
||||
fsnotify utilizes [`golang.org/x/sys`](https://pkg.go.dev/golang.org/x/sys) rather than [`syscall`](https://pkg.go.dev/syscall) from the standard library.
|
||||
|
||||
Cross platform: Windows, Linux, BSD and macOS.
|
||||
|
||||
@@ -16,22 +12,20 @@ Cross platform: Windows, Linux, BSD and macOS.
|
||||
| kqueue | BSD, macOS, iOS\* | Supported |
|
||||
| ReadDirectoryChangesW | Windows | Supported |
|
||||
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
|
||||
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) |
|
||||
| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) |
|
||||
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) |
|
||||
| fanotify | Linux 2.6.37+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) |
|
||||
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
|
||||
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
|
||||
|
||||
\* Android and iOS are untested.
|
||||
|
||||
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||
Please see [the documentation](https://pkg.go.dev/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||
|
||||
## API stability
|
||||
|
||||
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||
fsnotify is a fork of [howeyc/fsnotify](https://github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||
|
||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
|
||||
|
||||
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
||||
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -84,10 +78,6 @@ func main() {
|
||||
|
||||
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||
|
||||
## Example
|
||||
|
||||
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
|
||||
|
||||
## FAQ
|
||||
|
||||
**When a file is moved to another directory is it still being watched?**
|
||||
|
||||
36
vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go
generated
vendored
Normal file
36
vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows
|
||||
// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
|
||||
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Watcher watches a set of files, delivering events to a channel.
|
||||
type Watcher struct{}
|
||||
|
||||
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add starts watching the named file or directory (non-recursively).
|
||||
func (w *Watcher) Add(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove stops watching the the named file or directory (non-recursively).
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
return nil
|
||||
}
|
||||
7
vendor/github.com/fsnotify/fsnotify/go.mod
generated
vendored
7
vendor/github.com/fsnotify/fsnotify/go.mod
generated
vendored
@@ -1,7 +0,0 @@
|
||||
module github.com/fsnotify/fsnotify
|
||||
|
||||
go 1.13
|
||||
|
||||
require golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
|
||||
|
||||
retract v1.5.0
|
||||
2
vendor/github.com/fsnotify/fsnotify/go.sum
generated
vendored
2
vendor/github.com/fsnotify/fsnotify/go.sum
generated
vendored
@@ -1,2 +0,0 @@
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
13
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
13
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
@@ -163,6 +163,19 @@ func (w *Watcher) Remove(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WatchList returns the directories and files that are being monitered.
|
||||
func (w *Watcher) WatchList() []string {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
entries := make([]string, 0, len(w.watches))
|
||||
for pathname := range w.watches {
|
||||
entries = append(entries, pathname)
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
type watch struct {
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user