mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2025-06-26 18:18:24 +00:00
Compare commits
204 Commits
v1.17.6
...
pull-reque
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54ea4a24a7 | ||
|
|
e436533a6f | ||
|
|
0f299c3431 | ||
|
|
f852043078 | ||
|
|
ef0b16bc24 | ||
|
|
225dfec83f | ||
|
|
03c48a6824 | ||
|
|
6530826293 | ||
|
|
971fd195b3 | ||
|
|
3b10afd0fe | ||
|
|
6b7ed26fba | ||
|
|
8d5f1e2427 | ||
|
|
d82a9ccd89 | ||
|
|
8ac213e3e6 | ||
|
|
0128762832 | ||
|
|
d7b150a2e6 | ||
|
|
57c917e3b1 | ||
|
|
bc9ec77fdd | ||
|
|
82f2eb7b73 | ||
|
|
712d829018 | ||
|
|
598b9740fc | ||
|
|
968e2ccca4 | ||
|
|
aff9301f2e | ||
|
|
011fb72330 | ||
|
|
2adef9903e | ||
|
|
70b1f5af98 | ||
|
|
c9422f12b3 | ||
|
|
b7fbd56f7e | ||
|
|
bd87c009ba | ||
|
|
fc65d3a784 | ||
|
|
52b9631333 | ||
|
|
9429fbac5f | ||
|
|
04e9bf4ac1 | ||
|
|
3ceaf1f85c | ||
|
|
9f0c1042c4 | ||
|
|
352b55c8ce | ||
|
|
b13139793b | ||
|
|
05f44b7752 | ||
|
|
a109f28cb6 | ||
|
|
65b575fa96 | ||
|
|
6e413d8445 | ||
|
|
5d9b27f107 | ||
|
|
767aee913d | ||
|
|
25bac4c62a | ||
|
|
7e371aa024 | ||
|
|
bc2b937574 | ||
|
|
ae8561b509 | ||
|
|
64633903c7 | ||
|
|
1273f879cc | ||
|
|
8713a173fe | ||
|
|
e6d99934f8 | ||
|
|
0cf2d60406 | ||
|
|
0e759d4ad8 | ||
|
|
9e85fb54fc | ||
|
|
ce79d01cf5 | ||
|
|
5d27489d18 | ||
|
|
d80e8b9733 | ||
|
|
a72b9cd12c | ||
|
|
c2f4ac0959 | ||
|
|
5db5ddb31b | ||
|
|
ff1897f2e4 | ||
|
|
88f0157cae | ||
|
|
27f1738c3d | ||
|
|
f52df9522e | ||
|
|
edf79d6e8b | ||
|
|
6aadd6ed21 | ||
|
|
a1d60910b6 | ||
|
|
03f5a09aec | ||
|
|
1f2232fc5f | ||
|
|
b19f5d8f7d | ||
|
|
fa1379c6d5 | ||
|
|
4ded119c31 | ||
|
|
e0813e0c4d | ||
|
|
4add0a6bf2 | ||
|
|
fbcf8ef12e | ||
|
|
92472bd0ed | ||
|
|
ac236a80f8 | ||
|
|
b69d98d7cf | ||
|
|
adbe127afd | ||
|
|
82ccae23b1 | ||
|
|
44cf1f4e3b | ||
|
|
1d0777ee01 | ||
|
|
9f82e910f6 | ||
|
|
cb172ba336 | ||
|
|
bbdb13c47d | ||
|
|
03152dba8d | ||
|
|
cf026dce9a | ||
|
|
073fb138d7 | ||
|
|
948bc113f0 | ||
|
|
b457247a0c | ||
|
|
bae4b3ebd3 | ||
|
|
3a06066f6b | ||
|
|
c0292f5048 | ||
|
|
cd8937bc5b | ||
|
|
cec3445318 | ||
|
|
f830653738 | ||
|
|
6e9ff446c8 | ||
|
|
9a07de0ee8 | ||
|
|
517873e97d | ||
|
|
49b45693ee | ||
|
|
78d6cdc7f7 | ||
|
|
61640591ba | ||
|
|
df4c87b877 | ||
|
|
d6c312956b | ||
|
|
51f765dd71 | ||
|
|
d8cd5438e4 | ||
|
|
5ed25bb375 | ||
|
|
a7786d4d41 | ||
|
|
be1ac24f2a | ||
|
|
dd86f598b5 | ||
|
|
2b417c1a9a | ||
|
|
e89be14c86 | ||
|
|
f625242ed6 | ||
|
|
df73db7e1e | ||
|
|
89f33bdf71 | ||
|
|
6834d5e0a4 | ||
|
|
c91a1b1dc8 | ||
|
|
96d91df78e | ||
|
|
a990860bfa | ||
|
|
bf9d618ff2 | ||
|
|
7ae5c2901f | ||
|
|
6b236746ce | ||
|
|
ed3b52eb8d | ||
|
|
1176430278 | ||
|
|
c22f3bd56c | ||
|
|
6375e832ff | ||
|
|
991b9c222f | ||
|
|
fdad3927b4 | ||
|
|
6bd292eff8 | ||
|
|
9429ce039b | ||
|
|
d953bbb977 | ||
|
|
5cbf3f82d9 | ||
|
|
69375d7889 | ||
|
|
9753096398 | ||
|
|
76edd1d7ca | ||
|
|
a6476193c8 | ||
|
|
d75b1adeda | ||
|
|
9aa2f67a22 | ||
|
|
b89e7ca849 | ||
|
|
7c5ed8157b | ||
|
|
a401e4a5a6 | ||
|
|
2bc4201205 | ||
|
|
cb52e779ba | ||
|
|
8cc672bed9 | ||
|
|
be001d938c | ||
|
|
d584f9a40b | ||
|
|
11acbe7ca2 | ||
|
|
95bda3ad72 | ||
|
|
6e4b0632c5 | ||
|
|
e4be26ff55 | ||
|
|
8e6b57b38a | ||
|
|
c935779693 | ||
|
|
4b43a29957 | ||
|
|
b3b0d107de | ||
|
|
d22fca51b8 | ||
|
|
adad9b9c92 | ||
|
|
b6d360fbbe | ||
|
|
5699ec1cff | ||
|
|
ec182705f1 | ||
|
|
7598fe14bc | ||
|
|
4fc181a418 | ||
|
|
4bf5894833 | ||
|
|
272f891204 | ||
|
|
4b352e6bac | ||
|
|
178369eb8e | ||
|
|
3c012499db | ||
|
|
6e883bf10a | ||
|
|
cc61f186a8 | ||
|
|
aac0a62528 | ||
|
|
2529aebd6c | ||
|
|
784917a0d9 | ||
|
|
1330467652 | ||
|
|
22035d4561 | ||
|
|
9318aaf275 | ||
|
|
70261d84f1 | ||
|
|
f8f506fd85 | ||
|
|
b0a5fb9f86 | ||
|
|
83790dbccd | ||
|
|
7ceae92ac1 | ||
|
|
8dfa61338b | ||
|
|
484cae273c | ||
|
|
6e67bb247b | ||
|
|
8bd7dd7060 | ||
|
|
e25c052aa6 | ||
|
|
21ba9932d0 | ||
|
|
dcd65a6410 | ||
|
|
8603d605aa | ||
|
|
e1efa28fe6 | ||
|
|
75a934e11c | ||
|
|
43aca46f10 | ||
|
|
00f1d5a627 | ||
|
|
c0764366d9 | ||
|
|
1afada7de5 | ||
|
|
5c3ffc2fba | ||
|
|
e188090a92 | ||
|
|
1995925a7d | ||
|
|
46fc47c67a | ||
|
|
b142091234 | ||
|
|
e9b8ad95df | ||
|
|
f77a808105 | ||
|
|
832818084d | ||
|
|
ab0a4eaa19 | ||
|
|
0c687be794 | ||
|
|
8d869acce5 |
3
.github/copy-pr-bot.yaml
vendored
Normal file
3
.github/copy-pr-bot.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# https://docs.gha-runners.nvidia.com/apps/copy-pr-bot/#configuration
|
||||||
|
|
||||||
|
enabled: true
|
||||||
128
.github/dependabot.yml
vendored
128
.github/dependabot.yml
vendored
@@ -3,63 +3,43 @@
|
|||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
|
# main branch
|
||||||
- package-ecosystem: "gomod"
|
- package-ecosystem: "gomod"
|
||||||
target-branch: main
|
target-branch: main
|
||||||
directory: "/"
|
directories:
|
||||||
schedule:
|
- "/"
|
||||||
interval: "weekly"
|
- "deployments/devel"
|
||||||
day: "sunday"
|
- "tests"
|
||||||
ignore:
|
|
||||||
- dependency-name: k8s.io/*
|
|
||||||
labels:
|
|
||||||
- dependencies
|
|
||||||
|
|
||||||
- package-ecosystem: "docker"
|
|
||||||
target-branch: main
|
|
||||||
directory: "/deployments/container"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
|
||||||
- package-ecosystem: "gomod"
|
|
||||||
# This defines a specific dependabot rule for the latest release-* branch.
|
|
||||||
target-branch: release-1.16
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
day: "sunday"
|
|
||||||
ignore:
|
|
||||||
- dependency-name: k8s.io/*
|
|
||||||
labels:
|
|
||||||
- dependencies
|
|
||||||
- maintenance
|
|
||||||
|
|
||||||
- package-ecosystem: "docker"
|
|
||||||
target-branch: release-1.16
|
|
||||||
directory: "/deployments/container"
|
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
labels:
|
labels:
|
||||||
- dependencies
|
- dependencies
|
||||||
- maintenance
|
groups:
|
||||||
|
k8sio:
|
||||||
|
patterns:
|
||||||
|
- k8s.io/*
|
||||||
|
exclude-patterns:
|
||||||
|
- k8s.io/klog/*
|
||||||
|
|
||||||
- package-ecosystem: "gomod"
|
|
||||||
target-branch: main
|
|
||||||
directory: "deployments/devel"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
day: "sunday"
|
|
||||||
|
|
||||||
# A dependabot rule to bump the golang version.
|
|
||||||
- package-ecosystem: "docker"
|
- package-ecosystem: "docker"
|
||||||
target-branch: main
|
target-branch: main
|
||||||
directory: "/deployments/devel"
|
directories:
|
||||||
|
# CUDA image
|
||||||
|
- "/deployments/container"
|
||||||
|
# Golang version
|
||||||
|
- "/deployments/devel"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- dependencies
|
||||||
|
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
|
target-branch: main
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- dependencies
|
||||||
|
|
||||||
# Allow dependabot to update the libnvidia-container submodule.
|
# Allow dependabot to update the libnvidia-container submodule.
|
||||||
- package-ecosystem: "gitsubmodule"
|
- package-ecosystem: "gitsubmodule"
|
||||||
@@ -72,3 +52,69 @@ updates:
|
|||||||
labels:
|
labels:
|
||||||
- dependencies
|
- dependencies
|
||||||
- libnvidia-container
|
- libnvidia-container
|
||||||
|
|
||||||
|
# The release branch(es):
|
||||||
|
- package-ecosystem: "gomod"
|
||||||
|
target-branch: release-1.17
|
||||||
|
directories:
|
||||||
|
- "/"
|
||||||
|
# We don't update development or test dependencies on release branches
|
||||||
|
# - "deployments/devel"
|
||||||
|
# - "tests"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "sunday"
|
||||||
|
labels:
|
||||||
|
- dependencies
|
||||||
|
- maintenance
|
||||||
|
ignore:
|
||||||
|
# For release branches we only consider patch updates.
|
||||||
|
- dependency-name: "*"
|
||||||
|
update-types:
|
||||||
|
- version-update:semver-major
|
||||||
|
- version-update:semver-minor
|
||||||
|
groups:
|
||||||
|
k8sio:
|
||||||
|
patterns:
|
||||||
|
- k8s.io/*
|
||||||
|
exclude-patterns:
|
||||||
|
- k8s.io/klog/*
|
||||||
|
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
target-branch: release-1.17
|
||||||
|
directories:
|
||||||
|
# CUDA image
|
||||||
|
- "/deployments/container"
|
||||||
|
# Golang version
|
||||||
|
- "/deployments/devel"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "sunday"
|
||||||
|
ignore:
|
||||||
|
# For release branches we only apply patch updates to the golang version.
|
||||||
|
- dependency-name: "*golang*"
|
||||||
|
update-types:
|
||||||
|
- version-update:semver-major
|
||||||
|
- version-update:semver-minor
|
||||||
|
labels:
|
||||||
|
- dependencies
|
||||||
|
- maintenance
|
||||||
|
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
target-branch: release-1.17
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "sunday"
|
||||||
|
labels:
|
||||||
|
- dependencies
|
||||||
|
- maintenance
|
||||||
|
|
||||||
|
# Github actions need to be gh-pages branches.
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
target-branch: gh-pages
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
labels:
|
||||||
|
- dependencies
|
||||||
|
|||||||
53
.github/workflows/ci.yaml
vendored
Normal file
53
.github/workflows/ci.yaml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Copyright 2025 NVIDIA CORPORATION
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
name: CI Pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "pull-request/[0-9]+"
|
||||||
|
- main
|
||||||
|
- release-*
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
code-scanning:
|
||||||
|
uses: ./.github/workflows/code_scanning.yaml
|
||||||
|
|
||||||
|
variables:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.version.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- name: Generate Commit Short SHA
|
||||||
|
id: version
|
||||||
|
run: echo "version=$(echo $GITHUB_SHA | cut -c1-8)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
golang:
|
||||||
|
uses: ./.github/workflows/golang.yaml
|
||||||
|
|
||||||
|
image:
|
||||||
|
uses: ./.github/workflows/image.yaml
|
||||||
|
needs: [variables, golang, code-scanning]
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
version: ${{ needs.variables.outputs.version }}
|
||||||
|
build_multi_arch_images: ${{ github.ref_name == 'main' || startsWith(github.ref_name, 'release-') }}
|
||||||
|
|
||||||
|
e2e-test:
|
||||||
|
needs: [image, variables]
|
||||||
|
secrets: inherit
|
||||||
|
uses: ./.github/workflows/e2e.yaml
|
||||||
|
with:
|
||||||
|
version: ${{ needs.variables.outputs.version }}
|
||||||
5
.github/workflows/code_scanning.yaml
vendored
5
.github/workflows/code_scanning.yaml
vendored
@@ -15,6 +15,7 @@
|
|||||||
name: "CodeQL"
|
name: "CodeQL"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_call: {}
|
||||||
pull_request:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
@@ -22,10 +23,6 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- release-*
|
- release-*
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- release-*
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
|
|||||||
98
.github/workflows/e2e.yaml
vendored
Normal file
98
.github/workflows/e2e.yaml
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# Copyright 2025 NVIDIA CORPORATION
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
name: End-to-end Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
secrets:
|
||||||
|
AWS_ACCESS_KEY_ID:
|
||||||
|
required: true
|
||||||
|
AWS_SECRET_ACCESS_KEY:
|
||||||
|
required: true
|
||||||
|
AWS_SSH_KEY:
|
||||||
|
required: true
|
||||||
|
E2E_SSH_USER:
|
||||||
|
required: true
|
||||||
|
SLACK_BOT_TOKEN:
|
||||||
|
required: true
|
||||||
|
SLACK_CHANNEL_ID:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
e2e-tests:
|
||||||
|
runs-on: linux-amd64-cpu4
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Calculate build vars
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
echo "COMMIT_SHORT_SHA=${GITHUB_SHA:0:8}" >> $GITHUB_ENV
|
||||||
|
echo "LOWERCASE_REPO_OWNER=$(echo "${GITHUB_REPOSITORY_OWNER}" | awk '{print tolower($0)}')" >> $GITHUB_ENV
|
||||||
|
GOLANG_VERSION=$(./hack/golang-version.sh)
|
||||||
|
echo "GOLANG_VERSION=${GOLANG_VERSION##GOLANG_VERSION := }" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GOLANG_VERSION }}
|
||||||
|
|
||||||
|
- name: Set up Holodeck
|
||||||
|
uses: NVIDIA/holodeck@v0.2.6
|
||||||
|
with:
|
||||||
|
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
aws_ssh_key: ${{ secrets.AWS_SSH_KEY }}
|
||||||
|
holodeck_config: "tests/e2e/infra/aws.yaml"
|
||||||
|
|
||||||
|
- name: Get public dns name
|
||||||
|
id: holodeck_public_dns_name
|
||||||
|
uses: mikefarah/yq@master
|
||||||
|
with:
|
||||||
|
cmd: yq '.status.properties[] | select(.name == "public-dns-name") | .value' /github/workspace/.cache/holodeck.yaml
|
||||||
|
|
||||||
|
- name: Run e2e tests
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: ghcr.io/nvidia/container-toolkit
|
||||||
|
VERSION: ${{ inputs.version }}
|
||||||
|
SSH_KEY: ${{ secrets.AWS_SSH_KEY }}
|
||||||
|
E2E_SSH_USER: ${{ secrets.E2E_SSH_USER }}
|
||||||
|
E2E_SSH_HOST: ${{ steps.holodeck_public_dns_name.outputs.result }}
|
||||||
|
E2E_INSTALL_CTK: "true"
|
||||||
|
run: |
|
||||||
|
e2e_ssh_key=$(mktemp)
|
||||||
|
echo "$SSH_KEY" > "$e2e_ssh_key"
|
||||||
|
chmod 600 "$e2e_ssh_key"
|
||||||
|
export E2E_SSH_KEY="$e2e_ssh_key"
|
||||||
|
|
||||||
|
make -f tests/e2e/Makefile test
|
||||||
|
|
||||||
|
- name: Send Slack alert notification
|
||||||
|
if: ${{ failure() }}
|
||||||
|
uses: slackapi/slack-github-action@v2.0.0
|
||||||
|
with:
|
||||||
|
method: chat.postMessage
|
||||||
|
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||||
|
payload: |
|
||||||
|
channel: ${{ secrets.SLACK_CHANNEL_ID }}
|
||||||
|
text: |
|
||||||
|
:x: On repository ${{ github.repository }}, the Workflow *${{ github.workflow }}* has failed.
|
||||||
|
|
||||||
|
Details: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
5
.github/workflows/golang.yaml
vendored
5
.github/workflows/golang.yaml
vendored
@@ -15,6 +15,7 @@
|
|||||||
name: Golang
|
name: Golang
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_call: {}
|
||||||
pull_request:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
@@ -22,10 +23,6 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- release-*
|
- release-*
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- release-*
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check:
|
check:
|
||||||
|
|||||||
68
.github/workflows/image.yaml
vendored
68
.github/workflows/image.yaml
vendored
@@ -16,21 +16,18 @@
|
|||||||
name: image
|
name: image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
types:
|
inputs:
|
||||||
- opened
|
version:
|
||||||
- synchronize
|
required: true
|
||||||
branches:
|
type: string
|
||||||
- main
|
build_multi_arch_images:
|
||||||
- release-*
|
required: true
|
||||||
push:
|
type: string
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- release-*
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
packages:
|
packages:
|
||||||
runs-on: ubuntu-latest
|
runs-on: linux-amd64-cpu4
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
target:
|
target:
|
||||||
@@ -41,7 +38,7 @@ jobs:
|
|||||||
- centos7-x86_64
|
- centos7-x86_64
|
||||||
- centos8-ppc64le
|
- centos8-ppc64le
|
||||||
ispr:
|
ispr:
|
||||||
- ${{github.event_name == 'pull_request'}}
|
- ${{ github.ref_name != 'main' && !startsWith( github.ref_name, 'release-' ) }}
|
||||||
exclude:
|
exclude:
|
||||||
- ispr: true
|
- ispr: true
|
||||||
target: ubuntu18.04-arm64
|
target: ubuntu18.04-arm64
|
||||||
@@ -52,18 +49,25 @@ jobs:
|
|||||||
- ispr: true
|
- ispr: true
|
||||||
target: centos8-ppc64le
|
target: centos8-ppc64le
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
name: Check out code
|
name: Check out code
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
with:
|
||||||
|
image: tonistiigi/binfmt:master
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: build ${{ matrix.target }} packages
|
- name: build ${{ matrix.target }} packages
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install -y coreutils build-essential sed git bash make
|
sudo apt-get install -y coreutils build-essential sed git bash make
|
||||||
echo "Building packages"
|
echo "Building packages"
|
||||||
./scripts/build-packages.sh ${{ matrix.target }}
|
./scripts/build-packages.sh ${{ matrix.target }}
|
||||||
|
|
||||||
- name: 'Upload Artifacts'
|
- name: 'Upload Artifacts'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
@@ -72,7 +76,7 @@ jobs:
|
|||||||
path: ${{ github.workspace }}/dist/*
|
path: ${{ github.workspace }}/dist/*
|
||||||
|
|
||||||
image:
|
image:
|
||||||
runs-on: ubuntu-latest
|
runs-on: linux-amd64-cpu4
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
dist:
|
dist:
|
||||||
@@ -80,7 +84,7 @@ jobs:
|
|||||||
- ubi8
|
- ubi8
|
||||||
- packaging
|
- packaging
|
||||||
ispr:
|
ispr:
|
||||||
- ${{github.event_name == 'pull_request'}}
|
- ${{ github.ref_name != 'main' && !startsWith( github.ref_name, 'release-' ) }}
|
||||||
exclude:
|
exclude:
|
||||||
- ispr: true
|
- ispr: true
|
||||||
dist: ubi8
|
dist: ubi8
|
||||||
@@ -88,34 +92,15 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
name: Check out code
|
name: Check out code
|
||||||
- name: Calculate build vars
|
|
||||||
id: vars
|
|
||||||
run: |
|
|
||||||
echo "COMMIT_SHORT_SHA=${GITHUB_SHA:0:8}" >> $GITHUB_ENV
|
|
||||||
echo "LOWERCASE_REPO_OWNER=$(echo "${GITHUB_REPOSITORY_OWNER}" | awk '{print tolower($0)}')" >> $GITHUB_ENV
|
|
||||||
REPO_FULL_NAME="${{ github.event.pull_request.head.repo.full_name }}"
|
|
||||||
echo "${REPO_FULL_NAME}"
|
|
||||||
echo "LABEL_IMAGE_SOURCE=https://github.com/${REPO_FULL_NAME}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
PUSH_ON_BUILD="false"
|
|
||||||
BUILD_MULTI_ARCH_IMAGES="false"
|
|
||||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
|
||||||
if [[ "${{ github.actor }}" != "dependabot[bot]" && "${{ github.event.pull_request.head.repo.full_name }}" == "${{ github.repository }}" ]]; then
|
|
||||||
# For non-fork PRs that are not created by dependabot we do push images
|
|
||||||
PUSH_ON_BUILD="true"
|
|
||||||
fi
|
|
||||||
elif [[ "${{ github.event_name }}" == "push" ]]; then
|
|
||||||
# On push events we do generate images and enable muilti-arch builds
|
|
||||||
PUSH_ON_BUILD="true"
|
|
||||||
BUILD_MULTI_ARCH_IMAGES="true"
|
|
||||||
fi
|
|
||||||
echo "PUSH_ON_BUILD=${PUSH_ON_BUILD}" >> $GITHUB_ENV
|
|
||||||
echo "BUILD_MULTI_ARCH_IMAGES=${BUILD_MULTI_ARCH_IMAGES}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
with:
|
||||||
|
image: tonistiigi/binfmt:master
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Get built packages
|
- name: Get built packages
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
@@ -129,10 +114,13 @@ jobs:
|
|||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build image
|
- name: Build image
|
||||||
env:
|
env:
|
||||||
IMAGE_NAME: ghcr.io/${LOWERCASE_REPO_OWNER}/container-toolkit
|
IMAGE_NAME: ghcr.io/nvidia/container-toolkit
|
||||||
VERSION: ${COMMIT_SHORT_SHA}
|
VERSION: ${{ inputs.version }}
|
||||||
|
PUSH_ON_BUILD: "true"
|
||||||
|
BUILD_MULTI_ARCH_IMAGES: ${{ inputs.build_multi_arch_images }}
|
||||||
run: |
|
run: |
|
||||||
echo "${VERSION}"
|
echo "${VERSION}"
|
||||||
make -f deployments/container/Makefile build-${{ matrix.dist }}
|
make -f deployments/container/Makefile build-${{ matrix.dist }}
|
||||||
|
|||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,13 +1,13 @@
|
|||||||
dist
|
/dist
|
||||||
artifacts
|
/artifacts
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
/coverage.out*
|
/coverage.out*
|
||||||
/test/output/
|
/tests/output/
|
||||||
/nvidia-container-runtime
|
/nvidia-container-runtime
|
||||||
/nvidia-container-runtime.*
|
/nvidia-container-runtime.*
|
||||||
/nvidia-container-runtime-hook
|
/nvidia-container-runtime-hook
|
||||||
/nvidia-container-toolkit
|
/nvidia-container-toolkit
|
||||||
/nvidia-ctk
|
/nvidia-ctk
|
||||||
/shared-*
|
/shared-*
|
||||||
/release-*
|
/release-*
|
||||||
|
|||||||
@@ -176,12 +176,6 @@ image-packaging:
|
|||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
# Define publish test helpers
|
# Define publish test helpers
|
||||||
.test:toolkit:
|
|
||||||
extends:
|
|
||||||
- .integration
|
|
||||||
variables:
|
|
||||||
TEST_CASES: "toolkit"
|
|
||||||
|
|
||||||
.test:docker:
|
.test:docker:
|
||||||
extends:
|
extends:
|
||||||
- .integration
|
- .integration
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,5 +1,35 @@
|
|||||||
# NVIDIA Container Toolkit Changelog
|
# NVIDIA Container Toolkit Changelog
|
||||||
|
|
||||||
|
## v1.17.4
|
||||||
|
- Disable mounting of compat libs from container by default
|
||||||
|
- Add allow-cuda-compat-libs-from-container feature flag
|
||||||
|
- Skip graphics modifier in CSV mode
|
||||||
|
- Properly pass configSearchPaths to a Driver constructor
|
||||||
|
- Add support for containerd version 3 config
|
||||||
|
- Add string TOML source
|
||||||
|
|
||||||
|
### Changes in libnvidia-container
|
||||||
|
- Add no-cntlibs CLI option to nvidia-container-cli
|
||||||
|
|
||||||
|
### Changes in the Toolkit Container
|
||||||
|
- Bump CUDA base image version to 12.6.3
|
||||||
|
|
||||||
|
## v1.17.3
|
||||||
|
- Only allow host-relative LDConfig paths by default.
|
||||||
|
### Changes in libnvidia-container
|
||||||
|
- Create virtual copy of host ldconfig binary before calling fexecve()
|
||||||
|
|
||||||
|
## v1.17.2
|
||||||
|
- Fixed a bug where legacy images would set imex channels as `all`.
|
||||||
|
|
||||||
|
## v1.17.1
|
||||||
|
- Fixed a bug where specific symlinks existing in a container image could cause a container to fail to start.
|
||||||
|
- Fixed a bug on Tegra-based systems where a container would fail to start.
|
||||||
|
- Fixed a bug where the default container runtime config path was not properly set.
|
||||||
|
|
||||||
|
### Changes in the Toolkit Container
|
||||||
|
- Fallback to using a config file if the current runtime config can not be determined from the command line.
|
||||||
|
|
||||||
## v1.17.0
|
## v1.17.0
|
||||||
- Promote v1.17.0-rc.2 to v1.17.0
|
- Promote v1.17.0-rc.2 to v1.17.0
|
||||||
- Fix bug when using just-in-time CDI spec generation
|
- Fix bug when using just-in-time CDI spec generation
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ environment variables.
|
|||||||
|
|
||||||
## Testing packages locally
|
## Testing packages locally
|
||||||
|
|
||||||
The [test/release](./test/release/) folder contains documentation on how the installation of local or staged packages can be tested.
|
The [tests/release](./tests/release/) folder contains documentation on how the installation of local or staged packages can be tested.
|
||||||
|
|
||||||
|
|
||||||
## Releasing
|
## Releasing
|
||||||
|
|||||||
29
Makefile
29
Makefile
@@ -90,13 +90,32 @@ goimports:
|
|||||||
lint:
|
lint:
|
||||||
golangci-lint run ./...
|
golangci-lint run ./...
|
||||||
|
|
||||||
vendor:
|
vendor: | mod-tidy mod-vendor mod-verify
|
||||||
go mod tidy
|
|
||||||
go mod vendor
|
mod-tidy:
|
||||||
go mod verify
|
@for mod in $$(find . -name go.mod -not -path "./testdata/*" -not -path "./third_party/*"); do \
|
||||||
|
echo "Tidying $$mod..."; ( \
|
||||||
|
cd $$(dirname $$mod) && go mod tidy \
|
||||||
|
) || exit 1; \
|
||||||
|
done
|
||||||
|
|
||||||
|
mod-vendor:
|
||||||
|
@for mod in $$(find . -name go.mod -not -path "./testdata/*" -not -path "./third_party/*" -not -path "./deployments/*"); do \
|
||||||
|
echo "Vendoring $$mod..."; ( \
|
||||||
|
cd $$(dirname $$mod) && go mod vendor \
|
||||||
|
) || exit 1; \
|
||||||
|
done
|
||||||
|
|
||||||
|
mod-verify:
|
||||||
|
@for mod in $$(find . -name go.mod -not -path "./testdata/*" -not -path "./third_party/*"); do \
|
||||||
|
echo "Verifying $$mod..."; ( \
|
||||||
|
cd $$(dirname $$mod) && go mod verify | sed 's/^/ /g' \
|
||||||
|
) || exit 1; \
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
check-vendor: vendor
|
check-vendor: vendor
|
||||||
git diff --quiet HEAD -- go.mod go.sum vendor
|
git diff --exit-code HEAD -- go.mod go.sum vendor
|
||||||
|
|
||||||
licenses:
|
licenses:
|
||||||
go-licenses csv $(MODULE)/...
|
go-licenses csv $(MODULE)/...
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/chmod"
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/chmod"
|
||||||
symlinks "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/create-symlinks"
|
symlinks "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/create-symlinks"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/cudacompat"
|
||||||
ldcache "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/update-ldcache"
|
ldcache "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-cdi-hook/update-ldcache"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
)
|
)
|
||||||
@@ -32,5 +33,6 @@ func New(logger logger.Interface) []*cli.Command {
|
|||||||
ldcache.NewCommand(logger),
|
ldcache.NewCommand(logger),
|
||||||
symlinks.NewCommand(logger),
|
symlinks.NewCommand(logger),
|
||||||
chmod.NewCommand(logger),
|
chmod.NewCommand(logger),
|
||||||
|
cudacompat.NewCommand(logger),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
76
cmd/nvidia-cdi-hook/cudacompat/container-root.go
Normal file
76
cmd/nvidia-cdi-hook/cudacompat/container-root.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
# Copyright (c) 2025, 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 cudacompat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/moby/sys/symlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A containerRoot represents the root filesystem of a container.
|
||||||
|
type containerRoot string
|
||||||
|
|
||||||
|
// hasPath checks whether the specified path exists in the root.
|
||||||
|
func (r containerRoot) hasPath(path string) bool {
|
||||||
|
resolved, err := r.resolve(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(resolved); err != nil && os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// globFiles matches the specified pattern in the root.
|
||||||
|
// The files that match must be regular files.
|
||||||
|
func (r containerRoot) globFiles(pattern string) ([]string, error) {
|
||||||
|
patternPath, err := r.resolve(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
matches, err := filepath.Glob(patternPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var files []string
|
||||||
|
for _, match := range matches {
|
||||||
|
info, err := os.Lstat(match)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Ignore symlinks.
|
||||||
|
if info.Mode()&os.ModeSymlink != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Ignore directories.
|
||||||
|
if info.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
files = append(files, match)
|
||||||
|
}
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve returns the absolute path including root path.
|
||||||
|
// Symlinks are resolved, but are guaranteed to resolve in the root.
|
||||||
|
func (r containerRoot) resolve(path string) (string, error) {
|
||||||
|
absolute := filepath.Clean(filepath.Join(string(r), path))
|
||||||
|
return symlink.FollowSymlinkInScope(absolute, string(r))
|
||||||
|
}
|
||||||
221
cmd/nvidia-cdi-hook/cudacompat/cudacompat.go
Normal file
221
cmd/nvidia-cdi-hook/cudacompat/cudacompat.go
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/**
|
||||||
|
# Copyright (c) 2025, 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 cudacompat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cudaCompatPath = "/usr/local/cuda/compat"
|
||||||
|
// cudaCompatLdsoconfdFilenamePattern specifies the pattern for the filename
|
||||||
|
// in ld.so.conf.d that includes a reference to the CUDA compat path.
|
||||||
|
// The 00-compat prefix is chosen to ensure that these libraries have a
|
||||||
|
// higher precedence than other libraries on the system.
|
||||||
|
cudaCompatLdsoconfdFilenamePattern = "00-compat-*.conf"
|
||||||
|
)
|
||||||
|
|
||||||
|
type command struct {
|
||||||
|
logger logger.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
hostDriverVersion string
|
||||||
|
containerSpec string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCommand constructs a cuda-compat command with the specified logger
|
||||||
|
func NewCommand(logger logger.Interface) *cli.Command {
|
||||||
|
c := command{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
return c.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the enable-cuda-compat command
|
||||||
|
func (m command) build() *cli.Command {
|
||||||
|
cfg := options{}
|
||||||
|
|
||||||
|
// Create the 'enable-cuda-compat' command
|
||||||
|
c := cli.Command{
|
||||||
|
Name: "enable-cuda-compat",
|
||||||
|
Usage: "This hook ensures that the folder containing the CUDA compat libraries is added to the ldconfig search path if required.",
|
||||||
|
Before: func(c *cli.Context) error {
|
||||||
|
return m.validateFlags(c, &cfg)
|
||||||
|
},
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
return m.run(c, &cfg)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Flags = []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "host-driver-version",
|
||||||
|
Usage: "Specify the host driver version. If the CUDA compat libraries detected in the container do not have a higher MAJOR version, the hook is a no-op.",
|
||||||
|
Destination: &cfg.hostDriverVersion,
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "container-spec",
|
||||||
|
Hidden: true,
|
||||||
|
Category: "testing-only",
|
||||||
|
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 (m command) validateFlags(_ *cli.Context, cfg *options) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m command) run(_ *cli.Context, cfg *options) error {
|
||||||
|
if cfg.hostDriverVersion == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := oci.LoadContainerState(cfg.containerSpec)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to load container state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerRootDir, err := s.GetContainerRoot()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to determined container root: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerForwardCompatDir, err := m.getContainerForwardCompatDir(containerRoot(containerRootDir), cfg.hostDriverVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get container forward compat directory: %w", err)
|
||||||
|
}
|
||||||
|
if containerForwardCompatDir == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.createLdsoconfdFile(containerRoot(containerRootDir), cudaCompatLdsoconfdFilenamePattern, containerForwardCompatDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m command) getContainerForwardCompatDir(containerRoot containerRoot, hostDriverVersion string) (string, error) {
|
||||||
|
if hostDriverVersion == "" {
|
||||||
|
m.logger.Debugf("Host driver version not specified")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if !containerRoot.hasPath(cudaCompatPath) {
|
||||||
|
m.logger.Debugf("No CUDA forward compatibility libraries directory in container")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if !containerRoot.hasPath("/etc/ld.so.cache") {
|
||||||
|
m.logger.Debugf("The container does not have an LDCache")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
libs, err := containerRoot.globFiles(filepath.Join(cudaCompatPath, "libcuda.so.*.*"))
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Warningf("Failed to find CUDA compat library: %w", err)
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(libs) == 0 {
|
||||||
|
m.logger.Debugf("No CUDA forward compatibility libraries container")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(libs) != 1 {
|
||||||
|
m.logger.Warningf("Unexpected number of CUDA compat libraries in container: %v", libs)
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
compatDriverVersion := strings.TrimPrefix(filepath.Base(libs[0]), "libcuda.so.")
|
||||||
|
compatMajor, err := extractMajorVersion(compatDriverVersion)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to extract major version from %q: %v", compatDriverVersion, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
driverMajor, err := extractMajorVersion(hostDriverVersion)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to extract major version from %q: %v", hostDriverVersion, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if driverMajor >= compatMajor {
|
||||||
|
m.logger.Debugf("Compat major version is not greater than the host driver major version (%v >= %v)", hostDriverVersion, compatDriverVersion)
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedCompatDir := strings.TrimPrefix(filepath.Dir(libs[0]), string(containerRoot))
|
||||||
|
return resolvedCompatDir, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createLdsoconfdFile creates a file at /etc/ld.so.conf.d/ in the specified root.
|
||||||
|
// The file is created at /etc/ld.so.conf.d/{{ .pattern }} using `CreateTemp` and
|
||||||
|
// contains the specified directories on each line.
|
||||||
|
func (m command) createLdsoconfdFile(in containerRoot, pattern string, dirs ...string) error {
|
||||||
|
if len(dirs) == 0 {
|
||||||
|
m.logger.Debugf("No directories to add to /etc/ld.so.conf")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ldsoconfdDir, err := in.resolve("/etc/ld.so.conf.d")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(ldsoconfdDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create ld.so.conf.d: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configFile, err := os.CreateTemp(ldsoconfdDir, pattern)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create config file: %w", err)
|
||||||
|
}
|
||||||
|
defer configFile.Close()
|
||||||
|
|
||||||
|
m.logger.Debugf("Adding directories %v to %v", dirs, configFile.Name())
|
||||||
|
|
||||||
|
added := make(map[string]bool)
|
||||||
|
for _, dir := range dirs {
|
||||||
|
if added[dir] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = configFile.WriteString(fmt.Sprintf("%s\n", dir))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to update config file: %w", err)
|
||||||
|
}
|
||||||
|
added[dir] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The created file needs to be world readable for the cases where the container is run as a non-root user.
|
||||||
|
if err := configFile.Chmod(0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to chmod config file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractMajorVersion parses a version string and returns the major version as an int.
|
||||||
|
func extractMajorVersion(version string) (int, error) {
|
||||||
|
majorString := strings.SplitN(version, ".", 2)[0]
|
||||||
|
return strconv.Atoi(majorString)
|
||||||
|
}
|
||||||
182
cmd/nvidia-cdi-hook/cudacompat/cudacompat_test.go
Normal file
182
cmd/nvidia-cdi-hook/cudacompat/cudacompat_test.go
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
# Copyright (c) 2025, 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 cudacompat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCompatLibs(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
contents map[string]string
|
||||||
|
hostDriverVersion string
|
||||||
|
expectedContainerForwardCompatDir string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "empty root",
|
||||||
|
hostDriverVersion: "222.55.66",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "compat lib is newer; no ldcache",
|
||||||
|
contents: map[string]string{
|
||||||
|
"/usr/local/cuda/compat/libcuda.so.333.88.99": "",
|
||||||
|
},
|
||||||
|
hostDriverVersion: "222.55.66",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "compat lib is newer; ldcache",
|
||||||
|
contents: map[string]string{
|
||||||
|
"/etc/ld.so.cache": "",
|
||||||
|
"/usr/local/cuda/compat/libcuda.so.333.88.99": "",
|
||||||
|
},
|
||||||
|
hostDriverVersion: "222.55.66",
|
||||||
|
expectedContainerForwardCompatDir: "/usr/local/cuda/compat",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "compat lib is older; ldcache",
|
||||||
|
contents: map[string]string{
|
||||||
|
"/etc/ld.so.cache": "",
|
||||||
|
"/usr/local/cuda/compat/libcuda.so.111.88.99": "",
|
||||||
|
},
|
||||||
|
hostDriverVersion: "222.55.66",
|
||||||
|
expectedContainerForwardCompatDir: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "compat lib has same major version; ldcache",
|
||||||
|
contents: map[string]string{
|
||||||
|
"/etc/ld.so.cache": "",
|
||||||
|
"/usr/local/cuda/compat/libcuda.so.222.88.99": "",
|
||||||
|
},
|
||||||
|
hostDriverVersion: "222.55.66",
|
||||||
|
expectedContainerForwardCompatDir: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "numeric comparison is used; ldcache",
|
||||||
|
contents: map[string]string{
|
||||||
|
"/etc/ld.so.cache": "",
|
||||||
|
"/usr/local/cuda/compat/libcuda.so.222.88.99": "",
|
||||||
|
},
|
||||||
|
hostDriverVersion: "99.55.66",
|
||||||
|
expectedContainerForwardCompatDir: "/usr/local/cuda/compat",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "driver version empty; ldcache",
|
||||||
|
contents: map[string]string{
|
||||||
|
"/etc/ld.so.cache": "",
|
||||||
|
"/usr/local/cuda/compat/libcuda.so.222.88.99": "",
|
||||||
|
},
|
||||||
|
hostDriverVersion: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "symlinks are followed",
|
||||||
|
contents: map[string]string{
|
||||||
|
"/etc/ld.so.cache": "",
|
||||||
|
"/etc/alternatives/cuda/compat/libcuda.so.333.88.99": "",
|
||||||
|
"/usr/local/cuda": "symlink=/etc/alternatives/cuda",
|
||||||
|
},
|
||||||
|
hostDriverVersion: "222.55.66",
|
||||||
|
expectedContainerForwardCompatDir: "/etc/alternatives/cuda/compat",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "symlinks stay in container",
|
||||||
|
contents: map[string]string{
|
||||||
|
"/etc/ld.so.cache": "",
|
||||||
|
"/compat/libcuda.so.333.88.99": "",
|
||||||
|
"/usr/local/cuda": "symlink=../../../../../../",
|
||||||
|
},
|
||||||
|
hostDriverVersion: "222.55.66",
|
||||||
|
expectedContainerForwardCompatDir: "/compat",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
containerRootDir := t.TempDir()
|
||||||
|
for name, contents := range tc.contents {
|
||||||
|
target := filepath.Join(containerRootDir, name)
|
||||||
|
require.NoError(t, os.MkdirAll(filepath.Dir(target), 0755))
|
||||||
|
|
||||||
|
if strings.HasPrefix(contents, "symlink=") {
|
||||||
|
require.NoError(t, os.Symlink(strings.TrimPrefix(contents, "symlink="), target))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, os.WriteFile(target, []byte(contents), 0600))
|
||||||
|
}
|
||||||
|
|
||||||
|
c := command{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
containerForwardCompatDir, err := c.getContainerForwardCompatDir(containerRoot(containerRootDir), tc.hostDriverVersion)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, tc.expectedContainerForwardCompatDir, containerForwardCompatDir)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateLdconfig(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
folders []string
|
||||||
|
expectedContents string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "no folders; have no contents",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "single folder is added",
|
||||||
|
folders: []string{"/usr/local/cuda/compat"},
|
||||||
|
expectedContents: "/usr/local/cuda/compat\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
containerRootDir := t.TempDir()
|
||||||
|
c := command{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
err := c.createLdsoconfdFile(containerRoot(containerRootDir), cudaCompatLdsoconfdFilenamePattern, tc.folders...)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
matches, err := filepath.Glob(filepath.Join(containerRootDir, "/etc/ld.so.conf.d/00-compat-*.conf"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
if tc.expectedContents == "" {
|
||||||
|
require.Empty(t, matches)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Len(t, matches, 1)
|
||||||
|
contents, err := os.ReadFile(matches[0])
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.EqualValues(t, tc.expectedContents, string(contents))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
46
cmd/nvidia-cdi-hook/update-ldcache/container-root.go
Normal file
46
cmd/nvidia-cdi-hook/update-ldcache/container-root.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
# Copyright (c) 2025, 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 ldcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/moby/sys/symlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A containerRoot represents the root filesystem of a container.
|
||||||
|
type containerRoot string
|
||||||
|
|
||||||
|
// hasPath checks whether the specified path exists in the root.
|
||||||
|
func (r containerRoot) hasPath(path string) bool {
|
||||||
|
resolved, err := r.resolve(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(resolved); err != nil && os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve returns the absolute path including root path.
|
||||||
|
// Symlinks are resolved, but are guaranteed to resolve in the root.
|
||||||
|
func (r containerRoot) resolve(path string) (string, error) {
|
||||||
|
absolute := filepath.Clean(filepath.Join(string(r), path))
|
||||||
|
return symlink.FollowSymlinkInScope(absolute, string(r))
|
||||||
|
}
|
||||||
57
cmd/nvidia-cdi-hook/update-ldcache/safe-exec_linux.go
Normal file
57
cmd/nvidia-cdi-hook/update-ldcache/safe-exec_linux.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
# Copyright (c) 2025, 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 ldcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/opencontainers/runc/libcontainer/dmz"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SafeExec attempts to clone the specified binary (as an memfd, for example) before executing it.
|
||||||
|
func (m command) SafeExec(path string, args []string, envv []string) error {
|
||||||
|
safeExe, err := cloneBinary(path)
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Warningf("Failed to clone binary %q: %v; falling back to Exec", path, err)
|
||||||
|
//nolint:gosec // TODO: Can we harden this so that there is less risk of command injection
|
||||||
|
return syscall.Exec(path, args, envv)
|
||||||
|
}
|
||||||
|
defer safeExe.Close()
|
||||||
|
|
||||||
|
exePath := "/proc/self/fd/" + strconv.Itoa(int(safeExe.Fd()))
|
||||||
|
//nolint:gosec // TODO: Can we harden this so that there is less risk of command injection
|
||||||
|
return syscall.Exec(exePath, args, envv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneBinary(path string) (*os.File, error) {
|
||||||
|
exe, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("opening current binary: %w", err)
|
||||||
|
}
|
||||||
|
defer exe.Close()
|
||||||
|
|
||||||
|
stat, err := exe.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("checking %v size: %w", path, err)
|
||||||
|
}
|
||||||
|
size := stat.Size()
|
||||||
|
|
||||||
|
return dmz.CloneBinary(exe, size, path, os.TempDir())
|
||||||
|
}
|
||||||
29
cmd/nvidia-cdi-hook/update-ldcache/safe-exec_other.go
Normal file
29
cmd/nvidia-cdi-hook/update-ldcache/safe-exec_other.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//go:build !linux
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
|
/**
|
||||||
|
# Copyright (c) 2025, 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 ldcache
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
// SafeExec is not implemented on non-linux systems and forwards directly to the
|
||||||
|
// Exec syscall.
|
||||||
|
func (m *command) SafeExec(path string, args []string, envv []string) error {
|
||||||
|
//nolint:gosec // TODO: Can we harden this so that there is less risk of command injection
|
||||||
|
return syscall.Exec(path, args, envv)
|
||||||
|
}
|
||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
@@ -31,6 +30,15 @@ import (
|
|||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ldsoconfdFilenamePattern specifies the pattern for the filename
|
||||||
|
// in ld.so.conf.d that includes references to the specified directories.
|
||||||
|
// The 00-nvcr prefix is chosen to ensure that these libraries have a
|
||||||
|
// higher precedence than other libraries on the system, but lower than
|
||||||
|
// the 00-cuda-compat that is included in some containers.
|
||||||
|
ldsoconfdFilenamePattern = "00-nvcr-*.conf"
|
||||||
|
)
|
||||||
|
|
||||||
type command struct {
|
type command struct {
|
||||||
logger logger.Interface
|
logger logger.Interface
|
||||||
}
|
}
|
||||||
@@ -100,18 +108,20 @@ func (m command) run(c *cli.Context, cfg *options) error {
|
|||||||
return fmt.Errorf("failed to load container state: %v", err)
|
return fmt.Errorf("failed to load container state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
containerRoot, err := s.GetContainerRoot()
|
containerRootDir, err := s.GetContainerRoot()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to determined container root: %v", err)
|
return fmt.Errorf("failed to determined container root: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ldconfigPath := m.resolveLDConfigPath(cfg.ldconfigPath)
|
ldconfigPath := m.resolveLDConfigPath(cfg.ldconfigPath)
|
||||||
args := []string{filepath.Base(ldconfigPath)}
|
args := []string{filepath.Base(ldconfigPath)}
|
||||||
if containerRoot != "" {
|
if containerRootDir != "" {
|
||||||
args = append(args, "-r", containerRoot)
|
args = append(args, "-r", containerRootDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
if root(containerRoot).hasPath("/etc/ld.so.cache") {
|
containerRoot := containerRoot(containerRootDir)
|
||||||
|
|
||||||
|
if containerRoot.hasPath("/etc/ld.so.cache") {
|
||||||
args = append(args, "-C", "/etc/ld.so.cache")
|
args = append(args, "-C", "/etc/ld.so.cache")
|
||||||
} else {
|
} else {
|
||||||
m.logger.Debugf("No ld.so.cache found, skipping update")
|
m.logger.Debugf("No ld.so.cache found, skipping update")
|
||||||
@@ -119,8 +129,8 @@ func (m command) run(c *cli.Context, cfg *options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
folders := cfg.folders.Value()
|
folders := cfg.folders.Value()
|
||||||
if root(containerRoot).hasPath("/etc/ld.so.conf.d") {
|
if containerRoot.hasPath("/etc/ld.so.conf.d") {
|
||||||
err := m.createConfig(containerRoot, folders)
|
err := m.createLdsoconfdFile(containerRoot, ldsoconfdFilenamePattern, folders...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to update ld.so.conf.d: %v", err)
|
return fmt.Errorf("failed to update ld.so.conf.d: %v", err)
|
||||||
}
|
}
|
||||||
@@ -132,18 +142,7 @@ func (m command) run(c *cli.Context, cfg *options) error {
|
|||||||
// be configured to use a different config file by default.
|
// be configured to use a different config file by default.
|
||||||
args = append(args, "-f", "/etc/ld.so.conf")
|
args = append(args, "-f", "/etc/ld.so.conf")
|
||||||
|
|
||||||
//nolint:gosec // TODO: Can we harden this so that there is less risk of command injection
|
return m.SafeExec(ldconfigPath, args, nil)
|
||||||
return syscall.Exec(ldconfigPath, args, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
type root string
|
|
||||||
|
|
||||||
func (r root) hasPath(path string) bool {
|
|
||||||
_, err := os.Stat(filepath.Join(string(r), path))
|
|
||||||
if err != nil && os.IsNotExist(err) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveLDConfigPath determines the LDConfig path to use for the system.
|
// resolveLDConfigPath determines the LDConfig path to use for the system.
|
||||||
@@ -153,44 +152,46 @@ func (m command) resolveLDConfigPath(path string) string {
|
|||||||
return strings.TrimPrefix(config.NormalizeLDConfigPath("@"+path), "@")
|
return strings.TrimPrefix(config.NormalizeLDConfigPath("@"+path), "@")
|
||||||
}
|
}
|
||||||
|
|
||||||
// createConfig creates (or updates) /etc/ld.so.conf.d/00-nvcr-<RANDOM_STRING>.conf in the container
|
// createLdsoconfdFile creates a file at /etc/ld.so.conf.d/ in the specified root.
|
||||||
// to include the required paths.
|
// The file is created at /etc/ld.so.conf.d/{{ .pattern }} using `CreateTemp` and
|
||||||
// Note that the 00-nvcr prefix is chosen to ensure that these libraries have
|
// contains the specified directories on each line.
|
||||||
// a higher precedence than other libraries on the system but are applied AFTER
|
func (m command) createLdsoconfdFile(in containerRoot, pattern string, dirs ...string) error {
|
||||||
// 00-cuda-compat.conf.
|
if len(dirs) == 0 {
|
||||||
func (m command) createConfig(root string, folders []string) error {
|
m.logger.Debugf("No directories to add to /etc/ld.so.conf")
|
||||||
if len(folders) == 0 {
|
|
||||||
m.logger.Debugf("No folders to add to /etc/ld.so.conf")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(filepath.Join(root, "/etc/ld.so.conf.d"), 0755); err != nil {
|
ldsoconfdDir, err := in.resolve("/etc/ld.so.conf.d")
|
||||||
return fmt.Errorf("failed to create ld.so.conf.d: %v", err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(ldsoconfdDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create ld.so.conf.d: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
configFile, err := os.CreateTemp(filepath.Join(root, "/etc/ld.so.conf.d"), "00-nvcr-*.conf")
|
configFile, err := os.CreateTemp(ldsoconfdDir, pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create config file: %v", err)
|
return fmt.Errorf("failed to create config file: %w", err)
|
||||||
}
|
}
|
||||||
defer configFile.Close()
|
defer configFile.Close()
|
||||||
|
|
||||||
m.logger.Debugf("Adding folders %v to %v", folders, configFile.Name())
|
m.logger.Debugf("Adding directories %v to %v", dirs, configFile.Name())
|
||||||
|
|
||||||
configured := make(map[string]bool)
|
added := make(map[string]bool)
|
||||||
for _, folder := range folders {
|
for _, dir := range dirs {
|
||||||
if configured[folder] {
|
if added[dir] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, err = configFile.WriteString(fmt.Sprintf("%s\n", folder))
|
_, err = configFile.WriteString(fmt.Sprintf("%s\n", dir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to update ld.so.conf.d: %v", err)
|
return fmt.Errorf("failed to update config file: %w", err)
|
||||||
}
|
}
|
||||||
configured[folder] = true
|
added[dir] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// The created file needs to be world readable for the cases where the container is run as a non-root user.
|
// The created file needs to be world readable for the cases where the container is run as a non-root user.
|
||||||
if err := os.Chmod(configFile.Name(), 0644); err != nil {
|
if err := configFile.Chmod(0644); err != nil {
|
||||||
return fmt.Errorf("failed to chmod config file: %v", err)
|
return fmt.Errorf("failed to chmod config file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ func getDevicesFromEnvvar(containerImage image.CUDA, swarmResourceEnvvars []stri
|
|||||||
return containerImage.VisibleDevicesFromEnvVar()
|
return containerImage.VisibleDevicesFromEnvVar()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDevices(hookConfig *HookConfig, image image.CUDA, privileged bool) []string {
|
func (hookConfig *hookConfig) getDevices(image image.CUDA, privileged bool) []string {
|
||||||
// If enabled, try and get the device list from volume mounts first
|
// If enabled, try and get the device list from volume mounts first
|
||||||
if hookConfig.AcceptDeviceListAsVolumeMounts {
|
if hookConfig.AcceptDeviceListAsVolumeMounts {
|
||||||
devices := image.VisibleDevicesFromMounts()
|
devices := image.VisibleDevicesFromMounts()
|
||||||
@@ -197,7 +197,11 @@ func getMigDevices(image image.CUDA, envvar string) *string {
|
|||||||
return &devices
|
return &devices
|
||||||
}
|
}
|
||||||
|
|
||||||
func getImexChannels(hookConfig *HookConfig, image image.CUDA, privileged bool) []string {
|
func (hookConfig *hookConfig) getImexChannels(image image.CUDA, privileged bool) []string {
|
||||||
|
if hookConfig.Features.IgnoreImexChannelRequests.IsEnabled() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// If enabled, try and get the device list from volume mounts first
|
// If enabled, try and get the device list from volume mounts first
|
||||||
if hookConfig.AcceptDeviceListAsVolumeMounts {
|
if hookConfig.AcceptDeviceListAsVolumeMounts {
|
||||||
devices := image.ImexChannelsFromMounts()
|
devices := image.ImexChannelsFromMounts()
|
||||||
@@ -217,10 +221,10 @@ func getImexChannels(hookConfig *HookConfig, image image.CUDA, privileged bool)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HookConfig) getDriverCapabilities(cudaImage image.CUDA, legacyImage bool) image.DriverCapabilities {
|
func (hookConfig *hookConfig) getDriverCapabilities(cudaImage image.CUDA, legacyImage bool) image.DriverCapabilities {
|
||||||
// We use the default driver capabilities by default. This is filtered to only include the
|
// We use the default driver capabilities by default. This is filtered to only include the
|
||||||
// supported capabilities
|
// supported capabilities
|
||||||
supportedDriverCapabilities := image.NewDriverCapabilities(c.SupportedDriverCapabilities)
|
supportedDriverCapabilities := image.NewDriverCapabilities(hookConfig.SupportedDriverCapabilities)
|
||||||
|
|
||||||
capabilities := supportedDriverCapabilities.Intersection(image.DefaultDriverCapabilities)
|
capabilities := supportedDriverCapabilities.Intersection(image.DefaultDriverCapabilities)
|
||||||
|
|
||||||
@@ -244,10 +248,10 @@ func (c *HookConfig) getDriverCapabilities(cudaImage image.CUDA, legacyImage boo
|
|||||||
return capabilities
|
return capabilities
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNvidiaConfig(hookConfig *HookConfig, image image.CUDA, privileged bool) *nvidiaConfig {
|
func (hookConfig *hookConfig) getNvidiaConfig(image image.CUDA, privileged bool) *nvidiaConfig {
|
||||||
legacyImage := image.IsLegacy()
|
legacyImage := image.IsLegacy()
|
||||||
|
|
||||||
devices := getDevices(hookConfig, image, privileged)
|
devices := hookConfig.getDevices(image, privileged)
|
||||||
if len(devices) == 0 {
|
if len(devices) == 0 {
|
||||||
// empty devices means this is not a GPU container.
|
// empty devices means this is not a GPU container.
|
||||||
return nil
|
return nil
|
||||||
@@ -269,7 +273,7 @@ func getNvidiaConfig(hookConfig *HookConfig, image image.CUDA, privileged bool)
|
|||||||
log.Panicln("cannot set MIG_MONITOR_DEVICES in non privileged container")
|
log.Panicln("cannot set MIG_MONITOR_DEVICES in non privileged container")
|
||||||
}
|
}
|
||||||
|
|
||||||
imexChannels := getImexChannels(hookConfig, image, privileged)
|
imexChannels := hookConfig.getImexChannels(image, privileged)
|
||||||
|
|
||||||
driverCapabilities := hookConfig.getDriverCapabilities(image, legacyImage).String()
|
driverCapabilities := hookConfig.getDriverCapabilities(image, legacyImage).String()
|
||||||
|
|
||||||
@@ -288,7 +292,7 @@ func getNvidiaConfig(hookConfig *HookConfig, image image.CUDA, privileged bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainerConfig(hook HookConfig) (config containerConfig) {
|
func (hookConfig *hookConfig) getContainerConfig() (config containerConfig) {
|
||||||
var h HookState
|
var h HookState
|
||||||
d := json.NewDecoder(os.Stdin)
|
d := json.NewDecoder(os.Stdin)
|
||||||
if err := d.Decode(&h); err != nil {
|
if err := d.Decode(&h); err != nil {
|
||||||
@@ -305,7 +309,7 @@ func getContainerConfig(hook HookConfig) (config containerConfig) {
|
|||||||
image, err := image.New(
|
image, err := image.New(
|
||||||
image.WithEnv(s.Process.Env),
|
image.WithEnv(s.Process.Env),
|
||||||
image.WithMounts(s.Mounts),
|
image.WithMounts(s.Mounts),
|
||||||
image.WithDisableRequire(hook.DisableRequire),
|
image.WithDisableRequire(hookConfig.DisableRequire),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
@@ -316,6 +320,6 @@ func getContainerConfig(hook HookConfig) (config containerConfig) {
|
|||||||
Pid: h.Pid,
|
Pid: h.Pid,
|
||||||
Rootfs: s.Root.Path,
|
Rootfs: s.Root.Path,
|
||||||
Image: image,
|
Image: image,
|
||||||
Nvidia: getNvidiaConfig(&hook, image, privileged),
|
Nvidia: hookConfig.getNvidiaConfig(image, privileged),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/opencontainers/runtime-spec/specs-go"
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@ func TestGetNvidiaConfig(t *testing.T) {
|
|||||||
description string
|
description string
|
||||||
env map[string]string
|
env map[string]string
|
||||||
privileged bool
|
privileged bool
|
||||||
hookConfig *HookConfig
|
hookConfig *hookConfig
|
||||||
expectedConfig *nvidiaConfig
|
expectedConfig *nvidiaConfig
|
||||||
expectedPanic bool
|
expectedPanic bool
|
||||||
}{
|
}{
|
||||||
@@ -394,8 +395,10 @@ func TestGetNvidiaConfig(t *testing.T) {
|
|||||||
image.EnvVarNvidiaDriverCapabilities: "all",
|
image.EnvVarNvidiaDriverCapabilities: "all",
|
||||||
},
|
},
|
||||||
privileged: true,
|
privileged: true,
|
||||||
hookConfig: &HookConfig{
|
hookConfig: &hookConfig{
|
||||||
SupportedDriverCapabilities: "video,display",
|
Config: &config.Config{
|
||||||
|
SupportedDriverCapabilities: "video,display",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expectedConfig: &nvidiaConfig{
|
expectedConfig: &nvidiaConfig{
|
||||||
Devices: []string{"all"},
|
Devices: []string{"all"},
|
||||||
@@ -409,8 +412,10 @@ func TestGetNvidiaConfig(t *testing.T) {
|
|||||||
image.EnvVarNvidiaDriverCapabilities: "video,display",
|
image.EnvVarNvidiaDriverCapabilities: "video,display",
|
||||||
},
|
},
|
||||||
privileged: true,
|
privileged: true,
|
||||||
hookConfig: &HookConfig{
|
hookConfig: &hookConfig{
|
||||||
SupportedDriverCapabilities: "video,display,compute,utility",
|
Config: &config.Config{
|
||||||
|
SupportedDriverCapabilities: "video,display,compute,utility",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expectedConfig: &nvidiaConfig{
|
expectedConfig: &nvidiaConfig{
|
||||||
Devices: []string{"all"},
|
Devices: []string{"all"},
|
||||||
@@ -423,8 +428,10 @@ func TestGetNvidiaConfig(t *testing.T) {
|
|||||||
image.EnvVarNvidiaVisibleDevices: "all",
|
image.EnvVarNvidiaVisibleDevices: "all",
|
||||||
},
|
},
|
||||||
privileged: true,
|
privileged: true,
|
||||||
hookConfig: &HookConfig{
|
hookConfig: &hookConfig{
|
||||||
SupportedDriverCapabilities: "video,display,utility,compute",
|
Config: &config.Config{
|
||||||
|
SupportedDriverCapabilities: "video,display,utility,compute",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expectedConfig: &nvidiaConfig{
|
expectedConfig: &nvidiaConfig{
|
||||||
Devices: []string{"all"},
|
Devices: []string{"all"},
|
||||||
@@ -438,9 +445,11 @@ func TestGetNvidiaConfig(t *testing.T) {
|
|||||||
"DOCKER_SWARM_RESOURCE": "GPU1,GPU2",
|
"DOCKER_SWARM_RESOURCE": "GPU1,GPU2",
|
||||||
},
|
},
|
||||||
privileged: true,
|
privileged: true,
|
||||||
hookConfig: &HookConfig{
|
hookConfig: &hookConfig{
|
||||||
SwarmResource: "DOCKER_SWARM_RESOURCE",
|
Config: &config.Config{
|
||||||
SupportedDriverCapabilities: "video,display,utility,compute",
|
SwarmResource: "DOCKER_SWARM_RESOURCE",
|
||||||
|
SupportedDriverCapabilities: "video,display,utility,compute",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expectedConfig: &nvidiaConfig{
|
expectedConfig: &nvidiaConfig{
|
||||||
Devices: []string{"GPU1", "GPU2"},
|
Devices: []string{"GPU1", "GPU2"},
|
||||||
@@ -454,9 +463,11 @@ func TestGetNvidiaConfig(t *testing.T) {
|
|||||||
"DOCKER_SWARM_RESOURCE": "GPU1,GPU2",
|
"DOCKER_SWARM_RESOURCE": "GPU1,GPU2",
|
||||||
},
|
},
|
||||||
privileged: true,
|
privileged: true,
|
||||||
hookConfig: &HookConfig{
|
hookConfig: &hookConfig{
|
||||||
SwarmResource: "NOT_DOCKER_SWARM_RESOURCE,DOCKER_SWARM_RESOURCE",
|
Config: &config.Config{
|
||||||
SupportedDriverCapabilities: "video,display,utility,compute",
|
SwarmResource: "NOT_DOCKER_SWARM_RESOURCE,DOCKER_SWARM_RESOURCE",
|
||||||
|
SupportedDriverCapabilities: "video,display,utility,compute",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expectedConfig: &nvidiaConfig{
|
expectedConfig: &nvidiaConfig{
|
||||||
Devices: []string{"GPU1", "GPU2"},
|
Devices: []string{"GPU1", "GPU2"},
|
||||||
@@ -470,14 +481,14 @@ func TestGetNvidiaConfig(t *testing.T) {
|
|||||||
image.WithEnvMap(tc.env),
|
image.WithEnvMap(tc.env),
|
||||||
)
|
)
|
||||||
// Wrap the call to getNvidiaConfig() in a closure.
|
// Wrap the call to getNvidiaConfig() in a closure.
|
||||||
var config *nvidiaConfig
|
var cfg *nvidiaConfig
|
||||||
getConfig := func() {
|
getConfig := func() {
|
||||||
hookConfig := tc.hookConfig
|
hookCfg := tc.hookConfig
|
||||||
if hookConfig == nil {
|
if hookCfg == nil {
|
||||||
defaultConfig, _ := getDefaultHookConfig()
|
defaultConfig, _ := config.GetDefault()
|
||||||
hookConfig = &defaultConfig
|
hookCfg = &hookConfig{defaultConfig}
|
||||||
}
|
}
|
||||||
config = getNvidiaConfig(hookConfig, image, tc.privileged)
|
cfg = hookCfg.getNvidiaConfig(image, tc.privileged)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For any tests that are expected to panic, make sure they do.
|
// For any tests that are expected to panic, make sure they do.
|
||||||
@@ -491,18 +502,18 @@ func TestGetNvidiaConfig(t *testing.T) {
|
|||||||
|
|
||||||
// And start comparing the test results to the expected results.
|
// And start comparing the test results to the expected results.
|
||||||
if tc.expectedConfig == nil {
|
if tc.expectedConfig == nil {
|
||||||
require.Nil(t, config, tc.description)
|
require.Nil(t, cfg, tc.description)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NotNil(t, config, tc.description)
|
require.NotNil(t, cfg, tc.description)
|
||||||
|
|
||||||
require.Equal(t, tc.expectedConfig.Devices, config.Devices)
|
require.Equal(t, tc.expectedConfig.Devices, cfg.Devices)
|
||||||
require.Equal(t, tc.expectedConfig.MigConfigDevices, config.MigConfigDevices)
|
require.Equal(t, tc.expectedConfig.MigConfigDevices, cfg.MigConfigDevices)
|
||||||
require.Equal(t, tc.expectedConfig.MigMonitorDevices, config.MigMonitorDevices)
|
require.Equal(t, tc.expectedConfig.MigMonitorDevices, cfg.MigMonitorDevices)
|
||||||
require.Equal(t, tc.expectedConfig.DriverCapabilities, config.DriverCapabilities)
|
require.Equal(t, tc.expectedConfig.DriverCapabilities, cfg.DriverCapabilities)
|
||||||
|
|
||||||
require.ElementsMatch(t, tc.expectedConfig.Requirements, config.Requirements)
|
require.ElementsMatch(t, tc.expectedConfig.Requirements, cfg.Requirements)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -612,10 +623,11 @@ func TestDeviceListSourcePriority(t *testing.T) {
|
|||||||
),
|
),
|
||||||
image.WithMounts(tc.mountDevices),
|
image.WithMounts(tc.mountDevices),
|
||||||
)
|
)
|
||||||
hookConfig, _ := getDefaultHookConfig()
|
defaultConfig, _ := config.GetDefault()
|
||||||
hookConfig.AcceptEnvvarUnprivileged = tc.acceptUnprivileged
|
cfg := &hookConfig{defaultConfig}
|
||||||
hookConfig.AcceptDeviceListAsVolumeMounts = tc.acceptMounts
|
cfg.AcceptEnvvarUnprivileged = tc.acceptUnprivileged
|
||||||
devices = getDevices(&hookConfig, image, tc.privileged)
|
cfg.AcceptDeviceListAsVolumeMounts = tc.acceptMounts
|
||||||
|
devices = cfg.getDevices(image, tc.privileged)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all other tests, just grab the devices and check the results
|
// For all other tests, just grab the devices and check the results
|
||||||
@@ -940,8 +952,10 @@ func TestGetDriverCapabilities(t *testing.T) {
|
|||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
var capabilities string
|
var capabilities string
|
||||||
|
|
||||||
c := HookConfig{
|
c := hookConfig{
|
||||||
SupportedDriverCapabilities: tc.supportedCapabilities,
|
Config: &config.Config{
|
||||||
|
SupportedDriverCapabilities: tc.supportedCapabilities,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
image, _ := image.New(
|
image, _ := image.New(
|
||||||
|
|||||||
@@ -17,16 +17,10 @@ const (
|
|||||||
driverPath = "/run/nvidia/driver"
|
driverPath = "/run/nvidia/driver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HookConfig : options for the nvidia-container-runtime-hook.
|
// hookConfig wraps the toolkit config.
|
||||||
type HookConfig config.Config
|
// This allows for functions to be defined on the local type.
|
||||||
|
type hookConfig struct {
|
||||||
func getDefaultHookConfig() (HookConfig, error) {
|
*config.Config
|
||||||
defaultCfg, err := config.GetDefault()
|
|
||||||
if err != nil {
|
|
||||||
return HookConfig{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return *(*HookConfig)(defaultCfg), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadConfig loads the required paths for the hook config.
|
// loadConfig loads the required paths for the hook config.
|
||||||
@@ -56,12 +50,12 @@ func loadConfig() (*config.Config, error) {
|
|||||||
return config.GetDefault()
|
return config.GetDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHookConfig() (*HookConfig, error) {
|
func getHookConfig() (*hookConfig, error) {
|
||||||
cfg, err := loadConfig()
|
cfg, err := loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to load config: %v", err)
|
return nil, fmt.Errorf("failed to load config: %v", err)
|
||||||
}
|
}
|
||||||
config := (*HookConfig)(cfg)
|
config := &hookConfig{cfg}
|
||||||
|
|
||||||
allSupportedDriverCapabilities := image.SupportedDriverCapabilities
|
allSupportedDriverCapabilities := image.SupportedDriverCapabilities
|
||||||
if config.SupportedDriverCapabilities == "all" {
|
if config.SupportedDriverCapabilities == "all" {
|
||||||
@@ -79,7 +73,7 @@ func getHookConfig() (*HookConfig, error) {
|
|||||||
|
|
||||||
// getConfigOption returns the toml config option associated with the
|
// getConfigOption returns the toml config option associated with the
|
||||||
// specified struct field.
|
// specified struct field.
|
||||||
func (c HookConfig) getConfigOption(fieldName string) string {
|
func (c hookConfig) getConfigOption(fieldName string) string {
|
||||||
t := reflect.TypeOf(c)
|
t := reflect.TypeOf(c)
|
||||||
f, ok := t.FieldByName(fieldName)
|
f, ok := t.FieldByName(fieldName)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -93,7 +87,7 @@ func (c HookConfig) getConfigOption(fieldName string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getSwarmResourceEnvvars returns the swarm resource envvars for the config.
|
// getSwarmResourceEnvvars returns the swarm resource envvars for the config.
|
||||||
func (c *HookConfig) getSwarmResourceEnvvars() []string {
|
func (c *hookConfig) getSwarmResourceEnvvars() []string {
|
||||||
if c.SwarmResource == "" {
|
if c.SwarmResource == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,10 +90,10 @@ func TestGetHookConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var config HookConfig
|
var cfg hookConfig
|
||||||
getHookConfig := func() {
|
getHookConfig := func() {
|
||||||
c, _ := getHookConfig()
|
c, _ := getHookConfig()
|
||||||
config = *c
|
cfg = *c
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc.expectedPanic {
|
if tc.expectedPanic {
|
||||||
@@ -102,7 +103,7 @@ func TestGetHookConfig(t *testing.T) {
|
|||||||
|
|
||||||
getHookConfig()
|
getHookConfig()
|
||||||
|
|
||||||
require.EqualValues(t, tc.expectedDriverCapabilities, config.SupportedDriverCapabilities)
|
require.EqualValues(t, tc.expectedDriverCapabilities, cfg.SupportedDriverCapabilities)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,8 +145,10 @@ func TestGetSwarmResourceEnvvars(t *testing.T) {
|
|||||||
|
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||||
c := &HookConfig{
|
c := &hookConfig{
|
||||||
SwarmResource: tc.value,
|
Config: &config.Config{
|
||||||
|
SwarmResource: tc.value,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
envvars := c.getSwarmResourceEnvvars()
|
envvars := c.getSwarmResourceEnvvars()
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ func doPrestart() {
|
|||||||
}
|
}
|
||||||
cli := hook.NVIDIAContainerCLIConfig
|
cli := hook.NVIDIAContainerCLIConfig
|
||||||
|
|
||||||
container := getContainerConfig(*hook)
|
container := hook.getContainerConfig()
|
||||||
nvidia := container.Nvidia
|
nvidia := container.Nvidia
|
||||||
if nvidia == nil {
|
if nvidia == nil {
|
||||||
// Not a GPU container, nothing to do.
|
// Not a GPU container, nothing to do.
|
||||||
@@ -114,6 +114,9 @@ func doPrestart() {
|
|||||||
}
|
}
|
||||||
args = append(args, "configure")
|
args = append(args, "configure")
|
||||||
|
|
||||||
|
if !hook.Features.AllowCUDACompatLibsFromContainer.IsEnabled() {
|
||||||
|
args = append(args, "--no-cntlibs")
|
||||||
|
}
|
||||||
if ldconfigPath := cli.NormalizeLDConfigPath(); ldconfigPath != "" {
|
if ldconfigPath := cli.NormalizeLDConfigPath(); ldconfigPath != "" {
|
||||||
args = append(args, fmt.Sprintf("--ldconfig=%s", ldconfigPath))
|
args = append(args, fmt.Sprintf("--ldconfig=%s", ldconfigPath))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import (
|
|||||||
const (
|
const (
|
||||||
nvidiaRuntime = "nvidia-container-runtime"
|
nvidiaRuntime = "nvidia-container-runtime"
|
||||||
nvidiaHook = "nvidia-container-runtime-hook"
|
nvidiaHook = "nvidia-container-runtime-hook"
|
||||||
bundlePathSuffix = "test/output/bundle/"
|
bundlePathSuffix = "tests/output/bundle/"
|
||||||
specFile = "config.json"
|
specFile = "config.json"
|
||||||
unmodifiedSpecFileSuffix = "test/input/test_spec.json"
|
unmodifiedSpecFileSuffix = "tests/input/test_spec.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -46,8 +46,8 @@ func TestMain(m *testing.M) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error in test setup: could not get module root: %v", err)
|
log.Fatalf("error in test setup: could not get module root: %v", err)
|
||||||
}
|
}
|
||||||
testBinPath := filepath.Join(moduleRoot, "test", "bin")
|
testBinPath := filepath.Join(moduleRoot, "tests", "bin")
|
||||||
testInputPath := filepath.Join(moduleRoot, "test", "input")
|
testInputPath := filepath.Join(moduleRoot, "tests", "input")
|
||||||
|
|
||||||
// Set the environment variables for the test
|
// Set the environment variables for the test
|
||||||
os.Setenv("PATH", test.PrependToPath(testBinPath, moduleRoot))
|
os.Setenv("PATH", test.PrependToPath(testBinPath, moduleRoot))
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container/operator"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container/operator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -36,8 +36,10 @@ const (
|
|||||||
|
|
||||||
// Options defines the shared options for the CLIs to configure containers runtimes.
|
// Options defines the shared options for the CLIs to configure containers runtimes.
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Config string
|
Config string
|
||||||
Socket string
|
Socket string
|
||||||
|
// EnabledCDI indicates whether CDI should be enabled.
|
||||||
|
EnableCDI bool
|
||||||
RuntimeName string
|
RuntimeName string
|
||||||
RuntimeDir string
|
RuntimeDir string
|
||||||
SetAsDefault bool
|
SetAsDefault bool
|
||||||
@@ -111,6 +113,10 @@ func (o Options) UpdateConfig(cfg engine.Interface) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.EnableCDI {
|
||||||
|
cfg.EnableCDI()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,9 +23,9 @@ import (
|
|||||||
testlog "github.com/sirupsen/logrus/hooks/test"
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/containerd"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/containerd"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUpdateV1ConfigDefaultRuntime(t *testing.T) {
|
func TestUpdateV1ConfigDefaultRuntime(t *testing.T) {
|
||||||
@@ -88,37 +88,36 @@ func TestUpdateV1ConfigDefaultRuntime(t *testing.T) {
|
|||||||
SetAsDefault: tc.setAsDefault,
|
SetAsDefault: tc.setAsDefault,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := toml.Empty.Load()
|
v1, err := containerd.New(
|
||||||
require.NoError(t, err, "%d: %v", i, tc)
|
containerd.WithLogger(logger),
|
||||||
|
containerd.WithConfigSource(toml.Empty),
|
||||||
v1 := &containerd.ConfigV1{
|
containerd.WithRuntimeType(runtimeType),
|
||||||
Logger: logger,
|
containerd.WithUseLegacyConfig(tc.legacyConfig),
|
||||||
Tree: cfg,
|
containerd.WithConfigVersion(1),
|
||||||
UseDefaultRuntimeName: !tc.legacyConfig,
|
)
|
||||||
RuntimeType: runtimeType,
|
require.NoError(t, err)
|
||||||
}
|
|
||||||
|
|
||||||
err = o.UpdateConfig(v1)
|
err = o.UpdateConfig(v1)
|
||||||
require.NoError(t, err, "%d: %v", i, tc)
|
require.NoError(t, err)
|
||||||
|
|
||||||
defaultRuntimeName := v1.GetPath([]string{"plugins", "cri", "containerd", "default_runtime_name"})
|
cfg := v1.(*containerd.ConfigV1)
|
||||||
require.EqualValues(t, tc.expectedDefaultRuntimeName, defaultRuntimeName, "%d: %v", i, tc)
|
defaultRuntimeName := cfg.GetPath([]string{"plugins", "cri", "containerd", "default_runtime_name"})
|
||||||
|
require.EqualValues(t, tc.expectedDefaultRuntimeName, defaultRuntimeName)
|
||||||
|
|
||||||
defaultRuntime := v1.GetPath([]string{"plugins", "cri", "containerd", "default_runtime"})
|
defaultRuntime := cfg.GetPath([]string{"plugins", "cri", "containerd", "default_runtime"})
|
||||||
if tc.expectedDefaultRuntimeBinary == nil {
|
if tc.expectedDefaultRuntimeBinary == nil {
|
||||||
require.Nil(t, defaultRuntime, "%d: %v", i, tc)
|
require.Nil(t, defaultRuntime)
|
||||||
} else {
|
} else {
|
||||||
require.NotNil(t, defaultRuntime)
|
require.NotNil(t, defaultRuntime)
|
||||||
|
|
||||||
expected, err := defaultRuntimeTomlConfigV1(tc.expectedDefaultRuntimeBinary.(string))
|
expected, err := defaultRuntimeTomlConfigV1(tc.expectedDefaultRuntimeBinary.(string))
|
||||||
require.NoError(t, err, "%d: %v", i, tc)
|
require.NoError(t, err)
|
||||||
|
|
||||||
configContents, _ := toml.Marshal(defaultRuntime.(*toml.Tree))
|
configContents, _ := toml.Marshal(defaultRuntime.(*toml.Tree))
|
||||||
expectedContents, _ := toml.Marshal(expected)
|
expectedContents, _ := toml.Marshal(expected)
|
||||||
|
|
||||||
require.Equal(t, string(expectedContents), string(configContents), "%d: %v: %v", i, tc)
|
require.Equal(t, string(expectedContents), string(configContents), "%d: %v: %v", i, tc)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,24 +233,22 @@ func TestUpdateV1Config(t *testing.T) {
|
|||||||
RuntimeDir: runtimeDir,
|
RuntimeDir: runtimeDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := toml.Empty.Load()
|
v1, err := containerd.New(
|
||||||
|
containerd.WithLogger(logger),
|
||||||
|
containerd.WithConfigSource(toml.Empty),
|
||||||
|
containerd.WithRuntimeType(runtimeType),
|
||||||
|
containerd.WithConfigVersion(1),
|
||||||
|
containerd.WithContainerAnnotations("cdi.k8s.io/*"),
|
||||||
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
v1 := &containerd.ConfigV1{
|
|
||||||
Logger: logger,
|
|
||||||
Tree: cfg,
|
|
||||||
UseDefaultRuntimeName: true,
|
|
||||||
RuntimeType: runtimeType,
|
|
||||||
ContainerAnnotations: []string{"cdi.k8s.io/*"},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = o.UpdateConfig(v1)
|
err = o.UpdateConfig(v1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expected, err := toml.TreeFromMap(tc.expectedConfig)
|
expected, err := toml.TreeFromMap(tc.expectedConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, expected.String(), cfg.String())
|
require.Equal(t, expected.String(), v1.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,29 +390,73 @@ func TestUpdateV1ConfigWithRuncPresent(t *testing.T) {
|
|||||||
RuntimeDir: runtimeDir,
|
RuntimeDir: runtimeDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := toml.TreeFromMap(runcConfigMapV1("/runc-binary"))
|
v1, err := containerd.New(
|
||||||
|
containerd.WithLogger(logger),
|
||||||
|
containerd.WithConfigSource(toml.FromMap(runcConfigMapV1("/runc-binary"))),
|
||||||
|
containerd.WithRuntimeType(runtimeType),
|
||||||
|
containerd.WithConfigVersion(1),
|
||||||
|
containerd.WithContainerAnnotations("cdi.k8s.io/*"),
|
||||||
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
v1 := &containerd.ConfigV1{
|
|
||||||
Logger: logger,
|
|
||||||
Tree: cfg,
|
|
||||||
UseDefaultRuntimeName: true,
|
|
||||||
RuntimeType: runtimeType,
|
|
||||||
ContainerAnnotations: []string{"cdi.k8s.io/*"},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = o.UpdateConfig(v1)
|
err = o.UpdateConfig(v1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expected, err := toml.TreeFromMap(tc.expectedConfig)
|
expected, err := toml.TreeFromMap(tc.expectedConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, expected.String(), cfg.String())
|
require.Equal(t, expected.String(), v1.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateV1EnableCDI(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
const runtimeDir = "/test/runtime/dir"
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
enableCDI bool
|
||||||
|
expectedEnableCDIValue interface{}
|
||||||
|
}{
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
enableCDI: false,
|
||||||
|
expectedEnableCDIValue: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enableCDI: true,
|
||||||
|
expectedEnableCDIValue: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(fmt.Sprintf("%v", tc.enableCDI), func(t *testing.T) {
|
||||||
|
o := &container.Options{
|
||||||
|
EnableCDI: tc.enableCDI,
|
||||||
|
RuntimeName: "nvidia",
|
||||||
|
RuntimeDir: runtimeDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := toml.Empty.Load()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
v1 := &containerd.ConfigV1{
|
||||||
|
Logger: logger,
|
||||||
|
Tree: cfg,
|
||||||
|
RuntimeType: runtimeType,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = o.UpdateConfig(v1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
enableCDIValue := v1.GetPath([]string{"plugins", "cri", "containerd", "enable_cdi"})
|
||||||
|
require.EqualValues(t, tc.expectedEnableCDIValue, enableCDIValue)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRevertV1Config(t *testing.T) {
|
func TestRevertV1Config(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
config map[string]interface {
|
config map[string]interface {
|
||||||
}
|
}
|
||||||
@@ -469,25 +510,22 @@ func TestRevertV1Config(t *testing.T) {
|
|||||||
RuntimeName: "nvidia",
|
RuntimeName: "nvidia",
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := toml.LoadMap(tc.config)
|
|
||||||
require.NoError(t, err, "%d: %v", i, tc)
|
|
||||||
|
|
||||||
expected, err := toml.TreeFromMap(tc.expected)
|
expected, err := toml.TreeFromMap(tc.expected)
|
||||||
require.NoError(t, err, "%d: %v", i, tc)
|
require.NoError(t, err)
|
||||||
|
|
||||||
v1 := &containerd.ConfigV1{
|
v1, err := containerd.New(
|
||||||
Tree: cfg,
|
containerd.WithLogger(logger),
|
||||||
UseDefaultRuntimeName: true,
|
containerd.WithConfigSource(toml.FromMap(tc.config)),
|
||||||
RuntimeType: runtimeType,
|
containerd.WithRuntimeType(runtimeType),
|
||||||
}
|
|
||||||
|
containerd.WithContainerAnnotations("cdi.k8s.io/*"),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = o.RevertConfig(v1)
|
err = o.RevertConfig(v1)
|
||||||
require.NoError(t, err, "%d: %v", i, tc)
|
require.NoError(t, err)
|
||||||
|
|
||||||
configContents, _ := toml.Marshal(cfg)
|
require.Equal(t, expected.String(), v1.String())
|
||||||
expectedContents, _ := toml.Marshal(expected)
|
|
||||||
|
|
||||||
require.Equal(t, string(expectedContents), string(configContents), "%d: %v", i, tc)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,9 +23,9 @@ import (
|
|||||||
testlog "github.com/sirupsen/logrus/hooks/test"
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/containerd"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/containerd"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -72,18 +72,19 @@ func TestUpdateV2ConfigDefaultRuntime(t *testing.T) {
|
|||||||
SetAsDefault: tc.setAsDefault,
|
SetAsDefault: tc.setAsDefault,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := toml.LoadMap(map[string]interface{}{})
|
v2, err := containerd.New(
|
||||||
|
containerd.WithLogger(logger),
|
||||||
|
containerd.WithConfigSource(toml.Empty),
|
||||||
|
containerd.WithRuntimeType(runtimeType),
|
||||||
|
containerd.WithContainerAnnotations("cdi.k8s.io/*"),
|
||||||
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
v2 := &containerd.Config{
|
|
||||||
Logger: logger,
|
|
||||||
Tree: cfg,
|
|
||||||
RuntimeType: runtimeType,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = o.UpdateConfig(v2)
|
err = o.UpdateConfig(v2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cfg := v2.(*containerd.Config)
|
||||||
|
|
||||||
defaultRuntimeName := cfg.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"})
|
defaultRuntimeName := cfg.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"})
|
||||||
require.EqualValues(t, tc.expectedDefaultRuntimeName, defaultRuntimeName)
|
require.EqualValues(t, tc.expectedDefaultRuntimeName, defaultRuntimeName)
|
||||||
})
|
})
|
||||||
@@ -195,23 +196,21 @@ func TestUpdateV2Config(t *testing.T) {
|
|||||||
RuntimeDir: runtimeDir,
|
RuntimeDir: runtimeDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := toml.LoadMap(map[string]interface{}{})
|
v2, err := containerd.New(
|
||||||
|
containerd.WithLogger(logger),
|
||||||
|
containerd.WithConfigSource(toml.Empty),
|
||||||
|
containerd.WithRuntimeType(runtimeType),
|
||||||
|
containerd.WithContainerAnnotations("cdi.k8s.io/*"),
|
||||||
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
v2 := &containerd.Config{
|
|
||||||
Logger: logger,
|
|
||||||
Tree: cfg,
|
|
||||||
RuntimeType: runtimeType,
|
|
||||||
ContainerAnnotations: []string{"cdi.k8s.io/*"},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = o.UpdateConfig(v2)
|
err = o.UpdateConfig(v2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expected, err := toml.TreeFromMap(tc.expectedConfig)
|
expected, err := toml.TreeFromMap(tc.expectedConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, expected.String(), cfg.String())
|
require.Equal(t, expected.String(), v2.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,28 +347,75 @@ func TestUpdateV2ConfigWithRuncPresent(t *testing.T) {
|
|||||||
RuntimeDir: runtimeDir,
|
RuntimeDir: runtimeDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := toml.LoadMap(runcConfigMapV2("/runc-binary"))
|
v2, err := containerd.New(
|
||||||
|
containerd.WithLogger(logger),
|
||||||
|
containerd.WithConfigSource(toml.FromMap(runcConfigMapV2("/runc-binary"))),
|
||||||
|
containerd.WithRuntimeType(runtimeType),
|
||||||
|
containerd.WithContainerAnnotations("cdi.k8s.io/*"),
|
||||||
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
v2 := &containerd.Config{
|
|
||||||
Logger: logger,
|
|
||||||
Tree: cfg,
|
|
||||||
RuntimeType: runtimeType,
|
|
||||||
ContainerAnnotations: []string{"cdi.k8s.io/*"},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = o.UpdateConfig(v2)
|
err = o.UpdateConfig(v2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expected, err := toml.TreeFromMap(tc.expectedConfig)
|
expected, err := toml.TreeFromMap(tc.expectedConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, expected.String(), cfg.String())
|
require.Equal(t, expected.String(), v2.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateV2ConfigEnableCDI(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
const runtimeDir = "/test/runtime/dir"
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
enableCDI bool
|
||||||
|
expectedEnableCDIValue interface{}
|
||||||
|
}{
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
enableCDI: false,
|
||||||
|
expectedEnableCDIValue: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enableCDI: true,
|
||||||
|
expectedEnableCDIValue: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(fmt.Sprintf("%v", tc.enableCDI), func(t *testing.T) {
|
||||||
|
o := &container.Options{
|
||||||
|
EnableCDI: tc.enableCDI,
|
||||||
|
RuntimeName: "nvidia",
|
||||||
|
RuntimeDir: runtimeDir,
|
||||||
|
SetAsDefault: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := toml.LoadMap(map[string]interface{}{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
v2 := &containerd.Config{
|
||||||
|
Logger: logger,
|
||||||
|
Tree: cfg,
|
||||||
|
RuntimeType: runtimeType,
|
||||||
|
CRIRuntimePluginName: "io.containerd.grpc.v1.cri",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = o.UpdateConfig(v2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
enableCDIValue := cfg.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "enable_cdi"})
|
||||||
|
require.EqualValues(t, tc.expectedEnableCDIValue, enableCDIValue)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRevertV2Config(t *testing.T) {
|
func TestRevertV2Config(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
config map[string]interface {
|
config map[string]interface {
|
||||||
}
|
}
|
||||||
@@ -418,24 +464,21 @@ func TestRevertV2Config(t *testing.T) {
|
|||||||
RuntimeName: "nvidia",
|
RuntimeName: "nvidia",
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := toml.LoadMap(tc.config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expected, err := toml.TreeFromMap(tc.expected)
|
expected, err := toml.TreeFromMap(tc.expected)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
v2 := &containerd.Config{
|
v2, err := containerd.New(
|
||||||
Tree: cfg,
|
containerd.WithLogger(logger),
|
||||||
RuntimeType: runtimeType,
|
containerd.WithConfigSource(toml.FromMap(tc.config)),
|
||||||
}
|
containerd.WithRuntimeType(runtimeType),
|
||||||
|
containerd.WithContainerAnnotations("cdi.k8s.io/*"),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = o.RevertConfig(v2)
|
err = o.RevertConfig(v2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
configContents, _ := toml.Marshal(cfg)
|
require.Equal(t, expected.String(), v2.String())
|
||||||
expectedContents, _ := toml.Marshal(expected)
|
|
||||||
|
|
||||||
require.Equal(t, string(expectedContents), string(configContents))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,6 +497,7 @@ func runtimeMapV2(binary string) map[string]interface{} {
|
|||||||
|
|
||||||
func runcConfigMapV2(binary string) map[string]interface{} {
|
func runcConfigMapV2(binary string) map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
|
"version": 2,
|
||||||
"plugins": map[string]interface{}{
|
"plugins": map[string]interface{}{
|
||||||
"io.containerd.grpc.v1.cri": map[string]interface{}{
|
"io.containerd.grpc.v1.cri": map[string]interface{}{
|
||||||
"containerd": map[string]interface{}{
|
"containerd": map[string]interface{}{
|
||||||
@@ -23,9 +23,10 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
cli "github.com/urfave/cli/v2"
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/containerd"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/containerd"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -51,8 +52,11 @@ type Options struct {
|
|||||||
func Flags(opts *Options) []cli.Flag {
|
func Flags(opts *Options) []cli.Flag {
|
||||||
flags := []cli.Flag{
|
flags := []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "use-legacy-config",
|
Name: "use-legacy-config",
|
||||||
Usage: "Specify whether a legacy (pre v1.3) config should be used",
|
Usage: "Specify whether a legacy (pre v1.3) config should be used. " +
|
||||||
|
"This ensures that a version 1 container config is created by default and that the " +
|
||||||
|
"containerd.runtimes.default_runtime config section is used to define the default " +
|
||||||
|
"runtime instead of container.default_runtime_name.",
|
||||||
Destination: &opts.useLegacyConfig,
|
Destination: &opts.useLegacyConfig,
|
||||||
EnvVars: []string{"CONTAINERD_USE_LEGACY_CONFIG"},
|
EnvVars: []string{"CONTAINERD_USE_LEGACY_CONFIG"},
|
||||||
},
|
},
|
||||||
@@ -84,13 +88,7 @@ func Flags(opts *Options) []cli.Flag {
|
|||||||
func Setup(c *cli.Context, o *container.Options, co *Options) error {
|
func Setup(c *cli.Context, o *container.Options, co *Options) error {
|
||||||
log.Infof("Starting 'setup' for %v", c.App.Name)
|
log.Infof("Starting 'setup' for %v", c.App.Name)
|
||||||
|
|
||||||
cfg, err := containerd.New(
|
cfg, err := getRuntimeConfig(o, co)
|
||||||
containerd.WithPath(o.Config),
|
|
||||||
containerd.WithConfigSource(containerd.CommandLineSource(o.HostRootMount)),
|
|
||||||
containerd.WithRuntimeType(co.runtimeType),
|
|
||||||
containerd.WithUseLegacyConfig(co.useLegacyConfig),
|
|
||||||
containerd.WithContainerAnnotations(co.containerAnnotationsFromCDIPrefixes()...),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load config: %v", err)
|
return fmt.Errorf("unable to load config: %v", err)
|
||||||
}
|
}
|
||||||
@@ -114,13 +112,7 @@ func Setup(c *cli.Context, o *container.Options, co *Options) error {
|
|||||||
func Cleanup(c *cli.Context, o *container.Options, co *Options) error {
|
func Cleanup(c *cli.Context, o *container.Options, co *Options) error {
|
||||||
log.Infof("Starting 'cleanup' for %v", c.App.Name)
|
log.Infof("Starting 'cleanup' for %v", c.App.Name)
|
||||||
|
|
||||||
cfg, err := containerd.New(
|
cfg, err := getRuntimeConfig(o, co)
|
||||||
containerd.WithPath(o.Config),
|
|
||||||
containerd.WithConfigSource(containerd.CommandLineSource(o.HostRootMount)),
|
|
||||||
containerd.WithRuntimeType(co.runtimeType),
|
|
||||||
containerd.WithUseLegacyConfig(co.useLegacyConfig),
|
|
||||||
containerd.WithContainerAnnotations(co.containerAnnotationsFromCDIPrefixes()...),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load config: %v", err)
|
return fmt.Errorf("unable to load config: %v", err)
|
||||||
}
|
}
|
||||||
@@ -169,13 +161,24 @@ func (o *Options) runtimeConfigOverride() (map[string]interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetLowlevelRuntimePaths(o *container.Options, co *Options) ([]string, error) {
|
func GetLowlevelRuntimePaths(o *container.Options, co *Options) ([]string, error) {
|
||||||
cfg, err := containerd.New(
|
cfg, err := getRuntimeConfig(o, co)
|
||||||
containerd.WithConfigSource(containerd.CommandLineSource(o.HostRootMount)),
|
|
||||||
containerd.WithRuntimeType(co.runtimeType),
|
|
||||||
containerd.WithUseLegacyConfig(co.useLegacyConfig),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to load containerd config: %w", err)
|
return nil, fmt.Errorf("unable to load containerd config: %w", err)
|
||||||
}
|
}
|
||||||
return engine.GetBinaryPathsForRuntimes(cfg), nil
|
return engine.GetBinaryPathsForRuntimes(cfg), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRuntimeConfig(o *container.Options, co *Options) (engine.Interface, error) {
|
||||||
|
return containerd.New(
|
||||||
|
containerd.WithPath(o.Config),
|
||||||
|
containerd.WithConfigSource(
|
||||||
|
toml.LoadFirst(
|
||||||
|
containerd.CommandLineSource(o.HostRootMount),
|
||||||
|
toml.FromFile(o.Config),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
containerd.WithRuntimeType(co.runtimeType),
|
||||||
|
containerd.WithUseLegacyConfig(co.useLegacyConfig),
|
||||||
|
containerd.WithContainerAnnotations(co.containerAnnotationsFromCDIPrefixes()...),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -24,11 +24,12 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
cli "github.com/urfave/cli/v2"
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/crio"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/crio"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/ocihook"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/ocihook"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -116,10 +117,7 @@ func setupHook(o *container.Options, co *Options) error {
|
|||||||
func setupConfig(o *container.Options) error {
|
func setupConfig(o *container.Options) error {
|
||||||
log.Infof("Updating config file")
|
log.Infof("Updating config file")
|
||||||
|
|
||||||
cfg, err := crio.New(
|
cfg, err := getRuntimeConfig(o)
|
||||||
crio.WithPath(o.Config),
|
|
||||||
crio.WithConfigSource(crio.CommandLineSource(o.HostRootMount)),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load config: %v", err)
|
return fmt.Errorf("unable to load config: %v", err)
|
||||||
}
|
}
|
||||||
@@ -168,10 +166,7 @@ func cleanupHook(co *Options) error {
|
|||||||
func cleanupConfig(o *container.Options) error {
|
func cleanupConfig(o *container.Options) error {
|
||||||
log.Infof("Reverting config file modifications")
|
log.Infof("Reverting config file modifications")
|
||||||
|
|
||||||
cfg, err := crio.New(
|
cfg, err := getRuntimeConfig(o)
|
||||||
crio.WithPath(o.Config),
|
|
||||||
crio.WithConfigSource(crio.CommandLineSource(o.HostRootMount)),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load config: %v", err)
|
return fmt.Errorf("unable to load config: %v", err)
|
||||||
}
|
}
|
||||||
@@ -195,11 +190,21 @@ func RestartCrio(o *container.Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetLowlevelRuntimePaths(o *container.Options) ([]string, error) {
|
func GetLowlevelRuntimePaths(o *container.Options) ([]string, error) {
|
||||||
cfg, err := crio.New(
|
cfg, err := getRuntimeConfig(o)
|
||||||
crio.WithConfigSource(crio.CommandLineSource(o.HostRootMount)),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to load crio config: %w", err)
|
return nil, fmt.Errorf("unable to load crio config: %w", err)
|
||||||
}
|
}
|
||||||
return engine.GetBinaryPathsForRuntimes(cfg), nil
|
return engine.GetBinaryPathsForRuntimes(cfg), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRuntimeConfig(o *container.Options) (engine.Interface, error) {
|
||||||
|
return crio.New(
|
||||||
|
crio.WithPath(o.Config),
|
||||||
|
crio.WithConfigSource(
|
||||||
|
toml.LoadFirst(
|
||||||
|
crio.CommandLineSource(o.HostRootMount),
|
||||||
|
toml.FromFile(o.Config),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -22,9 +22,9 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
cli "github.com/urfave/cli/v2"
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/docker"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/docker"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -45,9 +45,7 @@ func Flags(opts *Options) []cli.Flag {
|
|||||||
func Setup(c *cli.Context, o *container.Options) error {
|
func Setup(c *cli.Context, o *container.Options) error {
|
||||||
log.Infof("Starting 'setup' for %v", c.App.Name)
|
log.Infof("Starting 'setup' for %v", c.App.Name)
|
||||||
|
|
||||||
cfg, err := docker.New(
|
cfg, err := getRuntimeConfig(o)
|
||||||
docker.WithPath(o.Config),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load config: %v", err)
|
return fmt.Errorf("unable to load config: %v", err)
|
||||||
}
|
}
|
||||||
@@ -71,9 +69,7 @@ func Setup(c *cli.Context, o *container.Options) error {
|
|||||||
func Cleanup(c *cli.Context, o *container.Options) error {
|
func Cleanup(c *cli.Context, o *container.Options) error {
|
||||||
log.Infof("Starting 'cleanup' for %v", c.App.Name)
|
log.Infof("Starting 'cleanup' for %v", c.App.Name)
|
||||||
|
|
||||||
cfg, err := docker.New(
|
cfg, err := getRuntimeConfig(o)
|
||||||
docker.WithPath(o.Config),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load config: %v", err)
|
return fmt.Errorf("unable to load config: %v", err)
|
||||||
}
|
}
|
||||||
@@ -107,3 +103,9 @@ func GetLowlevelRuntimePaths(o *container.Options) ([]string, error) {
|
|||||||
}
|
}
|
||||||
return engine.GetBinaryPathsForRuntimes(cfg), nil
|
return engine.GetBinaryPathsForRuntimes(cfg), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRuntimeConfig(o *container.Options) (engine.Interface, error) {
|
||||||
|
return docker.New(
|
||||||
|
docker.WithPath(o.Config),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -22,8 +22,8 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/docker"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/docker"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUpdateConfigDefaultRuntime(t *testing.T) {
|
func TestUpdateConfigDefaultRuntime(t *testing.T) {
|
||||||
@@ -21,10 +21,11 @@ import (
|
|||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container"
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container/runtime/containerd"
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container/runtime/containerd"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container/runtime/crio"
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container/runtime/crio"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container/runtime/docker"
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container/runtime/docker"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container/toolkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -66,6 +67,12 @@ func Flags(opts *Options) []cli.Flag {
|
|||||||
Destination: &opts.RestartMode,
|
Destination: &opts.RestartMode,
|
||||||
EnvVars: []string{"RUNTIME_RESTART_MODE"},
|
EnvVars: []string{"RUNTIME_RESTART_MODE"},
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "enable-cdi-in-runtime",
|
||||||
|
Usage: "Enable CDI in the configured runt ime",
|
||||||
|
Destination: &opts.EnableCDI,
|
||||||
|
EnvVars: []string{"RUNTIME_ENABLE_CDI"},
|
||||||
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "host-root",
|
Name: "host-root",
|
||||||
Usage: "Specify the path to the host root to be used when restarting the runtime using systemd",
|
Usage: "Specify the path to the host root to be used when restarting the runtime using systemd",
|
||||||
@@ -98,10 +105,14 @@ func Flags(opts *Options) []cli.Flag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ValidateOptions checks whether the specified options are valid
|
// ValidateOptions checks whether the specified options are valid
|
||||||
func ValidateOptions(opts *Options, runtime string, toolkitRoot string) error {
|
func ValidateOptions(c *cli.Context, opts *Options, runtime string, toolkitRoot string, to *toolkit.Options) error {
|
||||||
// We set this option here to ensure that it is available in future calls.
|
// We set this option here to ensure that it is available in future calls.
|
||||||
opts.RuntimeDir = toolkitRoot
|
opts.RuntimeDir = toolkitRoot
|
||||||
|
|
||||||
|
if !c.IsSet("enable-cdi-in-runtime") {
|
||||||
|
opts.EnableCDI = to.CDI.Enabled
|
||||||
|
}
|
||||||
|
|
||||||
// Apply the runtime-specific config changes.
|
// Apply the runtime-specific config changes.
|
||||||
switch runtime {
|
switch runtime {
|
||||||
case containerd.Name:
|
case containerd.Name:
|
||||||
@@ -23,8 +23,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type executableTarget struct {
|
type executableTarget struct {
|
||||||
@@ -33,6 +31,7 @@ type executableTarget struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type executable struct {
|
type executable struct {
|
||||||
|
fileInstaller
|
||||||
source string
|
source string
|
||||||
target executableTarget
|
target executableTarget
|
||||||
env map[string]string
|
env map[string]string
|
||||||
@@ -43,21 +42,21 @@ type executable struct {
|
|||||||
// install installs an executable component of the NVIDIA container toolkit. The source executable
|
// install installs an executable component of the NVIDIA container toolkit. The source executable
|
||||||
// is copied to a `.real` file and a wapper is created to set up the environment as required.
|
// is copied to a `.real` file and a wapper is created to set up the environment as required.
|
||||||
func (e executable) install(destFolder string) (string, error) {
|
func (e executable) install(destFolder string) (string, error) {
|
||||||
log.Infof("Installing executable '%v' to %v", e.source, destFolder)
|
e.logger.Infof("Installing executable '%v' to %v", e.source, destFolder)
|
||||||
|
|
||||||
dotfileName := e.dotfileName()
|
dotfileName := e.dotfileName()
|
||||||
|
|
||||||
installedDotfileName, err := installFileToFolderWithName(destFolder, dotfileName, e.source)
|
installedDotfileName, err := e.installFileToFolderWithName(destFolder, dotfileName, e.source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error installing file '%v' as '%v': %v", e.source, dotfileName, err)
|
return "", fmt.Errorf("error installing file '%v' as '%v': %v", e.source, dotfileName, err)
|
||||||
}
|
}
|
||||||
log.Infof("Installed '%v'", installedDotfileName)
|
e.logger.Infof("Installed '%v'", installedDotfileName)
|
||||||
|
|
||||||
wrapperFilename, err := e.installWrapper(destFolder, installedDotfileName)
|
wrapperFilename, err := e.installWrapper(destFolder, installedDotfileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error wrapping '%v': %v", installedDotfileName, err)
|
return "", fmt.Errorf("error wrapping '%v': %v", installedDotfileName, err)
|
||||||
}
|
}
|
||||||
log.Infof("Installed wrapper '%v'", wrapperFilename)
|
e.logger.Infof("Installed wrapper '%v'", wrapperFilename)
|
||||||
|
|
||||||
return wrapperFilename, nil
|
return wrapperFilename, nil
|
||||||
}
|
}
|
||||||
@@ -23,10 +23,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWrapper(t *testing.T) {
|
func TestWrapper(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
|
||||||
const shebang = "#! /bin/sh"
|
const shebang = "#! /bin/sh"
|
||||||
const destFolder = "/dest/folder"
|
const destFolder = "/dest/folder"
|
||||||
const dotfileName = "source.real"
|
const dotfileName = "source.real"
|
||||||
@@ -98,6 +101,8 @@ func TestWrapper(t *testing.T) {
|
|||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
tc.e.logger = logger
|
||||||
|
|
||||||
err := tc.e.writeWrapperTo(buf, destFolder, dotfileName)
|
err := tc.e.writeWrapperTo(buf, destFolder, dotfileName)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -107,6 +112,8 @@ func TestWrapper(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInstallExecutable(t *testing.T) {
|
func TestInstallExecutable(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
|
||||||
inputFolder, err := os.MkdirTemp("", "")
|
inputFolder, err := os.MkdirTemp("", "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer os.RemoveAll(inputFolder)
|
defer os.RemoveAll(inputFolder)
|
||||||
@@ -121,6 +128,9 @@ func TestInstallExecutable(t *testing.T) {
|
|||||||
require.NoError(t, sourceFile.Close())
|
require.NoError(t, sourceFile.Close())
|
||||||
|
|
||||||
e := executable{
|
e := executable{
|
||||||
|
fileInstaller: fileInstaller{
|
||||||
|
logger: logger,
|
||||||
|
},
|
||||||
source: source,
|
source: source,
|
||||||
target: executableTarget{
|
target: executableTarget{
|
||||||
dotfileName: "input.real",
|
dotfileName: "input.real",
|
||||||
95
cmd/nvidia-ctk-installer/container/toolkit/file-installer.go
Normal file
95
cmd/nvidia-ctk-installer/container/toolkit/file-installer.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
# Copyright 2024 NVIDIA CORPORATION
|
||||||
|
#
|
||||||
|
# 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 toolkit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fileInstaller struct {
|
||||||
|
logger logger.Interface
|
||||||
|
// sourceRoot specifies the root that is searched for the components to install.
|
||||||
|
sourceRoot string
|
||||||
|
}
|
||||||
|
|
||||||
|
// installFileToFolder copies a source file to a destination folder.
|
||||||
|
// The path of the input file is ignored.
|
||||||
|
// e.g. installFileToFolder("/some/path/file.txt", "/output/path")
|
||||||
|
// will result in a file "/output/path/file.txt" being generated
|
||||||
|
func (t *fileInstaller) installFileToFolder(destFolder string, src string) (string, error) {
|
||||||
|
name := filepath.Base(src)
|
||||||
|
return t.installFileToFolderWithName(destFolder, name, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cp src destFolder/name
|
||||||
|
func (t *fileInstaller) installFileToFolderWithName(destFolder string, name, src string) (string, error) {
|
||||||
|
dest := filepath.Join(destFolder, name)
|
||||||
|
err := t.installFile(dest, src)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error copying '%v' to '%v': %v", src, dest, err)
|
||||||
|
}
|
||||||
|
return dest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// installFile copies a file from src to dest and maintains
|
||||||
|
// file modes
|
||||||
|
func (t *fileInstaller) installFile(dest string, src string) error {
|
||||||
|
src = filepath.Join(t.sourceRoot, src)
|
||||||
|
t.logger.Infof("Installing '%v' to '%v'", src, dest)
|
||||||
|
|
||||||
|
source, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error opening source: %v", err)
|
||||||
|
}
|
||||||
|
defer source.Close()
|
||||||
|
|
||||||
|
destination, err := os.Create(dest)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating destination: %v", err)
|
||||||
|
}
|
||||||
|
defer destination.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(destination, source)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error copying file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = applyModeFromSource(dest, src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error setting destination file mode: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyModeFromSource sets the file mode for a destination file
|
||||||
|
// to match that of a specified source file
|
||||||
|
func applyModeFromSource(dest string, src string) error {
|
||||||
|
sourceInfo, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting file info for '%v': %v", src, err)
|
||||||
|
}
|
||||||
|
err = os.Chmod(dest, sourceInfo.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error setting mode for '%v': %v", dest, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
40
cmd/nvidia-ctk-installer/container/toolkit/options.go
Normal file
40
cmd/nvidia-ctk-installer/container/toolkit/options.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
# Copyright 2024 NVIDIA CORPORATION
|
||||||
|
#
|
||||||
|
# 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 toolkit
|
||||||
|
|
||||||
|
import "github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
|
|
||||||
|
// An Option provides a mechanism to configure an Installer.
|
||||||
|
type Option func(*Installer)
|
||||||
|
|
||||||
|
func WithLogger(logger logger.Interface) Option {
|
||||||
|
return func(i *Installer) {
|
||||||
|
i.logger = logger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithToolkitRoot(toolkitRoot string) Option {
|
||||||
|
return func(i *Installer) {
|
||||||
|
i.toolkitRoot = toolkitRoot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithSourceRoot(sourceRoot string) Option {
|
||||||
|
return func(i *Installer) {
|
||||||
|
i.sourceRoot = sourceRoot
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container/operator"
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container/operator"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -29,10 +29,10 @@ const (
|
|||||||
|
|
||||||
// installContainerRuntimes sets up the NVIDIA container runtimes, copying the executables
|
// installContainerRuntimes sets up the NVIDIA container runtimes, copying the executables
|
||||||
// and implementing the required wrapper
|
// and implementing the required wrapper
|
||||||
func installContainerRuntimes(toolkitDir string, driverRoot string) error {
|
func (t *Installer) installContainerRuntimes(toolkitDir string) error {
|
||||||
runtimes := operator.GetRuntimes()
|
runtimes := operator.GetRuntimes()
|
||||||
for _, runtime := range runtimes {
|
for _, runtime := range runtimes {
|
||||||
r := newNvidiaContainerRuntimeInstaller(runtime.Path)
|
r := t.newNvidiaContainerRuntimeInstaller(runtime.Path)
|
||||||
|
|
||||||
_, err := r.install(toolkitDir)
|
_, err := r.install(toolkitDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -46,17 +46,17 @@ func installContainerRuntimes(toolkitDir string, driverRoot string) error {
|
|||||||
// This installer will copy the specified source executable to the toolkit directory.
|
// This installer will copy the specified source executable to the toolkit directory.
|
||||||
// The executable is copied to a file with the same name as the source, but with a ".real" suffix and a wrapper is
|
// The executable is copied to a file with the same name as the source, but with a ".real" suffix and a wrapper is
|
||||||
// created to allow for the configuration of the runtime environment.
|
// created to allow for the configuration of the runtime environment.
|
||||||
func newNvidiaContainerRuntimeInstaller(source string) *executable {
|
func (t *Installer) newNvidiaContainerRuntimeInstaller(source string) *executable {
|
||||||
wrapperName := filepath.Base(source)
|
wrapperName := filepath.Base(source)
|
||||||
dotfileName := wrapperName + ".real"
|
dotfileName := wrapperName + ".real"
|
||||||
target := executableTarget{
|
target := executableTarget{
|
||||||
dotfileName: dotfileName,
|
dotfileName: dotfileName,
|
||||||
wrapperName: wrapperName,
|
wrapperName: wrapperName,
|
||||||
}
|
}
|
||||||
return newRuntimeInstaller(source, target, nil)
|
return t.newRuntimeInstaller(source, target, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRuntimeInstaller(source string, target executableTarget, env map[string]string) *executable {
|
func (t *Installer) newRuntimeInstaller(source string, target executableTarget, env map[string]string) *executable {
|
||||||
preLines := []string{
|
preLines := []string{
|
||||||
"",
|
"",
|
||||||
"cat /proc/modules | grep -e \"^nvidia \" >/dev/null 2>&1",
|
"cat /proc/modules | grep -e \"^nvidia \" >/dev/null 2>&1",
|
||||||
@@ -74,10 +74,11 @@ func newRuntimeInstaller(source string, target executableTarget, env map[string]
|
|||||||
}
|
}
|
||||||
|
|
||||||
r := executable{
|
r := executable{
|
||||||
source: source,
|
fileInstaller: t.fileInstaller,
|
||||||
target: target,
|
source: source,
|
||||||
env: runtimeEnv,
|
target: target,
|
||||||
preLines: preLines,
|
env: runtimeEnv,
|
||||||
|
preLines: preLines,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &r
|
return &r
|
||||||
@@ -21,11 +21,18 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNvidiaContainerRuntimeInstallerWrapper(t *testing.T) {
|
func TestNvidiaContainerRuntimeInstallerWrapper(t *testing.T) {
|
||||||
r := newNvidiaContainerRuntimeInstaller(nvidiaContainerRuntimeSource)
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
i := Installer{
|
||||||
|
fileInstaller: fileInstaller{
|
||||||
|
logger: logger,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
r := i.newNvidiaContainerRuntimeInstaller(nvidiaContainerRuntimeSource)
|
||||||
|
|
||||||
const shebang = "#! /bin/sh"
|
const shebang = "#! /bin/sh"
|
||||||
const destFolder = "/dest/folder"
|
const destFolder = "/dest/folder"
|
||||||
@@ -17,19 +17,17 @@
|
|||||||
package toolkit
|
package toolkit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"tags.cncf.io/container-device-interface/pkg/cdi"
|
"tags.cncf.io/container-device-interface/pkg/cdi"
|
||||||
"tags.cncf.io/container-device-interface/pkg/parser"
|
"tags.cncf.io/container-device-interface/pkg/parser"
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/system/nvdevices"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/system/nvdevices"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi"
|
||||||
transformroot "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root"
|
transformroot "github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi/transform/root"
|
||||||
@@ -44,10 +42,16 @@ const (
|
|||||||
|
|
||||||
nvidiaContainerToolkitConfigSource = "/etc/nvidia-container-runtime/config.toml"
|
nvidiaContainerToolkitConfigSource = "/etc/nvidia-container-runtime/config.toml"
|
||||||
configFilename = "config.toml"
|
configFilename = "config.toml"
|
||||||
|
|
||||||
toolkitPidFilename = "toolkit.pid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cdiOptions struct {
|
||||||
|
Enabled bool
|
||||||
|
outputDir string
|
||||||
|
kind string
|
||||||
|
vendor string
|
||||||
|
class string
|
||||||
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
DriverRoot string
|
DriverRoot string
|
||||||
DevRoot string
|
DevRoot string
|
||||||
@@ -67,11 +71,8 @@ type Options struct {
|
|||||||
|
|
||||||
ContainerCLIDebug string
|
ContainerCLIDebug string
|
||||||
|
|
||||||
cdiEnabled bool
|
// CDI stores the CDI options for the toolkit.
|
||||||
cdiOutputDir string
|
CDI cdiOptions
|
||||||
cdiKind string
|
|
||||||
cdiVendor string
|
|
||||||
cdiClass string
|
|
||||||
|
|
||||||
createDeviceNodes cli.StringSlice
|
createDeviceNodes cli.StringSlice
|
||||||
|
|
||||||
@@ -174,21 +175,21 @@ func Flags(opts *Options) []cli.Flag {
|
|||||||
Name: "cdi-enabled",
|
Name: "cdi-enabled",
|
||||||
Aliases: []string{"enable-cdi"},
|
Aliases: []string{"enable-cdi"},
|
||||||
Usage: "enable the generation of a CDI specification",
|
Usage: "enable the generation of a CDI specification",
|
||||||
Destination: &opts.cdiEnabled,
|
Destination: &opts.CDI.Enabled,
|
||||||
EnvVars: []string{"CDI_ENABLED", "ENABLE_CDI"},
|
EnvVars: []string{"CDI_ENABLED", "ENABLE_CDI"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "cdi-output-dir",
|
Name: "cdi-output-dir",
|
||||||
Usage: "the directory where the CDI output files are to be written. If this is set to '', no CDI specification is generated.",
|
Usage: "the directory where the CDI output files are to be written. If this is set to '', no CDI specification is generated.",
|
||||||
Value: "/var/run/cdi",
|
Value: "/var/run/cdi",
|
||||||
Destination: &opts.cdiOutputDir,
|
Destination: &opts.CDI.outputDir,
|
||||||
EnvVars: []string{"CDI_OUTPUT_DIR"},
|
EnvVars: []string{"CDI_OUTPUT_DIR"},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "cdi-kind",
|
Name: "cdi-kind",
|
||||||
Usage: "the vendor string to use for the generated CDI specification",
|
Usage: "the vendor string to use for the generated CDI specification",
|
||||||
Value: "management.nvidia.com/gpu",
|
Value: "management.nvidia.com/gpu",
|
||||||
Destination: &opts.cdiKind,
|
Destination: &opts.CDI.kind,
|
||||||
EnvVars: []string{"CDI_KIND"},
|
EnvVars: []string{"CDI_KIND"},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
@@ -215,25 +216,48 @@ func Flags(opts *Options) []cli.Flag {
|
|||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateOptions checks whether the specified options are valid
|
// An Installer is used to install the NVIDIA Container Toolkit from the toolkit container.
|
||||||
func ValidateOptions(opts *Options, toolkitRoot string) error {
|
type Installer struct {
|
||||||
if toolkitRoot == "" {
|
fileInstaller
|
||||||
return fmt.Errorf("invalid --toolkit-root option: %v", toolkitRoot)
|
// toolkitRoot specifies the destination path at which the toolkit is installed.
|
||||||
|
toolkitRoot string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInstaller creates an installer for the NVIDIA Container Toolkit.
|
||||||
|
func NewInstaller(opts ...Option) *Installer {
|
||||||
|
i := &Installer{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
vendor, class := parser.ParseQualifier(opts.cdiKind)
|
if i.logger == nil {
|
||||||
|
i.logger = logger.New()
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateOptions checks whether the specified options are valid
|
||||||
|
func (t *Installer) ValidateOptions(opts *Options) error {
|
||||||
|
if t == nil {
|
||||||
|
return fmt.Errorf("toolkit installer is not initilized")
|
||||||
|
}
|
||||||
|
if t.toolkitRoot == "" {
|
||||||
|
return fmt.Errorf("invalid --toolkit-root option: %v", t.toolkitRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
vendor, class := parser.ParseQualifier(opts.CDI.kind)
|
||||||
if err := parser.ValidateVendorName(vendor); err != nil {
|
if err := parser.ValidateVendorName(vendor); err != nil {
|
||||||
return fmt.Errorf("invalid CDI vendor name: %v", err)
|
return fmt.Errorf("invalid CDI vendor name: %v", err)
|
||||||
}
|
}
|
||||||
if err := parser.ValidateClassName(class); err != nil {
|
if err := parser.ValidateClassName(class); err != nil {
|
||||||
return fmt.Errorf("invalid CDI class name: %v", err)
|
return fmt.Errorf("invalid CDI class name: %v", err)
|
||||||
}
|
}
|
||||||
opts.cdiVendor = vendor
|
opts.CDI.vendor = vendor
|
||||||
opts.cdiClass = class
|
opts.CDI.class = class
|
||||||
|
|
||||||
if opts.cdiEnabled && opts.cdiOutputDir == "" {
|
if opts.CDI.Enabled && opts.CDI.outputDir == "" {
|
||||||
log.Warning("Skipping CDI spec generation (no output directory specified)")
|
t.logger.Warning("Skipping CDI spec generation (no output directory specified)")
|
||||||
opts.cdiEnabled = false
|
opts.CDI.Enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
isDisabled := false
|
isDisabled := false
|
||||||
@@ -246,8 +270,8 @@ func ValidateOptions(opts *Options, toolkitRoot string) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !opts.cdiEnabled && !isDisabled {
|
if !opts.CDI.Enabled && !isDisabled {
|
||||||
log.Info("disabling device node creation since --cdi-enabled=false")
|
t.logger.Info("disabling device node creation since --cdi-enabled=false")
|
||||||
isDisabled = true
|
isDisabled = true
|
||||||
}
|
}
|
||||||
if isDisabled {
|
if isDisabled {
|
||||||
@@ -257,117 +281,93 @@ func ValidateOptions(opts *Options, toolkitRoot string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryDelete attempts to remove the specified toolkit folder.
|
|
||||||
// A toolkit.pid file -- if present -- is skipped.
|
|
||||||
func TryDelete(cli *cli.Context, toolkitRoot string) error {
|
|
||||||
log.Infof("Attempting to delete NVIDIA container toolkit from '%v'", toolkitRoot)
|
|
||||||
|
|
||||||
contents, err := os.ReadDir(toolkitRoot)
|
|
||||||
if err != nil && errors.Is(err, os.ErrNotExist) {
|
|
||||||
return nil
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("failed to read the contents of %v: %w", toolkitRoot, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, content := range contents {
|
|
||||||
if content.Name() == toolkitPidFilename {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name := filepath.Join(toolkitRoot, content.Name())
|
|
||||||
if err := os.RemoveAll(name); err != nil {
|
|
||||||
log.Warningf("could not remove %v: %v", name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := os.RemoveAll(toolkitRoot); err != nil {
|
|
||||||
log.Warningf("could not remove %v: %v", toolkitRoot, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install installs the components of the NVIDIA container toolkit.
|
// Install installs the components of the NVIDIA container toolkit.
|
||||||
// Any existing installation is removed.
|
// Any existing installation is removed.
|
||||||
func Install(cli *cli.Context, opts *Options, toolkitRoot string) error {
|
func (t *Installer) Install(cli *cli.Context, opts *Options) error {
|
||||||
log.Infof("Installing NVIDIA container toolkit to '%v'", toolkitRoot)
|
if t == nil {
|
||||||
|
return fmt.Errorf("toolkit installer is not initilized")
|
||||||
|
}
|
||||||
|
t.logger.Infof("Installing NVIDIA container toolkit to '%v'", t.toolkitRoot)
|
||||||
|
|
||||||
log.Infof("Removing existing NVIDIA container toolkit installation")
|
t.logger.Infof("Removing existing NVIDIA container toolkit installation")
|
||||||
err := os.RemoveAll(toolkitRoot)
|
err := os.RemoveAll(t.toolkitRoot)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error removing toolkit directory: %v", err)
|
return fmt.Errorf("error removing toolkit directory: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error removing toolkit directory: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error removing toolkit directory: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
toolkitConfigDir := filepath.Join(toolkitRoot, ".config", "nvidia-container-runtime")
|
toolkitConfigDir := filepath.Join(t.toolkitRoot, ".config", "nvidia-container-runtime")
|
||||||
toolkitConfigPath := filepath.Join(toolkitConfigDir, configFilename)
|
toolkitConfigPath := filepath.Join(toolkitConfigDir, configFilename)
|
||||||
|
|
||||||
err = createDirectories(toolkitRoot, toolkitConfigDir)
|
err = t.createDirectories(t.toolkitRoot, toolkitConfigDir)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("could not create required directories: %v", err)
|
return fmt.Errorf("could not create required directories: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("could not create required directories: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("could not create required directories: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = installContainerLibraries(toolkitRoot)
|
err = t.installContainerLibraries(t.toolkitRoot)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error installing NVIDIA container library: %v", err)
|
return fmt.Errorf("error installing NVIDIA container library: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container library: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container library: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = installContainerRuntimes(toolkitRoot, opts.DriverRoot)
|
err = t.installContainerRuntimes(t.toolkitRoot)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error installing NVIDIA container runtime: %v", err)
|
return fmt.Errorf("error installing NVIDIA container runtime: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container runtime: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container runtime: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
nvidiaContainerCliExecutable, err := installContainerCLI(toolkitRoot)
|
nvidiaContainerCliExecutable, err := t.installContainerCLI(t.toolkitRoot)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error installing NVIDIA container CLI: %v", err)
|
return fmt.Errorf("error installing NVIDIA container CLI: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container CLI: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container CLI: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
nvidiaContainerRuntimeHookPath, err := installRuntimeHook(toolkitRoot, toolkitConfigPath)
|
nvidiaContainerRuntimeHookPath, err := t.installRuntimeHook(t.toolkitRoot, toolkitConfigPath)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error installing NVIDIA container runtime hook: %v", err)
|
return fmt.Errorf("error installing NVIDIA container runtime hook: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container runtime hook: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container runtime hook: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
nvidiaCTKPath, err := installContainerToolkitCLI(toolkitRoot)
|
nvidiaCTKPath, err := t.installContainerToolkitCLI(t.toolkitRoot)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error installing NVIDIA Container Toolkit CLI: %v", err)
|
return fmt.Errorf("error installing NVIDIA Container Toolkit CLI: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA Container Toolkit CLI: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA Container Toolkit CLI: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
nvidiaCDIHookPath, err := installContainerCDIHookCLI(toolkitRoot)
|
nvidiaCDIHookPath, err := t.installContainerCDIHookCLI(t.toolkitRoot)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error installing NVIDIA Container CDI Hook CLI: %v", err)
|
return fmt.Errorf("error installing NVIDIA Container CDI Hook CLI: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA Container CDI Hook CLI: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA Container CDI Hook CLI: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = installToolkitConfig(cli, toolkitConfigPath, nvidiaContainerCliExecutable, nvidiaCTKPath, nvidiaContainerRuntimeHookPath, opts)
|
err = t.installToolkitConfig(cli, toolkitConfigPath, nvidiaContainerCliExecutable, nvidiaCTKPath, nvidiaContainerRuntimeHookPath, opts)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error installing NVIDIA container toolkit config: %v", err)
|
return fmt.Errorf("error installing NVIDIA container toolkit config: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container toolkit config: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error installing NVIDIA container toolkit config: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = createDeviceNodes(opts)
|
err = t.createDeviceNodes(opts)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error creating device nodes: %v", err)
|
return fmt.Errorf("error creating device nodes: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error creating device nodes: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error creating device nodes: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = generateCDISpec(opts, nvidiaCDIHookPath)
|
err = t.generateCDISpec(opts, nvidiaCDIHookPath)
|
||||||
if err != nil && !opts.ignoreErrors {
|
if err != nil && !opts.ignoreErrors {
|
||||||
return fmt.Errorf("error generating CDI specification: %v", err)
|
return fmt.Errorf("error generating CDI specification: %v", err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Errorf("Ignoring error: %v", fmt.Errorf("error generating CDI specification: %v", err))
|
t.logger.Errorf("Ignoring error: %v", fmt.Errorf("error generating CDI specification: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -378,8 +378,8 @@ func Install(cli *cli.Context, opts *Options, toolkitRoot string) error {
|
|||||||
// A predefined set of library candidates are considered, with the first one
|
// A predefined set of library candidates are considered, with the first one
|
||||||
// resulting in success being installed to the toolkit folder. The install process
|
// resulting in success being installed to the toolkit folder. The install process
|
||||||
// resolves the symlink for the library and copies the versioned library itself.
|
// resolves the symlink for the library and copies the versioned library itself.
|
||||||
func installContainerLibraries(toolkitRoot string) error {
|
func (t *Installer) installContainerLibraries(toolkitRoot string) error {
|
||||||
log.Infof("Installing NVIDIA container library to '%v'", toolkitRoot)
|
t.logger.Infof("Installing NVIDIA container library to '%v'", toolkitRoot)
|
||||||
|
|
||||||
libs := []string{
|
libs := []string{
|
||||||
"libnvidia-container.so.1",
|
"libnvidia-container.so.1",
|
||||||
@@ -387,7 +387,7 @@ func installContainerLibraries(toolkitRoot string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, l := range libs {
|
for _, l := range libs {
|
||||||
err := installLibrary(l, toolkitRoot)
|
err := t.installLibrary(l, toolkitRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to install %s: %v", l, err)
|
return fmt.Errorf("failed to install %s: %v", l, err)
|
||||||
}
|
}
|
||||||
@@ -397,23 +397,23 @@ func installContainerLibraries(toolkitRoot string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// installLibrary installs the specified library to the toolkit directory.
|
// installLibrary installs the specified library to the toolkit directory.
|
||||||
func installLibrary(libName string, toolkitRoot string) error {
|
func (t *Installer) installLibrary(libName string, toolkitRoot string) error {
|
||||||
libraryPath, err := findLibrary("", libName)
|
libraryPath, err := t.findLibrary(libName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error locating NVIDIA container library: %v", err)
|
return fmt.Errorf("error locating NVIDIA container library: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
installedLibPath, err := installFileToFolder(toolkitRoot, libraryPath)
|
installedLibPath, err := t.installFileToFolder(toolkitRoot, libraryPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error installing %v to %v: %v", libraryPath, toolkitRoot, err)
|
return fmt.Errorf("error installing %v to %v: %v", libraryPath, toolkitRoot, err)
|
||||||
}
|
}
|
||||||
log.Infof("Installed '%v' to '%v'", libraryPath, installedLibPath)
|
t.logger.Infof("Installed '%v' to '%v'", libraryPath, installedLibPath)
|
||||||
|
|
||||||
if filepath.Base(installedLibPath) == libName {
|
if filepath.Base(installedLibPath) == libName {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = installSymlink(toolkitRoot, libName, installedLibPath)
|
err = t.installSymlink(toolkitRoot, libName, installedLibPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error installing symlink for NVIDIA container library: %v", err)
|
return fmt.Errorf("error installing symlink for NVIDIA container library: %v", err)
|
||||||
}
|
}
|
||||||
@@ -423,8 +423,8 @@ func installLibrary(libName string, toolkitRoot string) error {
|
|||||||
|
|
||||||
// installToolkitConfig installs the config file for the NVIDIA container toolkit ensuring
|
// installToolkitConfig installs the config file for the NVIDIA container toolkit ensuring
|
||||||
// that the settings are updated to match the desired install and nvidia driver directories.
|
// that the settings are updated to match the desired install and nvidia driver directories.
|
||||||
func installToolkitConfig(c *cli.Context, toolkitConfigPath string, nvidiaContainerCliExecutablePath string, nvidiaCTKPath string, nvidaContainerRuntimeHookPath string, opts *Options) error {
|
func (t *Installer) installToolkitConfig(c *cli.Context, toolkitConfigPath string, nvidiaContainerCliExecutablePath string, nvidiaCTKPath string, nvidaContainerRuntimeHookPath string, opts *Options) error {
|
||||||
log.Infof("Installing NVIDIA container toolkit config '%v'", toolkitConfigPath)
|
t.logger.Infof("Installing NVIDIA container toolkit config '%v'", toolkitConfigPath)
|
||||||
|
|
||||||
cfg, err := config.New(
|
cfg, err := config.New(
|
||||||
config.WithConfigFile(nvidiaContainerToolkitConfigSource),
|
config.WithConfigFile(nvidiaContainerToolkitConfigSource),
|
||||||
@@ -486,11 +486,11 @@ func installToolkitConfig(c *cli.Context, toolkitConfigPath string, nvidiaContai
|
|||||||
|
|
||||||
for key, value := range optionalConfigValues {
|
for key, value := range optionalConfigValues {
|
||||||
if !c.IsSet(key) {
|
if !c.IsSet(key) {
|
||||||
log.Infof("Skipping unset option: %v", key)
|
t.logger.Infof("Skipping unset option: %v", key)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if value == nil {
|
if value == nil {
|
||||||
log.Infof("Skipping option with nil value: %v", key)
|
t.logger.Infof("Skipping option with nil value: %v", key)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +505,7 @@ func installToolkitConfig(c *cli.Context, toolkitConfigPath string, nvidiaContai
|
|||||||
}
|
}
|
||||||
value = v.Value()
|
value = v.Value()
|
||||||
default:
|
default:
|
||||||
log.Warningf("Unexpected type for option %v=%v: %T", key, value, v)
|
t.logger.Warningf("Unexpected type for option %v=%v: %T", key, value, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Set(key, value)
|
cfg.Set(key, value)
|
||||||
@@ -517,16 +517,17 @@ func installToolkitConfig(c *cli.Context, toolkitConfigPath string, nvidiaContai
|
|||||||
|
|
||||||
os.Stdout.WriteString("Using config:\n")
|
os.Stdout.WriteString("Using config:\n")
|
||||||
if _, err = cfg.WriteTo(os.Stdout); err != nil {
|
if _, err = cfg.WriteTo(os.Stdout); err != nil {
|
||||||
log.Warningf("Failed to output config to STDOUT: %v", err)
|
t.logger.Warningf("Failed to output config to STDOUT: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// installContainerToolkitCLI installs the nvidia-ctk CLI executable and wrapper.
|
// installContainerToolkitCLI installs the nvidia-ctk CLI executable and wrapper.
|
||||||
func installContainerToolkitCLI(toolkitDir string) (string, error) {
|
func (t *Installer) installContainerToolkitCLI(toolkitDir string) (string, error) {
|
||||||
e := executable{
|
e := executable{
|
||||||
source: "/usr/bin/nvidia-ctk",
|
fileInstaller: t.fileInstaller,
|
||||||
|
source: "/usr/bin/nvidia-ctk",
|
||||||
target: executableTarget{
|
target: executableTarget{
|
||||||
dotfileName: "nvidia-ctk.real",
|
dotfileName: "nvidia-ctk.real",
|
||||||
wrapperName: "nvidia-ctk",
|
wrapperName: "nvidia-ctk",
|
||||||
@@ -537,9 +538,10 @@ func installContainerToolkitCLI(toolkitDir string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// installContainerCDIHookCLI installs the nvidia-cdi-hook CLI executable and wrapper.
|
// installContainerCDIHookCLI installs the nvidia-cdi-hook CLI executable and wrapper.
|
||||||
func installContainerCDIHookCLI(toolkitDir string) (string, error) {
|
func (t *Installer) installContainerCDIHookCLI(toolkitDir string) (string, error) {
|
||||||
e := executable{
|
e := executable{
|
||||||
source: "/usr/bin/nvidia-cdi-hook",
|
fileInstaller: t.fileInstaller,
|
||||||
|
source: "/usr/bin/nvidia-cdi-hook",
|
||||||
target: executableTarget{
|
target: executableTarget{
|
||||||
dotfileName: "nvidia-cdi-hook.real",
|
dotfileName: "nvidia-cdi-hook.real",
|
||||||
wrapperName: "nvidia-cdi-hook",
|
wrapperName: "nvidia-cdi-hook",
|
||||||
@@ -551,15 +553,16 @@ func installContainerCDIHookCLI(toolkitDir string) (string, error) {
|
|||||||
|
|
||||||
// installContainerCLI sets up the NVIDIA container CLI executable, copying the executable
|
// installContainerCLI sets up the NVIDIA container CLI executable, copying the executable
|
||||||
// and implementing the required wrapper
|
// and implementing the required wrapper
|
||||||
func installContainerCLI(toolkitRoot string) (string, error) {
|
func (t *Installer) installContainerCLI(toolkitRoot string) (string, error) {
|
||||||
log.Infof("Installing NVIDIA container CLI from '%v'", nvidiaContainerCliSource)
|
t.logger.Infof("Installing NVIDIA container CLI from '%v'", nvidiaContainerCliSource)
|
||||||
|
|
||||||
env := map[string]string{
|
env := map[string]string{
|
||||||
"LD_LIBRARY_PATH": toolkitRoot,
|
"LD_LIBRARY_PATH": toolkitRoot,
|
||||||
}
|
}
|
||||||
|
|
||||||
e := executable{
|
e := executable{
|
||||||
source: nvidiaContainerCliSource,
|
fileInstaller: t.fileInstaller,
|
||||||
|
source: nvidiaContainerCliSource,
|
||||||
target: executableTarget{
|
target: executableTarget{
|
||||||
dotfileName: "nvidia-container-cli.real",
|
dotfileName: "nvidia-container-cli.real",
|
||||||
wrapperName: "nvidia-container-cli",
|
wrapperName: "nvidia-container-cli",
|
||||||
@@ -576,15 +579,16 @@ func installContainerCLI(toolkitRoot string) (string, error) {
|
|||||||
|
|
||||||
// installRuntimeHook sets up the NVIDIA runtime hook, copying the executable
|
// installRuntimeHook sets up the NVIDIA runtime hook, copying the executable
|
||||||
// and implementing the required wrapper
|
// and implementing the required wrapper
|
||||||
func installRuntimeHook(toolkitRoot string, configFilePath string) (string, error) {
|
func (t *Installer) installRuntimeHook(toolkitRoot string, configFilePath string) (string, error) {
|
||||||
log.Infof("Installing NVIDIA container runtime hook from '%v'", nvidiaContainerRuntimeHookSource)
|
t.logger.Infof("Installing NVIDIA container runtime hook from '%v'", nvidiaContainerRuntimeHookSource)
|
||||||
|
|
||||||
argLines := []string{
|
argLines := []string{
|
||||||
fmt.Sprintf("-config \"%s\"", configFilePath),
|
fmt.Sprintf("-config \"%s\"", configFilePath),
|
||||||
}
|
}
|
||||||
|
|
||||||
e := executable{
|
e := executable{
|
||||||
source: nvidiaContainerRuntimeHookSource,
|
fileInstaller: t.fileInstaller,
|
||||||
|
source: nvidiaContainerRuntimeHookSource,
|
||||||
target: executableTarget{
|
target: executableTarget{
|
||||||
dotfileName: "nvidia-container-runtime-hook.real",
|
dotfileName: "nvidia-container-runtime-hook.real",
|
||||||
wrapperName: "nvidia-container-runtime-hook",
|
wrapperName: "nvidia-container-runtime-hook",
|
||||||
@@ -597,7 +601,7 @@ func installRuntimeHook(toolkitRoot string, configFilePath string) (string, erro
|
|||||||
return "", fmt.Errorf("error installing NVIDIA container runtime hook: %v", err)
|
return "", fmt.Errorf("error installing NVIDIA container runtime hook: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = installSymlink(toolkitRoot, "nvidia-container-toolkit", installedPath)
|
err = t.installSymlink(toolkitRoot, "nvidia-container-toolkit", installedPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error installing symlink to NVIDIA container runtime hook: %v", err)
|
return "", fmt.Errorf("error installing symlink to NVIDIA container runtime hook: %v", err)
|
||||||
}
|
}
|
||||||
@@ -607,10 +611,10 @@ func installRuntimeHook(toolkitRoot string, configFilePath string) (string, erro
|
|||||||
|
|
||||||
// installSymlink creates a symlink in the toolkitDirectory that points to the specified target.
|
// installSymlink creates a symlink in the toolkitDirectory that points to the specified target.
|
||||||
// Note: The target is assumed to be local to the toolkit directory
|
// Note: The target is assumed to be local to the toolkit directory
|
||||||
func installSymlink(toolkitRoot string, link string, target string) error {
|
func (t *Installer) installSymlink(toolkitRoot string, link string, target string) error {
|
||||||
symlinkPath := filepath.Join(toolkitRoot, link)
|
symlinkPath := filepath.Join(toolkitRoot, link)
|
||||||
targetPath := filepath.Base(target)
|
targetPath := filepath.Base(target)
|
||||||
log.Infof("Creating symlink '%v' -> '%v'", symlinkPath, targetPath)
|
t.logger.Infof("Creating symlink '%v' -> '%v'", symlinkPath, targetPath)
|
||||||
|
|
||||||
err := os.Symlink(targetPath, symlinkPath)
|
err := os.Symlink(targetPath, symlinkPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -619,72 +623,10 @@ func installSymlink(toolkitRoot string, link string, target string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// installFileToFolder copies a source file to a destination folder.
|
|
||||||
// The path of the input file is ignored.
|
|
||||||
// e.g. installFileToFolder("/some/path/file.txt", "/output/path")
|
|
||||||
// will result in a file "/output/path/file.txt" being generated
|
|
||||||
func installFileToFolder(destFolder string, src string) (string, error) {
|
|
||||||
name := filepath.Base(src)
|
|
||||||
return installFileToFolderWithName(destFolder, name, src)
|
|
||||||
}
|
|
||||||
|
|
||||||
// cp src destFolder/name
|
|
||||||
func installFileToFolderWithName(destFolder string, name, src string) (string, error) {
|
|
||||||
dest := filepath.Join(destFolder, name)
|
|
||||||
err := installFile(dest, src)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("error copying '%v' to '%v': %v", src, dest, err)
|
|
||||||
}
|
|
||||||
return dest, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// installFile copies a file from src to dest and maintains
|
|
||||||
// file modes
|
|
||||||
func installFile(dest string, src string) error {
|
|
||||||
log.Infof("Installing '%v' to '%v'", src, dest)
|
|
||||||
|
|
||||||
source, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error opening source: %v", err)
|
|
||||||
}
|
|
||||||
defer source.Close()
|
|
||||||
|
|
||||||
destination, err := os.Create(dest)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error creating destination: %v", err)
|
|
||||||
}
|
|
||||||
defer destination.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(destination, source)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error copying file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = applyModeFromSource(dest, src)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting destination file mode: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyModeFromSource sets the file mode for a destination file
|
|
||||||
// to match that of a specified source file
|
|
||||||
func applyModeFromSource(dest string, src string) error {
|
|
||||||
sourceInfo, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error getting file info for '%v': %v", src, err)
|
|
||||||
}
|
|
||||||
err = os.Chmod(dest, sourceInfo.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error setting mode for '%v': %v", dest, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// findLibrary searches a set of candidate libraries in the specified root for
|
// findLibrary searches a set of candidate libraries in the specified root for
|
||||||
// a given library name
|
// a given library name
|
||||||
func findLibrary(root string, libName string) (string, error) {
|
func (t *Installer) findLibrary(libName string) (string, error) {
|
||||||
log.Infof("Finding library %v (root=%v)", libName, root)
|
t.logger.Infof("Finding library %v (root=%v)", libName)
|
||||||
|
|
||||||
candidateDirs := []string{
|
candidateDirs := []string{
|
||||||
"/usr/lib64",
|
"/usr/lib64",
|
||||||
@@ -693,16 +635,16 @@ func findLibrary(root string, libName string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range candidateDirs {
|
for _, d := range candidateDirs {
|
||||||
l := filepath.Join(root, d, libName)
|
l := filepath.Join(t.sourceRoot, d, libName)
|
||||||
log.Infof("Checking library candidate '%v'", l)
|
t.logger.Infof("Checking library candidate '%v'", l)
|
||||||
|
|
||||||
libraryCandidate, err := resolveLink(l)
|
libraryCandidate, err := t.resolveLink(l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("Skipping library candidate '%v': %v", l, err)
|
t.logger.Infof("Skipping library candidate '%v': %v", l, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return libraryCandidate, nil
|
return strings.TrimPrefix(libraryCandidate, t.sourceRoot), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("error locating library '%v'", libName)
|
return "", fmt.Errorf("error locating library '%v'", libName)
|
||||||
@@ -711,20 +653,20 @@ func findLibrary(root string, libName string) (string, error) {
|
|||||||
// resolveLink finds the target of a symlink or the file itself in the
|
// resolveLink finds the target of a symlink or the file itself in the
|
||||||
// case of a regular file.
|
// case of a regular file.
|
||||||
// This is equivalent to running `readlink -f ${l}`
|
// This is equivalent to running `readlink -f ${l}`
|
||||||
func resolveLink(l string) (string, error) {
|
func (t *Installer) resolveLink(l string) (string, error) {
|
||||||
resolved, err := filepath.EvalSymlinks(l)
|
resolved, err := filepath.EvalSymlinks(l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error resolving link '%v': %v", l, err)
|
return "", fmt.Errorf("error resolving link '%v': %v", l, err)
|
||||||
}
|
}
|
||||||
if l != resolved {
|
if l != resolved {
|
||||||
log.Infof("Resolved link: '%v' => '%v'", l, resolved)
|
t.logger.Infof("Resolved link: '%v' => '%v'", l, resolved)
|
||||||
}
|
}
|
||||||
return resolved, nil
|
return resolved, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDirectories(dir ...string) error {
|
func (t *Installer) createDirectories(dir ...string) error {
|
||||||
for _, d := range dir {
|
for _, d := range dir {
|
||||||
log.Infof("Creating directory '%v'", d)
|
t.logger.Infof("Creating directory '%v'", d)
|
||||||
err := os.MkdirAll(d, 0755)
|
err := os.MkdirAll(d, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating directory: %v", err)
|
return fmt.Errorf("error creating directory: %v", err)
|
||||||
@@ -733,7 +675,7 @@ func createDirectories(dir ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDeviceNodes(opts *Options) error {
|
func (t *Installer) createDeviceNodes(opts *Options) error {
|
||||||
modes := opts.createDeviceNodes.Value()
|
modes := opts.createDeviceNodes.Value()
|
||||||
if len(modes) == 0 {
|
if len(modes) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -747,9 +689,9 @@ func createDeviceNodes(opts *Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, mode := range modes {
|
for _, mode := range modes {
|
||||||
log.Infof("Creating %v device nodes at %v", mode, opts.DevRootCtrPath)
|
t.logger.Infof("Creating %v device nodes at %v", mode, opts.DevRootCtrPath)
|
||||||
if mode != "control" {
|
if mode != "control" {
|
||||||
log.Warningf("Unrecognised device mode: %v", mode)
|
t.logger.Warningf("Unrecognised device mode: %v", mode)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := devices.CreateNVIDIAControlDevices(); err != nil {
|
if err := devices.CreateNVIDIAControlDevices(); err != nil {
|
||||||
@@ -760,18 +702,19 @@ func createDeviceNodes(opts *Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generateCDISpec generates a CDI spec for use in management containers
|
// generateCDISpec generates a CDI spec for use in management containers
|
||||||
func generateCDISpec(opts *Options, nvidiaCDIHookPath string) error {
|
func (t *Installer) generateCDISpec(opts *Options, nvidiaCDIHookPath string) error {
|
||||||
if !opts.cdiEnabled {
|
if !opts.CDI.Enabled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Info("Generating CDI spec for management containers")
|
t.logger.Info("Generating CDI spec for management containers")
|
||||||
cdilib, err := nvcdi.New(
|
cdilib, err := nvcdi.New(
|
||||||
|
nvcdi.WithLogger(t.logger),
|
||||||
nvcdi.WithMode(nvcdi.ModeManagement),
|
nvcdi.WithMode(nvcdi.ModeManagement),
|
||||||
nvcdi.WithDriverRoot(opts.DriverRootCtrPath),
|
nvcdi.WithDriverRoot(opts.DriverRootCtrPath),
|
||||||
nvcdi.WithDevRoot(opts.DevRootCtrPath),
|
nvcdi.WithDevRoot(opts.DevRootCtrPath),
|
||||||
nvcdi.WithNVIDIACDIHookPath(nvidiaCDIHookPath),
|
nvcdi.WithNVIDIACDIHookPath(nvidiaCDIHookPath),
|
||||||
nvcdi.WithVendor(opts.cdiVendor),
|
nvcdi.WithVendor(opts.CDI.vendor),
|
||||||
nvcdi.WithClass(opts.cdiClass),
|
nvcdi.WithClass(opts.CDI.class),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create CDI library for management containers: %v", err)
|
return fmt.Errorf("failed to create CDI library for management containers: %v", err)
|
||||||
@@ -796,7 +739,7 @@ func generateCDISpec(opts *Options, nvidiaCDIHookPath string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to generate CDI name for management containers: %v", err)
|
return fmt.Errorf("failed to generate CDI name for management containers: %v", err)
|
||||||
}
|
}
|
||||||
err = spec.Save(filepath.Join(opts.cdiOutputDir, name))
|
err = spec.Save(filepath.Join(opts.CDI.outputDir, name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to save CDI spec for management containers: %v", err)
|
return fmt.Errorf("failed to save CDI spec for management containers: %v", err)
|
||||||
}
|
}
|
||||||
217
cmd/nvidia-ctk-installer/container/toolkit/toolkit_test.go
Normal file
217
cmd/nvidia-ctk-installer/container/toolkit/toolkit_test.go
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
/**
|
||||||
|
# Copyright 2024 NVIDIA CORPORATION
|
||||||
|
#
|
||||||
|
# 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 toolkit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/symlinks"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInstall(t *testing.T) {
|
||||||
|
t.Setenv("__NVCT_TESTING_DEVICES_ARE_FILES", "true")
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
|
||||||
|
moduleRoot, err := test.GetModuleRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
artifactRoot := filepath.Join(moduleRoot, "testdata", "installer", "artifacts")
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
hostRoot string
|
||||||
|
packageType string
|
||||||
|
cdiEnabled bool
|
||||||
|
expectedError error
|
||||||
|
expectedCdiSpec string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
hostRoot: "rootfs-empty",
|
||||||
|
packageType: "deb",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hostRoot: "rootfs-empty",
|
||||||
|
packageType: "rpm",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hostRoot: "rootfs-empty",
|
||||||
|
packageType: "deb",
|
||||||
|
cdiEnabled: true,
|
||||||
|
expectedError: fmt.Errorf("no NVIDIA device nodes found"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hostRoot: "rootfs-1",
|
||||||
|
packageType: "deb",
|
||||||
|
cdiEnabled: true,
|
||||||
|
expectedCdiSpec: `---
|
||||||
|
cdiVersion: 0.5.0
|
||||||
|
containerEdits:
|
||||||
|
env:
|
||||||
|
- NVIDIA_VISIBLE_DEVICES=void
|
||||||
|
hooks:
|
||||||
|
- args:
|
||||||
|
- nvidia-cdi-hook
|
||||||
|
- create-symlinks
|
||||||
|
- --link
|
||||||
|
- libcuda.so.1::/lib/x86_64-linux-gnu/libcuda.so
|
||||||
|
hookName: createContainer
|
||||||
|
path: {{ .toolkitRoot }}/nvidia-cdi-hook
|
||||||
|
- args:
|
||||||
|
- nvidia-cdi-hook
|
||||||
|
- update-ldcache
|
||||||
|
- --folder
|
||||||
|
- /lib/x86_64-linux-gnu
|
||||||
|
hookName: createContainer
|
||||||
|
path: {{ .toolkitRoot }}/nvidia-cdi-hook
|
||||||
|
mounts:
|
||||||
|
- containerPath: /lib/x86_64-linux-gnu/libcuda.so.999.88.77
|
||||||
|
hostPath: /host/driver/root/lib/x86_64-linux-gnu/libcuda.so.999.88.77
|
||||||
|
options:
|
||||||
|
- ro
|
||||||
|
- nosuid
|
||||||
|
- nodev
|
||||||
|
- bind
|
||||||
|
devices:
|
||||||
|
- containerEdits:
|
||||||
|
deviceNodes:
|
||||||
|
- hostPath: /host/driver/root/dev/nvidia0
|
||||||
|
path: /dev/nvidia0
|
||||||
|
- hostPath: /host/driver/root/dev/nvidiactl
|
||||||
|
path: /dev/nvidiactl
|
||||||
|
- hostPath: /host/driver/root/dev/nvidia-caps-imex-channels/channel0
|
||||||
|
path: /dev/nvidia-caps-imex-channels/channel0
|
||||||
|
- hostPath: /host/driver/root/dev/nvidia-caps-imex-channels/channel1
|
||||||
|
path: /dev/nvidia-caps-imex-channels/channel1
|
||||||
|
- hostPath: /host/driver/root/dev/nvidia-caps-imex-channels/channel2047
|
||||||
|
path: /dev/nvidia-caps-imex-channels/channel2047
|
||||||
|
name: all
|
||||||
|
kind: example.com/class
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
// hostRoot := filepath.Join(moduleRoot, "testdata", "lookup", tc.hostRoot)
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
testRoot := t.TempDir()
|
||||||
|
toolkitRoot := filepath.Join(testRoot, "toolkit-test")
|
||||||
|
cdiOutputDir := filepath.Join(moduleRoot, "toolkit-test", "/var/cdi")
|
||||||
|
sourceRoot := filepath.Join(artifactRoot, tc.packageType)
|
||||||
|
options := Options{
|
||||||
|
DriverRoot: "/host/driver/root",
|
||||||
|
DriverRootCtrPath: filepath.Join(moduleRoot, "testdata", "lookup", tc.hostRoot),
|
||||||
|
CDI: cdiOptions{
|
||||||
|
Enabled: tc.cdiEnabled,
|
||||||
|
outputDir: cdiOutputDir,
|
||||||
|
kind: "example.com/class",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ti := NewInstaller(
|
||||||
|
WithLogger(logger),
|
||||||
|
WithToolkitRoot(toolkitRoot),
|
||||||
|
WithSourceRoot(sourceRoot),
|
||||||
|
)
|
||||||
|
require.NoError(t, ti.ValidateOptions(&options))
|
||||||
|
|
||||||
|
err := ti.Install(&cli.Context{}, &options)
|
||||||
|
if tc.expectedError == nil {
|
||||||
|
require.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
require.Contains(t, err.Error(), tc.expectedError.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
require.DirExists(t, toolkitRoot)
|
||||||
|
requireSymlink(t, toolkitRoot, "libnvidia-container.so.1", "libnvidia-container.so.99.88.77")
|
||||||
|
requireSymlink(t, toolkitRoot, "libnvidia-container-go.so.1", "libnvidia-container-go.so.99.88.77")
|
||||||
|
|
||||||
|
requireWrappedExecutable(t, toolkitRoot, "nvidia-cdi-hook")
|
||||||
|
requireWrappedExecutable(t, toolkitRoot, "nvidia-container-cli")
|
||||||
|
requireWrappedExecutable(t, toolkitRoot, "nvidia-container-runtime")
|
||||||
|
requireWrappedExecutable(t, toolkitRoot, "nvidia-container-runtime-hook")
|
||||||
|
requireWrappedExecutable(t, toolkitRoot, "nvidia-container-runtime.cdi")
|
||||||
|
requireWrappedExecutable(t, toolkitRoot, "nvidia-container-runtime.legacy")
|
||||||
|
requireWrappedExecutable(t, toolkitRoot, "nvidia-ctk")
|
||||||
|
|
||||||
|
requireSymlink(t, toolkitRoot, "nvidia-container-toolkit", "nvidia-container-runtime-hook")
|
||||||
|
|
||||||
|
// TODO: Add checks for wrapper contents
|
||||||
|
// grep -q -E "nvidia driver modules are not yet loaded, invoking runc directly" "${shared_dir}/usr/local/nvidia/toolkit/nvidia-container-runtime"
|
||||||
|
// grep -q -E "exec runc \".@\"" "${shared_dir}/usr/local/nvidia/toolkit/nvidia-container-runtime"
|
||||||
|
|
||||||
|
require.DirExists(t, filepath.Join(toolkitRoot, ".config"))
|
||||||
|
require.DirExists(t, filepath.Join(toolkitRoot, ".config", "nvidia-container-runtime"))
|
||||||
|
require.FileExists(t, filepath.Join(toolkitRoot, ".config", "nvidia-container-runtime", "config.toml"))
|
||||||
|
|
||||||
|
cfgToml, err := config.New(config.WithConfigFile(filepath.Join(toolkitRoot, ".config", "nvidia-container-runtime", "config.toml")))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cfg, err := cfgToml.Config()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Ensure that the config file has the required contents.
|
||||||
|
// TODO: Add checks for additional config options.
|
||||||
|
require.Equal(t, "/host/driver/root", cfg.NVIDIAContainerCLIConfig.Root)
|
||||||
|
require.Equal(t, "@/host/driver/root/sbin/ldconfig", string(cfg.NVIDIAContainerCLIConfig.Ldconfig))
|
||||||
|
require.EqualValues(t, filepath.Join(toolkitRoot, "nvidia-container-cli"), cfg.NVIDIAContainerCLIConfig.Path)
|
||||||
|
require.EqualValues(t, filepath.Join(toolkitRoot, "nvidia-ctk"), cfg.NVIDIACTKConfig.Path)
|
||||||
|
|
||||||
|
if len(tc.expectedCdiSpec) > 0 {
|
||||||
|
cdiSpecFile := filepath.Join(cdiOutputDir, "example.com-class.yaml")
|
||||||
|
require.FileExists(t, cdiSpecFile)
|
||||||
|
info, err := os.Stat(cdiSpecFile)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotZero(t, info.Mode()&0004)
|
||||||
|
contents, err := os.ReadFile(cdiSpecFile)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, strings.ReplaceAll(tc.expectedCdiSpec, "{{ .toolkitRoot }}", toolkitRoot), string(contents))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requireWrappedExecutable(t *testing.T, toolkitRoot string, expectedExecutable string) {
|
||||||
|
requireExecutable(t, toolkitRoot, expectedExecutable)
|
||||||
|
requireExecutable(t, toolkitRoot, expectedExecutable+".real")
|
||||||
|
}
|
||||||
|
|
||||||
|
func requireExecutable(t *testing.T, toolkitRoot string, expectedExecutable string) {
|
||||||
|
executable := filepath.Join(toolkitRoot, expectedExecutable)
|
||||||
|
require.FileExists(t, executable)
|
||||||
|
info, err := os.Lstat(executable)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Zero(t, info.Mode()&os.ModeSymlink)
|
||||||
|
require.NotZero(t, info.Mode()&0111)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requireSymlink(t *testing.T, toolkitRoot string, expectedLink string, expectedTarget string) {
|
||||||
|
link := filepath.Join(toolkitRoot, expectedLink)
|
||||||
|
require.FileExists(t, link)
|
||||||
|
target, err := symlinks.Resolve(link)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedTarget, target)
|
||||||
|
}
|
||||||
@@ -8,12 +8,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container/runtime"
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container/runtime"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/tools/container/toolkit"
|
"github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk-installer/container/toolkit"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -38,6 +38,7 @@ type options struct {
|
|||||||
runtimeArgs string
|
runtimeArgs string
|
||||||
root string
|
root string
|
||||||
pidFile string
|
pidFile string
|
||||||
|
sourceRoot string
|
||||||
|
|
||||||
toolkitOptions toolkit.Options
|
toolkitOptions toolkit.Options
|
||||||
runtimeOptions runtime.Options
|
runtimeOptions runtime.Options
|
||||||
@@ -51,12 +52,46 @@ func (o options) toolkitRoot() string {
|
|||||||
var Version = "development"
|
var Version = "development"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
remainingArgs, root, err := ParseArgs(os.Args)
|
logger := logger.New()
|
||||||
|
|
||||||
|
remainingArgs, root, err := ParseArgs(logger, os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error: unable to parse arguments: %v", err)
|
logger.Errorf("Error: unable to parse arguments: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c := NewApp(logger, root)
|
||||||
|
|
||||||
|
// Run the CLI
|
||||||
|
logger.Infof("Starting %v", c.Name)
|
||||||
|
if err := c.Run(remainingArgs); err != nil {
|
||||||
|
logger.Errorf("error running nvidia-toolkit: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("Completed %v", c.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An app represents the nvidia-ctk-installer.
|
||||||
|
type app struct {
|
||||||
|
logger logger.Interface
|
||||||
|
// defaultRoot stores the root to use if the --root flag is not specified.
|
||||||
|
defaultRoot string
|
||||||
|
|
||||||
|
toolkit *toolkit.Installer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewApp creates the CLI app fro the specified options.
|
||||||
|
// defaultRoot is used as the root if not specified via the --root flag.
|
||||||
|
func NewApp(logger logger.Interface, defaultRoot string) *cli.App {
|
||||||
|
a := app{
|
||||||
|
logger: logger,
|
||||||
|
defaultRoot: defaultRoot,
|
||||||
|
}
|
||||||
|
return a.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a app) build() *cli.App {
|
||||||
options := options{
|
options := options{
|
||||||
toolkitOptions: toolkit.Options{},
|
toolkitOptions: toolkit.Options{},
|
||||||
}
|
}
|
||||||
@@ -68,10 +103,10 @@ func main() {
|
|||||||
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.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.Version = Version
|
||||||
c.Before = func(ctx *cli.Context) error {
|
c.Before = func(ctx *cli.Context) error {
|
||||||
return validateFlags(ctx, &options)
|
return a.Before(ctx, &options)
|
||||||
}
|
}
|
||||||
c.Action = func(ctx *cli.Context) error {
|
c.Action = func(ctx *cli.Context) error {
|
||||||
return Run(ctx, &options)
|
return a.Run(ctx, &options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup flags for the CLI
|
// Setup flags for the CLI
|
||||||
@@ -102,11 +137,18 @@ func main() {
|
|||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "root",
|
Name: "root",
|
||||||
Value: root,
|
Value: a.defaultRoot,
|
||||||
Usage: "the folder where the NVIDIA Container Toolkit is to be installed. It will be installed to `ROOT`/toolkit",
|
Usage: "the folder where the NVIDIA Container Toolkit is to be installed. It will be installed to `ROOT`/toolkit",
|
||||||
Destination: &options.root,
|
Destination: &options.root,
|
||||||
EnvVars: []string{"ROOT"},
|
EnvVars: []string{"ROOT"},
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "source-root",
|
||||||
|
Value: "/",
|
||||||
|
Usage: "The folder where the required toolkit artifacts can be found",
|
||||||
|
Destination: &options.sourceRoot,
|
||||||
|
EnvVars: []string{"SOURCE_ROOT"},
|
||||||
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "pid-file",
|
Name: "pid-file",
|
||||||
Value: defaultPidFile,
|
Value: defaultPidFile,
|
||||||
@@ -119,41 +161,47 @@ func main() {
|
|||||||
c.Flags = append(c.Flags, toolkit.Flags(&options.toolkitOptions)...)
|
c.Flags = append(c.Flags, toolkit.Flags(&options.toolkitOptions)...)
|
||||||
c.Flags = append(c.Flags, runtime.Flags(&options.runtimeOptions)...)
|
c.Flags = append(c.Flags, runtime.Flags(&options.runtimeOptions)...)
|
||||||
|
|
||||||
// Run the CLI
|
return c
|
||||||
log.Infof("Starting %v", c.Name)
|
|
||||||
if err := c.Run(remainingArgs); err != nil {
|
|
||||||
log.Errorf("error running nvidia-toolkit: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Completed %v", c.Name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateFlags(_ *cli.Context, o *options) error {
|
func (a *app) Before(c *cli.Context, o *options) error {
|
||||||
|
a.toolkit = toolkit.NewInstaller(
|
||||||
|
toolkit.WithLogger(a.logger),
|
||||||
|
toolkit.WithSourceRoot(o.sourceRoot),
|
||||||
|
toolkit.WithToolkitRoot(o.toolkitRoot()),
|
||||||
|
)
|
||||||
|
return a.validateFlags(c, o)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) validateFlags(c *cli.Context, o *options) error {
|
||||||
|
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)
|
||||||
|
}
|
||||||
if filepath.Base(o.pidFile) != toolkitPidFilename {
|
if filepath.Base(o.pidFile) != toolkitPidFilename {
|
||||||
return fmt.Errorf("invalid toolkit.pid path %v", o.pidFile)
|
return fmt.Errorf("invalid toolkit.pid path %v", o.pidFile)
|
||||||
}
|
}
|
||||||
if err := toolkit.ValidateOptions(&o.toolkitOptions, o.toolkitRoot()); err != nil {
|
|
||||||
|
if err := a.toolkit.ValidateOptions(&o.toolkitOptions); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := runtime.ValidateOptions(&o.runtimeOptions, o.runtime, o.toolkitRoot()); err != nil {
|
if err := runtime.ValidateOptions(c, &o.runtimeOptions, o.runtime, o.toolkitRoot(), &o.toolkitOptions); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the core logic of the CLI
|
// Run installs the NVIDIA Container Toolkit and updates the requested runtime.
|
||||||
func Run(c *cli.Context, o *options) error {
|
// If the application is run as a daemon, the application waits and unconfigures
|
||||||
err := verifyFlags(o)
|
// the runtime on termination.
|
||||||
if err != nil {
|
func (a *app) Run(c *cli.Context, o *options) error {
|
||||||
return fmt.Errorf("unable to verify flags: %v", err)
|
err := a.initialize(o.pidFile)
|
||||||
}
|
|
||||||
|
|
||||||
err = initialize(o.pidFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to initialize: %v", err)
|
return fmt.Errorf("unable to initialize: %v", err)
|
||||||
}
|
}
|
||||||
defer shutdown(o.pidFile)
|
defer a.shutdown(o.pidFile)
|
||||||
|
|
||||||
if len(o.toolkitOptions.ContainerRuntimeRuntimes.Value()) == 0 {
|
if len(o.toolkitOptions.ContainerRuntimeRuntimes.Value()) == 0 {
|
||||||
lowlevelRuntimePaths, err := runtime.GetLowlevelRuntimePaths(&o.runtimeOptions, o.runtime)
|
lowlevelRuntimePaths, err := runtime.GetLowlevelRuntimePaths(&o.runtimeOptions, o.runtime)
|
||||||
@@ -164,7 +212,8 @@ func Run(c *cli.Context, o *options) error {
|
|||||||
|
|
||||||
o.toolkitOptions.ContainerRuntimeRuntimes = *cli.NewStringSlice(lowlevelRuntimePaths...)
|
o.toolkitOptions.ContainerRuntimeRuntimes = *cli.NewStringSlice(lowlevelRuntimePaths...)
|
||||||
}
|
}
|
||||||
err = toolkit.Install(c, &o.toolkitOptions, o.toolkitRoot())
|
|
||||||
|
err = a.toolkit.Install(c, &o.toolkitOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to install toolkit: %v", err)
|
return fmt.Errorf("unable to install toolkit: %v", err)
|
||||||
}
|
}
|
||||||
@@ -175,7 +224,7 @@ func Run(c *cli.Context, o *options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !o.noDaemon {
|
if !o.noDaemon {
|
||||||
err = waitForSignal()
|
err = a.waitForSignal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to wait for signal: %v", err)
|
return fmt.Errorf("unable to wait for signal: %v", err)
|
||||||
}
|
}
|
||||||
@@ -191,8 +240,8 @@ func Run(c *cli.Context, o *options) error {
|
|||||||
|
|
||||||
// ParseArgs checks if a single positional argument was defined and extracts this the root.
|
// ParseArgs checks if a single positional argument was defined and extracts this the root.
|
||||||
// If no positional arguments are defined, it is assumed that the root is specified as a flag.
|
// If no positional arguments are defined, it is assumed that the root is specified as a flag.
|
||||||
func ParseArgs(args []string) ([]string, string, error) {
|
func ParseArgs(logger logger.Interface, args []string) ([]string, string, error) {
|
||||||
log.Infof("Parsing arguments")
|
logger.Infof("Parsing arguments")
|
||||||
|
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
return args, "", nil
|
return args, "", nil
|
||||||
@@ -217,20 +266,8 @@ func ParseArgs(args []string) ([]string, string, error) {
|
|||||||
return nil, "", fmt.Errorf("unexpected positional argument(s) %v", args[2:lastPositionalArg+1])
|
return nil, "", fmt.Errorf("unexpected positional argument(s) %v", args[2:lastPositionalArg+1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyFlags(o *options) error {
|
func (a *app) initialize(pidFile string) error {
|
||||||
log.Infof("Verifying Flags")
|
a.logger.Infof("Initializing")
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func initialize(pidFile string) error {
|
|
||||||
log.Infof("Initializing")
|
|
||||||
|
|
||||||
if dir := filepath.Dir(pidFile); dir != "" {
|
if dir := filepath.Dir(pidFile); dir != "" {
|
||||||
err := os.MkdirAll(dir, 0755)
|
err := os.MkdirAll(dir, 0755)
|
||||||
@@ -246,8 +283,8 @@ func initialize(pidFile string) error {
|
|||||||
|
|
||||||
err = unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB)
|
err = unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("Unable to get exclusive lock on '%v'", pidFile)
|
a.logger.Warningf("Unable to get exclusive lock on '%v'", pidFile)
|
||||||
log.Warningf("This normally means an instance of the NVIDIA toolkit Container is already running, aborting")
|
a.logger.Warningf("This normally means an instance of the NVIDIA toolkit Container is already running, aborting")
|
||||||
return fmt.Errorf("unable to get flock on pidfile: %v", err)
|
return fmt.Errorf("unable to get flock on pidfile: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,8 +301,8 @@ func initialize(pidFile string) error {
|
|||||||
case <-waitingForSignal:
|
case <-waitingForSignal:
|
||||||
signalReceived <- true
|
signalReceived <- true
|
||||||
default:
|
default:
|
||||||
log.Infof("Signal received, exiting early")
|
a.logger.Infof("Signal received, exiting early")
|
||||||
shutdown(pidFile)
|
a.shutdown(pidFile)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -273,18 +310,18 @@ func initialize(pidFile string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForSignal() error {
|
func (a *app) waitForSignal() error {
|
||||||
log.Infof("Waiting for signal")
|
a.logger.Infof("Waiting for signal")
|
||||||
waitingForSignal <- true
|
waitingForSignal <- true
|
||||||
<-signalReceived
|
<-signalReceived
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func shutdown(pidFile string) {
|
func (a *app) shutdown(pidFile string) {
|
||||||
log.Infof("Shutting Down")
|
a.logger.Infof("Shutting Down")
|
||||||
|
|
||||||
err := os.Remove(pidFile)
|
err := os.Remove(pidFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("Unable to remove pidfile: %v", err)
|
a.logger.Warningf("Unable to remove pidfile: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
516
cmd/nvidia-ctk-installer/main_test.go
Normal file
516
cmd/nvidia-ctk-installer/main_test.go
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
/**
|
||||||
|
# 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"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseArgs(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
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(logger, 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApp(t *testing.T) {
|
||||||
|
t.Setenv("__NVCT_TESTING_DEVICES_ARE_FILES", "true")
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
|
||||||
|
moduleRoot, err := test.GetModuleRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
artifactRoot := filepath.Join(moduleRoot, "testdata", "installer", "artifacts")
|
||||||
|
hostRoot := filepath.Join(moduleRoot, "testdata", "lookup", "rootfs-1")
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
args []string
|
||||||
|
expectedToolkitConfig string
|
||||||
|
expectedRuntimeConfig string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "no args",
|
||||||
|
expectedToolkitConfig: `accept-nvidia-visible-devices-as-volume-mounts = false
|
||||||
|
accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||||
|
disable-require = false
|
||||||
|
supported-driver-capabilities = "compat32,compute,display,graphics,ngx,utility,video"
|
||||||
|
swarm-resource = ""
|
||||||
|
|
||||||
|
[nvidia-container-cli]
|
||||||
|
debug = ""
|
||||||
|
environment = []
|
||||||
|
ldcache = ""
|
||||||
|
ldconfig = "@/run/nvidia/driver/sbin/ldconfig"
|
||||||
|
load-kmods = true
|
||||||
|
no-cgroups = false
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-cli"
|
||||||
|
root = "/run/nvidia/driver"
|
||||||
|
user = ""
|
||||||
|
|
||||||
|
[nvidia-container-runtime]
|
||||||
|
debug = "/dev/null"
|
||||||
|
log-level = "info"
|
||||||
|
mode = "auto"
|
||||||
|
runtimes = ["docker-runc", "runc", "crun"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.cdi]
|
||||||
|
annotation-prefixes = ["cdi.k8s.io/"]
|
||||||
|
default-kind = "nvidia.com/gpu"
|
||||||
|
spec-dirs = ["/etc/cdi", "/var/run/cdi"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.csv]
|
||||||
|
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.jit-cdi]
|
||||||
|
load-kernel-modules = ["nvidia", "nvidia-uvm", "nvidia-modeset"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime-hook]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime-hook"
|
||||||
|
skip-mode-detection = true
|
||||||
|
|
||||||
|
[nvidia-ctk]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-ctk"
|
||||||
|
`,
|
||||||
|
expectedRuntimeConfig: `{
|
||||||
|
"default-runtime": "nvidia",
|
||||||
|
"runtimes": {
|
||||||
|
"nvidia": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime"
|
||||||
|
},
|
||||||
|
"nvidia-cdi": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.cdi"
|
||||||
|
},
|
||||||
|
"nvidia-legacy": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.legacy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "CDI enabled enables CDI in docker",
|
||||||
|
args: []string{"--cdi-enabled", "--create-device-nodes=none"},
|
||||||
|
expectedToolkitConfig: `accept-nvidia-visible-devices-as-volume-mounts = false
|
||||||
|
accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||||
|
disable-require = false
|
||||||
|
supported-driver-capabilities = "compat32,compute,display,graphics,ngx,utility,video"
|
||||||
|
swarm-resource = ""
|
||||||
|
|
||||||
|
[nvidia-container-cli]
|
||||||
|
debug = ""
|
||||||
|
environment = []
|
||||||
|
ldcache = ""
|
||||||
|
ldconfig = "@/run/nvidia/driver/sbin/ldconfig"
|
||||||
|
load-kmods = true
|
||||||
|
no-cgroups = false
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-cli"
|
||||||
|
root = "/run/nvidia/driver"
|
||||||
|
user = ""
|
||||||
|
|
||||||
|
[nvidia-container-runtime]
|
||||||
|
debug = "/dev/null"
|
||||||
|
log-level = "info"
|
||||||
|
mode = "auto"
|
||||||
|
runtimes = ["docker-runc", "runc", "crun"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.cdi]
|
||||||
|
annotation-prefixes = ["cdi.k8s.io/"]
|
||||||
|
default-kind = "nvidia.com/gpu"
|
||||||
|
spec-dirs = ["/etc/cdi", "/var/run/cdi"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.csv]
|
||||||
|
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.jit-cdi]
|
||||||
|
load-kernel-modules = ["nvidia", "nvidia-uvm", "nvidia-modeset"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime-hook]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime-hook"
|
||||||
|
skip-mode-detection = true
|
||||||
|
|
||||||
|
[nvidia-ctk]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-ctk"
|
||||||
|
`,
|
||||||
|
expectedRuntimeConfig: `{
|
||||||
|
"default-runtime": "nvidia",
|
||||||
|
"features": {
|
||||||
|
"cdi": true
|
||||||
|
},
|
||||||
|
"runtimes": {
|
||||||
|
"nvidia": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime"
|
||||||
|
},
|
||||||
|
"nvidia-cdi": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.cdi"
|
||||||
|
},
|
||||||
|
"nvidia-legacy": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.legacy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "--enable-cdi-in-runtime=false overrides --cdi-enabled in Docker",
|
||||||
|
args: []string{"--cdi-enabled", "--create-device-nodes=none", "--enable-cdi-in-runtime=false"},
|
||||||
|
expectedToolkitConfig: `accept-nvidia-visible-devices-as-volume-mounts = false
|
||||||
|
accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||||
|
disable-require = false
|
||||||
|
supported-driver-capabilities = "compat32,compute,display,graphics,ngx,utility,video"
|
||||||
|
swarm-resource = ""
|
||||||
|
|
||||||
|
[nvidia-container-cli]
|
||||||
|
debug = ""
|
||||||
|
environment = []
|
||||||
|
ldcache = ""
|
||||||
|
ldconfig = "@/run/nvidia/driver/sbin/ldconfig"
|
||||||
|
load-kmods = true
|
||||||
|
no-cgroups = false
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-cli"
|
||||||
|
root = "/run/nvidia/driver"
|
||||||
|
user = ""
|
||||||
|
|
||||||
|
[nvidia-container-runtime]
|
||||||
|
debug = "/dev/null"
|
||||||
|
log-level = "info"
|
||||||
|
mode = "auto"
|
||||||
|
runtimes = ["docker-runc", "runc", "crun"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.cdi]
|
||||||
|
annotation-prefixes = ["cdi.k8s.io/"]
|
||||||
|
default-kind = "nvidia.com/gpu"
|
||||||
|
spec-dirs = ["/etc/cdi", "/var/run/cdi"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.csv]
|
||||||
|
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.jit-cdi]
|
||||||
|
load-kernel-modules = ["nvidia", "nvidia-uvm", "nvidia-modeset"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime-hook]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime-hook"
|
||||||
|
skip-mode-detection = true
|
||||||
|
|
||||||
|
[nvidia-ctk]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-ctk"
|
||||||
|
`,
|
||||||
|
expectedRuntimeConfig: `{
|
||||||
|
"default-runtime": "nvidia",
|
||||||
|
"runtimes": {
|
||||||
|
"nvidia": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime"
|
||||||
|
},
|
||||||
|
"nvidia-cdi": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.cdi"
|
||||||
|
},
|
||||||
|
"nvidia-legacy": {
|
||||||
|
"args": [],
|
||||||
|
"path": "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.legacy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "CDI enabled enables CDI in containerd",
|
||||||
|
args: []string{"--cdi-enabled", "--runtime=containerd"},
|
||||||
|
expectedToolkitConfig: `accept-nvidia-visible-devices-as-volume-mounts = false
|
||||||
|
accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||||
|
disable-require = false
|
||||||
|
supported-driver-capabilities = "compat32,compute,display,graphics,ngx,utility,video"
|
||||||
|
swarm-resource = ""
|
||||||
|
|
||||||
|
[nvidia-container-cli]
|
||||||
|
debug = ""
|
||||||
|
environment = []
|
||||||
|
ldcache = ""
|
||||||
|
ldconfig = "@/run/nvidia/driver/sbin/ldconfig"
|
||||||
|
load-kmods = true
|
||||||
|
no-cgroups = false
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-cli"
|
||||||
|
root = "/run/nvidia/driver"
|
||||||
|
user = ""
|
||||||
|
|
||||||
|
[nvidia-container-runtime]
|
||||||
|
debug = "/dev/null"
|
||||||
|
log-level = "info"
|
||||||
|
mode = "auto"
|
||||||
|
runtimes = ["docker-runc", "runc", "crun"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.cdi]
|
||||||
|
annotation-prefixes = ["cdi.k8s.io/"]
|
||||||
|
default-kind = "nvidia.com/gpu"
|
||||||
|
spec-dirs = ["/etc/cdi", "/var/run/cdi"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.csv]
|
||||||
|
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.jit-cdi]
|
||||||
|
load-kernel-modules = ["nvidia", "nvidia-uvm", "nvidia-modeset"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime-hook]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime-hook"
|
||||||
|
skip-mode-detection = true
|
||||||
|
|
||||||
|
[nvidia-ctk]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-ctk"
|
||||||
|
`,
|
||||||
|
expectedRuntimeConfig: `version = 2
|
||||||
|
|
||||||
|
[plugins]
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri"]
|
||||||
|
enable_cdi = true
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd]
|
||||||
|
default_runtime_name = "nvidia"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
|
||||||
|
privileged_without_host_devices = false
|
||||||
|
runtime_engine = ""
|
||||||
|
runtime_root = ""
|
||||||
|
runtime_type = "io.containerd.runc.v2"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]
|
||||||
|
BinaryName = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia-cdi]
|
||||||
|
privileged_without_host_devices = false
|
||||||
|
runtime_engine = ""
|
||||||
|
runtime_root = ""
|
||||||
|
runtime_type = "io.containerd.runc.v2"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia-cdi.options]
|
||||||
|
BinaryName = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.cdi"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia-legacy]
|
||||||
|
privileged_without_host_devices = false
|
||||||
|
runtime_engine = ""
|
||||||
|
runtime_root = ""
|
||||||
|
runtime_type = "io.containerd.runc.v2"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia-legacy.options]
|
||||||
|
BinaryName = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.legacy"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "--enable-cdi-in-runtime=false overrides --cdi-enabled in containerd",
|
||||||
|
args: []string{"--cdi-enabled", "--create-device-nodes=none", "--enable-cdi-in-runtime=false", "--runtime=containerd"},
|
||||||
|
expectedToolkitConfig: `accept-nvidia-visible-devices-as-volume-mounts = false
|
||||||
|
accept-nvidia-visible-devices-envvar-when-unprivileged = true
|
||||||
|
disable-require = false
|
||||||
|
supported-driver-capabilities = "compat32,compute,display,graphics,ngx,utility,video"
|
||||||
|
swarm-resource = ""
|
||||||
|
|
||||||
|
[nvidia-container-cli]
|
||||||
|
debug = ""
|
||||||
|
environment = []
|
||||||
|
ldcache = ""
|
||||||
|
ldconfig = "@/run/nvidia/driver/sbin/ldconfig"
|
||||||
|
load-kmods = true
|
||||||
|
no-cgroups = false
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-cli"
|
||||||
|
root = "/run/nvidia/driver"
|
||||||
|
user = ""
|
||||||
|
|
||||||
|
[nvidia-container-runtime]
|
||||||
|
debug = "/dev/null"
|
||||||
|
log-level = "info"
|
||||||
|
mode = "auto"
|
||||||
|
runtimes = ["docker-runc", "runc", "crun"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.cdi]
|
||||||
|
annotation-prefixes = ["cdi.k8s.io/"]
|
||||||
|
default-kind = "nvidia.com/gpu"
|
||||||
|
spec-dirs = ["/etc/cdi", "/var/run/cdi"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.csv]
|
||||||
|
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.jit-cdi]
|
||||||
|
load-kernel-modules = ["nvidia", "nvidia-uvm", "nvidia-modeset"]
|
||||||
|
|
||||||
|
[nvidia-container-runtime-hook]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime-hook"
|
||||||
|
skip-mode-detection = true
|
||||||
|
|
||||||
|
[nvidia-ctk]
|
||||||
|
path = "{{ .toolkitRoot }}/toolkit/nvidia-ctk"
|
||||||
|
`,
|
||||||
|
expectedRuntimeConfig: `version = 2
|
||||||
|
|
||||||
|
[plugins]
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri"]
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd]
|
||||||
|
default_runtime_name = "nvidia"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
|
||||||
|
privileged_without_host_devices = false
|
||||||
|
runtime_engine = ""
|
||||||
|
runtime_root = ""
|
||||||
|
runtime_type = "io.containerd.runc.v2"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]
|
||||||
|
BinaryName = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia-cdi]
|
||||||
|
privileged_without_host_devices = false
|
||||||
|
runtime_engine = ""
|
||||||
|
runtime_root = ""
|
||||||
|
runtime_type = "io.containerd.runc.v2"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia-cdi.options]
|
||||||
|
BinaryName = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.cdi"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia-legacy]
|
||||||
|
privileged_without_host_devices = false
|
||||||
|
runtime_engine = ""
|
||||||
|
runtime_root = ""
|
||||||
|
runtime_type = "io.containerd.runc.v2"
|
||||||
|
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia-legacy.options]
|
||||||
|
BinaryName = "{{ .toolkitRoot }}/toolkit/nvidia-container-runtime.legacy"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
testRoot := t.TempDir()
|
||||||
|
|
||||||
|
cdiOutputDir := filepath.Join(testRoot, "/var/run/cdi")
|
||||||
|
runtimeConfigFile := filepath.Join(testRoot, "config.file")
|
||||||
|
|
||||||
|
toolkitRoot := filepath.Join(testRoot, "toolkit-test")
|
||||||
|
toolkitConfigFile := filepath.Join(toolkitRoot, "toolkit/.config/nvidia-container-runtime/config.toml")
|
||||||
|
|
||||||
|
app := NewApp(logger, toolkitRoot)
|
||||||
|
|
||||||
|
testArgs := []string{
|
||||||
|
"nvidia-ctk-installer",
|
||||||
|
"--no-daemon",
|
||||||
|
"--cdi-output-dir=" + cdiOutputDir,
|
||||||
|
"--config=" + runtimeConfigFile,
|
||||||
|
"--create-device-nodes=none",
|
||||||
|
"--driver-root-ctr-path=" + hostRoot,
|
||||||
|
"--pid-file=" + filepath.Join(testRoot, "toolkit.pid"),
|
||||||
|
"--restart-mode=none",
|
||||||
|
"--source-root=" + filepath.Join(artifactRoot, "deb"),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(append(testArgs, tc.args...))
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.FileExists(t, toolkitConfigFile)
|
||||||
|
toolkitConfigFileContents, err := os.ReadFile(toolkitConfigFile)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, strings.ReplaceAll(tc.expectedToolkitConfig, "{{ .toolkitRoot }}", toolkitRoot), string(toolkitConfigFileContents))
|
||||||
|
|
||||||
|
require.FileExists(t, runtimeConfigFile)
|
||||||
|
runtimeConfigFileContents, err := os.ReadFile(runtimeConfigFile)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, strings.ReplaceAll(tc.expectedRuntimeConfig, "{{ .toolkitRoot }}", toolkitRoot), string(runtimeConfigFileContents))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -25,6 +25,8 @@ import (
|
|||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
cdi "tags.cncf.io/container-device-interface/pkg/parser"
|
cdi "tags.cncf.io/container-device-interface/pkg/parser"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/go-nvml/pkg/nvml"
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/platform-support/tegra/csv"
|
||||||
@@ -60,6 +62,9 @@ type options struct {
|
|||||||
files cli.StringSlice
|
files cli.StringSlice
|
||||||
ignorePatterns cli.StringSlice
|
ignorePatterns cli.StringSlice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the following are used for dependency injection during spec generation.
|
||||||
|
nvmllib nvml.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommand constructs a generate-cdi command with the specified logger
|
// NewCommand constructs a generate-cdi command with the specified logger
|
||||||
@@ -104,10 +109,12 @@ func (m command) build() *cli.Command {
|
|||||||
Destination: &opts.format,
|
Destination: &opts.format,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "mode",
|
Name: "mode",
|
||||||
Aliases: []string{"discovery-mode"},
|
Aliases: []string{"discovery-mode"},
|
||||||
Usage: "The mode to use when discovering the available entities. One of [auto | nvml | wsl]. If mode is set to 'auto' the mode will be determined based on the system configuration.",
|
Usage: "The mode to use when discovering the available entities. " +
|
||||||
Value: nvcdi.ModeAuto,
|
"One of [" + strings.Join(nvcdi.AllModes[string](), " | ") + "]. " +
|
||||||
|
"If mode is set to 'auto' the mode will be determined based on the system configuration.",
|
||||||
|
Value: string(nvcdi.ModeAuto),
|
||||||
Destination: &opts.mode,
|
Destination: &opts.mode,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@@ -184,13 +191,7 @@ func (m command) validateFlags(c *cli.Context, opts *options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts.mode = strings.ToLower(opts.mode)
|
opts.mode = strings.ToLower(opts.mode)
|
||||||
switch opts.mode {
|
if !nvcdi.IsValidMode(opts.mode) {
|
||||||
case nvcdi.ModeAuto:
|
|
||||||
case nvcdi.ModeCSV:
|
|
||||||
case nvcdi.ModeNvml:
|
|
||||||
case nvcdi.ModeWsl:
|
|
||||||
case nvcdi.ModeManagement:
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("invalid discovery mode: %v", opts.mode)
|
return fmt.Errorf("invalid discovery mode: %v", opts.mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,6 +274,8 @@ func (m command) generateSpec(opts *options) (spec.Interface, error) {
|
|||||||
nvcdi.WithLibrarySearchPaths(opts.librarySearchPaths.Value()),
|
nvcdi.WithLibrarySearchPaths(opts.librarySearchPaths.Value()),
|
||||||
nvcdi.WithCSVFiles(opts.csv.files.Value()),
|
nvcdi.WithCSVFiles(opts.csv.files.Value()),
|
||||||
nvcdi.WithCSVIgnorePatterns(opts.csv.ignorePatterns.Value()),
|
nvcdi.WithCSVIgnorePatterns(opts.csv.ignorePatterns.Value()),
|
||||||
|
// We set the following to allow for dependency injection:
|
||||||
|
nvcdi.WithNvmlLib(opts.nvmllib),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create CDI library: %v", err)
|
return nil, fmt.Errorf("failed to create CDI library: %v", err)
|
||||||
|
|||||||
157
cmd/nvidia-ctk/cdi/generate/generate_test.go
Normal file
157
cmd/nvidia-ctk/cdi/generate/generate_test.go
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/**
|
||||||
|
# Copyright (c) 2025, 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 (
|
||||||
|
"bytes"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/go-nvml/pkg/nvml"
|
||||||
|
"github.com/NVIDIA/go-nvml/pkg/nvml/mock/dgxa100"
|
||||||
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateSpec(t *testing.T) {
|
||||||
|
t.Setenv("__NVCT_TESTING_DEVICES_ARE_FILES", "true")
|
||||||
|
moduleRoot, err := test.GetModuleRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
driverRoot := filepath.Join(moduleRoot, "testdata", "lookup", "rootfs-1")
|
||||||
|
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
options options
|
||||||
|
expectedValidateError error
|
||||||
|
expectedOptions options
|
||||||
|
expectedError error
|
||||||
|
expectedSpec string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "default",
|
||||||
|
options: options{
|
||||||
|
format: "yaml",
|
||||||
|
mode: "nvml",
|
||||||
|
vendor: "example.com",
|
||||||
|
class: "device",
|
||||||
|
driverRoot: driverRoot,
|
||||||
|
},
|
||||||
|
expectedOptions: options{
|
||||||
|
format: "yaml",
|
||||||
|
mode: "nvml",
|
||||||
|
vendor: "example.com",
|
||||||
|
class: "device",
|
||||||
|
nvidiaCDIHookPath: "/usr/bin/nvidia-cdi-hook",
|
||||||
|
driverRoot: driverRoot,
|
||||||
|
},
|
||||||
|
expectedSpec: `---
|
||||||
|
cdiVersion: 0.5.0
|
||||||
|
containerEdits:
|
||||||
|
deviceNodes:
|
||||||
|
- hostPath: {{ .driverRoot }}/dev/nvidiactl
|
||||||
|
path: /dev/nvidiactl
|
||||||
|
env:
|
||||||
|
- NVIDIA_VISIBLE_DEVICES=void
|
||||||
|
hooks:
|
||||||
|
- args:
|
||||||
|
- nvidia-cdi-hook
|
||||||
|
- create-symlinks
|
||||||
|
- --link
|
||||||
|
- libcuda.so.1::/lib/x86_64-linux-gnu/libcuda.so
|
||||||
|
hookName: createContainer
|
||||||
|
path: /usr/bin/nvidia-cdi-hook
|
||||||
|
- args:
|
||||||
|
- nvidia-cdi-hook
|
||||||
|
- enable-cuda-compat
|
||||||
|
- --host-driver-version=999.88.77
|
||||||
|
hookName: createContainer
|
||||||
|
path: /usr/bin/nvidia-cdi-hook
|
||||||
|
- args:
|
||||||
|
- nvidia-cdi-hook
|
||||||
|
- update-ldcache
|
||||||
|
- --folder
|
||||||
|
- /lib/x86_64-linux-gnu
|
||||||
|
hookName: createContainer
|
||||||
|
path: /usr/bin/nvidia-cdi-hook
|
||||||
|
mounts:
|
||||||
|
- containerPath: /lib/x86_64-linux-gnu/libcuda.so.999.88.77
|
||||||
|
hostPath: {{ .driverRoot }}/lib/x86_64-linux-gnu/libcuda.so.999.88.77
|
||||||
|
options:
|
||||||
|
- ro
|
||||||
|
- nosuid
|
||||||
|
- nodev
|
||||||
|
- bind
|
||||||
|
devices:
|
||||||
|
- containerEdits:
|
||||||
|
deviceNodes:
|
||||||
|
- hostPath: {{ .driverRoot }}/dev/nvidia0
|
||||||
|
path: /dev/nvidia0
|
||||||
|
name: "0"
|
||||||
|
- containerEdits:
|
||||||
|
deviceNodes:
|
||||||
|
- hostPath: {{ .driverRoot }}/dev/nvidia0
|
||||||
|
path: /dev/nvidia0
|
||||||
|
name: all
|
||||||
|
kind: example.com/device
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
c := command{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.validateFlags(nil, &tc.options)
|
||||||
|
require.ErrorIs(t, err, tc.expectedValidateError)
|
||||||
|
require.EqualValues(t, tc.expectedOptions, tc.options)
|
||||||
|
|
||||||
|
// Set up a mock server, reusing the DGX A100 mock.
|
||||||
|
server := dgxa100.New()
|
||||||
|
// Override the driver version to match the version in our mock filesystem.
|
||||||
|
server.SystemGetDriverVersionFunc = func() (string, nvml.Return) {
|
||||||
|
return "999.88.77", nvml.SUCCESS
|
||||||
|
}
|
||||||
|
// Set the device count to 1 explicitly since we only have a single device node.
|
||||||
|
server.DeviceGetCountFunc = func() (int, nvml.Return) {
|
||||||
|
return 1, nvml.SUCCESS
|
||||||
|
}
|
||||||
|
for _, d := range server.Devices {
|
||||||
|
// TODO: This is not implemented in the mock.
|
||||||
|
(d.(*dgxa100.Device)).GetMaxMigDeviceCountFunc = func() (int, nvml.Return) {
|
||||||
|
return 0, nvml.SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tc.options.nvmllib = server
|
||||||
|
|
||||||
|
spec, err := c.generateSpec(&tc.options)
|
||||||
|
require.ErrorIs(t, err, tc.expectedError)
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err = spec.WriteTo(&buf)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, strings.ReplaceAll(tc.expectedSpec, "{{ .driverRoot }}", driverRoot), buf.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -163,7 +163,7 @@ func (m command) build() *cli.Command {
|
|||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "cdi.enabled",
|
Name: "cdi.enabled",
|
||||||
Aliases: []string{"cdi.enable"},
|
Aliases: []string{"cdi.enable", "enable-cdi"},
|
||||||
Usage: "Enable CDI in the configured runtime",
|
Usage: "Enable CDI in the configured runtime",
|
||||||
Destination: &config.cdi.enabled,
|
Destination: &config.cdi.enabled,
|
||||||
},
|
},
|
||||||
@@ -225,6 +225,17 @@ func (m command) validateFlags(c *cli.Context, config *config) error {
|
|||||||
return fmt.Errorf("unrecognized Config Source: %v", config.configSource)
|
return fmt.Errorf("unrecognized Config Source: %v", config.configSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.configFilePath == "" {
|
||||||
|
switch config.runtime {
|
||||||
|
case "containerd":
|
||||||
|
config.configFilePath = defaultContainerdConfigFilePath
|
||||||
|
case "crio":
|
||||||
|
config.configFilePath = defaultCrioConfigFilePath
|
||||||
|
case "docker":
|
||||||
|
config.configFilePath = defaultDockerConfigFilePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,9 +252,6 @@ func (m command) configureWrapper(c *cli.Context, config *config) error {
|
|||||||
|
|
||||||
// configureConfigFile updates the specified container engine config file to enable the NVIDIA runtime.
|
// configureConfigFile updates the specified container engine config file to enable the NVIDIA runtime.
|
||||||
func (m command) configureConfigFile(c *cli.Context, config *config) error {
|
func (m command) configureConfigFile(c *cli.Context, config *config) error {
|
||||||
configFilePath := config.resolveConfigFilePath()
|
|
||||||
|
|
||||||
var err error
|
|
||||||
configSource, err := config.resolveConfigSource()
|
configSource, err := config.resolveConfigSource()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -254,19 +262,19 @@ func (m command) configureConfigFile(c *cli.Context, config *config) error {
|
|||||||
case "containerd":
|
case "containerd":
|
||||||
cfg, err = containerd.New(
|
cfg, err = containerd.New(
|
||||||
containerd.WithLogger(m.logger),
|
containerd.WithLogger(m.logger),
|
||||||
containerd.WithPath(configFilePath),
|
containerd.WithPath(config.configFilePath),
|
||||||
containerd.WithConfigSource(configSource),
|
containerd.WithConfigSource(configSource),
|
||||||
)
|
)
|
||||||
case "crio":
|
case "crio":
|
||||||
cfg, err = crio.New(
|
cfg, err = crio.New(
|
||||||
crio.WithLogger(m.logger),
|
crio.WithLogger(m.logger),
|
||||||
crio.WithPath(configFilePath),
|
crio.WithPath(config.configFilePath),
|
||||||
crio.WithConfigSource(configSource),
|
crio.WithConfigSource(configSource),
|
||||||
)
|
)
|
||||||
case "docker":
|
case "docker":
|
||||||
cfg, err = docker.New(
|
cfg, err = docker.New(
|
||||||
docker.WithLogger(m.logger),
|
docker.WithLogger(m.logger),
|
||||||
docker.WithPath(configFilePath),
|
docker.WithPath(config.configFilePath),
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unrecognized runtime '%v'", config.runtime)
|
err = fmt.Errorf("unrecognized runtime '%v'", config.runtime)
|
||||||
@@ -284,9 +292,8 @@ func (m command) configureConfigFile(c *cli.Context, config *config) error {
|
|||||||
return fmt.Errorf("unable to update config: %v", err)
|
return fmt.Errorf("unable to update config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = enableCDI(config, cfg)
|
if config.cdi.enabled {
|
||||||
if err != nil {
|
cfg.EnableCDI()
|
||||||
return fmt.Errorf("failed to enable CDI in %s: %w", config.runtime, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outputPath := config.getOutputConfigPath()
|
outputPath := config.getOutputConfigPath()
|
||||||
@@ -307,22 +314,6 @@ func (m command) configureConfigFile(c *cli.Context, config *config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveConfigFilePath returns the default config file path for the configured container engine
|
|
||||||
func (c *config) resolveConfigFilePath() string {
|
|
||||||
if c.configFilePath != "" {
|
|
||||||
return c.configFilePath
|
|
||||||
}
|
|
||||||
switch c.runtime {
|
|
||||||
case "containerd":
|
|
||||||
return defaultContainerdConfigFilePath
|
|
||||||
case "crio":
|
|
||||||
return defaultCrioConfigFilePath
|
|
||||||
case "docker":
|
|
||||||
return defaultDockerConfigFilePath
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveConfigSource returns the default config source or the user provided config source
|
// resolveConfigSource returns the default config source or the user provided config source
|
||||||
func (c *config) resolveConfigSource() (toml.Loader, error) {
|
func (c *config) resolveConfigSource() (toml.Loader, error) {
|
||||||
switch c.configSource {
|
switch c.configSource {
|
||||||
@@ -351,7 +342,7 @@ func (c *config) getOutputConfigPath() string {
|
|||||||
if c.dryRun {
|
if c.dryRun {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return c.resolveConfigFilePath()
|
return c.configFilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
// configureOCIHook creates and configures the OCI hook for the NVIDIA runtime
|
// configureOCIHook creates and configures the OCI hook for the NVIDIA runtime
|
||||||
@@ -362,19 +353,3 @@ func (m *command) configureOCIHook(c *cli.Context, config *config) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// enableCDI enables the use of CDI in the corresponding container engine
|
|
||||||
func enableCDI(config *config, cfg engine.Interface) error {
|
|
||||||
if !config.cdi.enabled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
switch config.runtime {
|
|
||||||
case "containerd":
|
|
||||||
cfg.Set("enable_cdi", true)
|
|
||||||
case "docker":
|
|
||||||
cfg.Set("features", map[string]bool{"cdi": true})
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("enabling CDI in %s is not supported", config.runtime)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,12 +19,8 @@ package devchar
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
@@ -44,7 +40,6 @@ type config struct {
|
|||||||
devCharPath string
|
devCharPath string
|
||||||
driverRoot string
|
driverRoot string
|
||||||
dryRun bool
|
dryRun bool
|
||||||
watch bool
|
|
||||||
createAll bool
|
createAll bool
|
||||||
createDeviceNodes bool
|
createDeviceNodes bool
|
||||||
loadKernelModules bool
|
loadKernelModules bool
|
||||||
@@ -89,13 +84,6 @@ func (m command) build() *cli.Command {
|
|||||||
Destination: &cfg.driverRoot,
|
Destination: &cfg.driverRoot,
|
||||||
EnvVars: []string{"NVIDIA_DRIVER_ROOT", "DRIVER_ROOT"},
|
EnvVars: []string{"NVIDIA_DRIVER_ROOT", "DRIVER_ROOT"},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "watch",
|
|
||||||
Usage: "If set, the command will watch for changes to the driver root and recreate the symlinks when changes are detected.",
|
|
||||||
Value: false,
|
|
||||||
Destination: &cfg.watch,
|
|
||||||
EnvVars: []string{"WATCH"},
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "create-all",
|
Name: "create-all",
|
||||||
Usage: "Create all possible /dev/char symlinks instead of limiting these to existing device nodes.",
|
Usage: "Create all possible /dev/char symlinks instead of limiting these to existing device nodes.",
|
||||||
@@ -127,7 +115,7 @@ func (m command) build() *cli.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m command) validateFlags(r *cli.Context, cfg *config) error {
|
func (m command) validateFlags(r *cli.Context, cfg *config) error {
|
||||||
if cfg.createAll && cfg.watch {
|
if cfg.createAll {
|
||||||
return fmt.Errorf("create-all and watch are mutually exclusive")
|
return fmt.Errorf("create-all and watch are mutually exclusive")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,19 +133,6 @@ func (m command) validateFlags(r *cli.Context, cfg *config) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m command) run(c *cli.Context, cfg *config) error {
|
func (m command) run(c *cli.Context, cfg *config) error {
|
||||||
var watcher *fsnotify.Watcher
|
|
||||||
var sigs chan os.Signal
|
|
||||||
|
|
||||||
if cfg.watch {
|
|
||||||
watcher, err := newFSWatcher(filepath.Join(cfg.driverRoot, "dev"))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create FS watcher: %v", err)
|
|
||||||
}
|
|
||||||
defer watcher.Close()
|
|
||||||
|
|
||||||
sigs = newOSWatcher(syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
|
||||||
}
|
|
||||||
|
|
||||||
l, err := NewSymlinkCreator(
|
l, err := NewSymlinkCreator(
|
||||||
WithLogger(m.logger),
|
WithLogger(m.logger),
|
||||||
WithDevCharPath(cfg.devCharPath),
|
WithDevCharPath(cfg.devCharPath),
|
||||||
@@ -171,47 +146,11 @@ func (m command) run(c *cli.Context, cfg *config) error {
|
|||||||
return fmt.Errorf("failed to create symlink creator: %v", err)
|
return fmt.Errorf("failed to create symlink creator: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
create:
|
|
||||||
err = l.CreateLinks()
|
err = l.CreateLinks()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create links: %v", err)
|
return fmt.Errorf("failed to create links: %v", err)
|
||||||
}
|
}
|
||||||
if !cfg.watch {
|
return nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
|
|
||||||
case event := <-watcher.Events:
|
|
||||||
deviceNode := filepath.Base(event.Name)
|
|
||||||
if !strings.HasPrefix(deviceNode, "nvidia") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
|
||||||
m.logger.Infof("%s created, restarting.", event.Name)
|
|
||||||
goto create
|
|
||||||
}
|
|
||||||
if event.Op&fsnotify.Create == fsnotify.Remove {
|
|
||||||
m.logger.Infof("%s removed. Ignoring", event.Name)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch for any other fs errors and log them.
|
|
||||||
case err := <-watcher.Errors:
|
|
||||||
m.logger.Errorf("inotify: %s", err)
|
|
||||||
|
|
||||||
// React to signals
|
|
||||||
case s := <-sigs:
|
|
||||||
switch s {
|
|
||||||
case syscall.SIGHUP:
|
|
||||||
m.logger.Infof("Received SIGHUP, recreating symlinks.")
|
|
||||||
goto create
|
|
||||||
default:
|
|
||||||
m.logger.Infof("Received signal %q, shutting down.", s)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type linkCreator struct {
|
type linkCreator struct {
|
||||||
@@ -399,27 +338,3 @@ type deviceNode struct {
|
|||||||
func (d deviceNode) devCharName() string {
|
func (d deviceNode) devCharName() string {
|
||||||
return fmt.Sprintf("%d:%d", d.major, d.minor)
|
return fmt.Sprintf("%d:%d", d.major, d.minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFSWatcher(files ...string) (*fsnotify.Watcher, error) {
|
|
||||||
watcher, err := fsnotify.NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range files {
|
|
||||||
err = watcher.Add(f)
|
|
||||||
if err != nil {
|
|
||||||
watcher.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return watcher, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOSWatcher(sigs ...os.Signal) chan os.Signal {
|
|
||||||
sigChan := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigChan, sigs...)
|
|
||||||
|
|
||||||
return sigChan
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
ARG GOLANG_VERSION=x.x.x
|
ARG GOLANG_VERSION=x.x.x
|
||||||
|
|
||||||
FROM nvidia/cuda:12.6.2-base-ubuntu20.04
|
FROM nvcr.io/nvidia/cuda:12.8.0-base-ubuntu20.04
|
||||||
|
|
||||||
ARG ARTIFACTS_ROOT
|
ARG ARTIFACTS_ROOT
|
||||||
COPY ${ARTIFACTS_ROOT} /artifacts/packages/
|
COPY ${ARTIFACTS_ROOT} /artifacts/packages/
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
ARG GOLANG_VERSION=x.x.x
|
ARG GOLANG_VERSION=x.x.x
|
||||||
ARG VERSION="N/A"
|
ARG VERSION="N/A"
|
||||||
|
|
||||||
FROM nvidia/cuda:12.6.2-base-ubi8 as build
|
FROM nvcr.io/nvidia/cuda:12.8.0-base-ubi8 AS build
|
||||||
|
|
||||||
RUN yum install -y \
|
RUN yum install -y \
|
||||||
wget make git gcc \
|
wget make git gcc \
|
||||||
@@ -36,19 +36,18 @@ RUN set -eux; \
|
|||||||
| tar -C /usr/local -xz
|
| tar -C /usr/local -xz
|
||||||
|
|
||||||
|
|
||||||
ENV GOPATH /go
|
ENV GOPATH=/go
|
||||||
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
|
ENV PATH=$GOPATH/bin:/usr/local/go/bin:$PATH
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# NOTE: Until the config utilities are properly integrated into the
|
RUN mkdir /artifacts
|
||||||
# nvidia-container-toolkit repository, these are built from the `tools` folder
|
ARG VERSION="N/A"
|
||||||
# and not `cmd`.
|
ARG GIT_COMMIT="unknown"
|
||||||
RUN GOPATH=/artifacts go install -ldflags="-s -w -X 'main.Version=${VERSION}'" ./tools/...
|
RUN make PREFIX=/artifacts cmd-nvidia-ctk-installer
|
||||||
|
|
||||||
|
FROM nvcr.io/nvidia/cuda:12.8.0-base-ubi8
|
||||||
FROM nvidia/cuda:12.6.2-base-ubi8
|
|
||||||
|
|
||||||
ENV NVIDIA_DISABLE_REQUIRE="true"
|
ENV NVIDIA_DISABLE_REQUIRE="true"
|
||||||
ENV NVIDIA_VISIBLE_DEVICES=void
|
ENV NVIDIA_VISIBLE_DEVICES=void
|
||||||
@@ -62,7 +61,8 @@ WORKDIR /artifacts/packages
|
|||||||
|
|
||||||
ARG PACKAGE_VERSION
|
ARG PACKAGE_VERSION
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ENV PACKAGE_ARCH ${TARGETARCH}
|
ENV PACKAGE_ARCH=${TARGETARCH}
|
||||||
|
|
||||||
RUN PACKAGE_ARCH=${PACKAGE_ARCH/amd64/x86_64} && PACKAGE_ARCH=${PACKAGE_ARCH/arm64/aarch64} && \
|
RUN PACKAGE_ARCH=${PACKAGE_ARCH/amd64/x86_64} && PACKAGE_ARCH=${PACKAGE_ARCH/arm64/aarch64} && \
|
||||||
yum localinstall -y \
|
yum localinstall -y \
|
||||||
${PACKAGE_DIST}/${PACKAGE_ARCH}/libnvidia-container1-1.*.rpm \
|
${PACKAGE_DIST}/${PACKAGE_ARCH}/libnvidia-container1-1.*.rpm \
|
||||||
@@ -71,10 +71,12 @@ RUN PACKAGE_ARCH=${PACKAGE_ARCH/amd64/x86_64} && PACKAGE_ARCH=${PACKAGE_ARCH/arm
|
|||||||
|
|
||||||
WORKDIR /work
|
WORKDIR /work
|
||||||
|
|
||||||
COPY --from=build /artifacts/bin /work
|
COPY --from=build /artifacts/nvidia-ctk-installer /work/nvidia-ctk-installer
|
||||||
|
RUN ln -s nvidia-ctk-installer nvidia-toolkit
|
||||||
|
|
||||||
ENV PATH=/work:$PATH
|
ENV PATH=/work:$PATH
|
||||||
|
|
||||||
|
ARG VERSION
|
||||||
LABEL io.k8s.display-name="NVIDIA Container Runtime Config"
|
LABEL io.k8s.display-name="NVIDIA Container Runtime Config"
|
||||||
LABEL name="NVIDIA Container Runtime Config"
|
LABEL name="NVIDIA Container Runtime Config"
|
||||||
LABEL vendor="NVIDIA"
|
LABEL vendor="NVIDIA"
|
||||||
@@ -85,4 +87,4 @@ LABEL description="See summary"
|
|||||||
|
|
||||||
RUN mkdir /licenses && mv /NGC-DL-CONTAINER-LICENSE /licenses/NGC-DL-CONTAINER-LICENSE
|
RUN mkdir /licenses && mv /NGC-DL-CONTAINER-LICENSE /licenses/NGC-DL-CONTAINER-LICENSE
|
||||||
|
|
||||||
ENTRYPOINT ["/work/nvidia-toolkit"]
|
ENTRYPOINT ["/work/nvidia-ctk-installer"]
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
ARG GOLANG_VERSION=x.x.x
|
ARG GOLANG_VERSION=x.x.x
|
||||||
ARG VERSION="N/A"
|
ARG VERSION="N/A"
|
||||||
|
|
||||||
FROM nvidia/cuda:12.6.2-base-ubuntu20.04 as build
|
FROM nvcr.io/nvidia/cuda:12.8.0-base-ubuntu20.04 AS build
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y wget make git gcc \
|
apt-get install -y wget make git gcc \
|
||||||
@@ -35,19 +35,18 @@ RUN set -eux; \
|
|||||||
wget -nv -O - https://storage.googleapis.com/golang/go${GOLANG_VERSION}.linux-${ARCH}.tar.gz \
|
wget -nv -O - https://storage.googleapis.com/golang/go${GOLANG_VERSION}.linux-${ARCH}.tar.gz \
|
||||||
| tar -C /usr/local -xz
|
| tar -C /usr/local -xz
|
||||||
|
|
||||||
ENV GOPATH /go
|
ENV GOPATH=/go
|
||||||
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
|
ENV PATH=$GOPATH/bin:/usr/local/go/bin:$PATH
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# NOTE: Until the config utilities are properly integrated into the
|
RUN mkdir /artifacts
|
||||||
# nvidia-container-toolkit repository, these are built from the `tools` folder
|
ARG VERSION="N/A"
|
||||||
# and not `cmd`.
|
ARG GIT_COMMIT="unknown"
|
||||||
RUN GOPATH=/artifacts go install -ldflags="-s -w -X 'main.Version=${VERSION}'" ./tools/...
|
RUN make PREFIX=/artifacts cmd-nvidia-ctk-installer
|
||||||
|
|
||||||
|
FROM nvcr.io/nvidia/cuda:12.8.0-base-ubuntu20.04
|
||||||
FROM nvcr.io/nvidia/cuda:12.6.2-base-ubuntu20.04
|
|
||||||
|
|
||||||
# Remove the CUDA repository configurations to avoid issues with rotated GPG keys
|
# Remove the CUDA repository configurations to avoid issues with rotated GPG keys
|
||||||
RUN rm -f /etc/apt/sources.list.d/cuda.list
|
RUN rm -f /etc/apt/sources.list.d/cuda.list
|
||||||
@@ -71,7 +70,7 @@ WORKDIR /artifacts/packages
|
|||||||
|
|
||||||
ARG PACKAGE_VERSION
|
ARG PACKAGE_VERSION
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ENV PACKAGE_ARCH ${TARGETARCH}
|
ENV PACKAGE_ARCH=${TARGETARCH}
|
||||||
|
|
||||||
RUN dpkg -i \
|
RUN dpkg -i \
|
||||||
${PACKAGE_DIST}/${PACKAGE_ARCH}/libnvidia-container1_1.*.deb \
|
${PACKAGE_DIST}/${PACKAGE_ARCH}/libnvidia-container1_1.*.deb \
|
||||||
@@ -80,10 +79,12 @@ RUN dpkg -i \
|
|||||||
|
|
||||||
WORKDIR /work
|
WORKDIR /work
|
||||||
|
|
||||||
COPY --from=build /artifacts/bin /work/
|
COPY --from=build /artifacts/nvidia-ctk-installer /work/nvidia-ctk-installer
|
||||||
|
RUN ln -s nvidia-ctk-installer nvidia-toolkit
|
||||||
|
|
||||||
ENV PATH=/work:$PATH
|
ENV PATH=/work:$PATH
|
||||||
|
|
||||||
|
ARG VERSION
|
||||||
LABEL io.k8s.display-name="NVIDIA Container Runtime Config"
|
LABEL io.k8s.display-name="NVIDIA Container Runtime Config"
|
||||||
LABEL name="NVIDIA Container Runtime Config"
|
LABEL name="NVIDIA Container Runtime Config"
|
||||||
LABEL vendor="NVIDIA"
|
LABEL vendor="NVIDIA"
|
||||||
@@ -94,4 +95,4 @@ LABEL description="See summary"
|
|||||||
|
|
||||||
RUN mkdir /licenses && mv /NGC-DL-CONTAINER-LICENSE /licenses/NGC-DL-CONTAINER-LICENSE
|
RUN mkdir /licenses && mv /NGC-DL-CONTAINER-LICENSE /licenses/NGC-DL-CONTAINER-LICENSE
|
||||||
|
|
||||||
ENTRYPOINT ["/work/nvidia-toolkit"]
|
ENTRYPOINT ["/work/nvidia-ctk-installer"]
|
||||||
|
|||||||
@@ -27,12 +27,6 @@ DIST_DIR ?= $(CURDIR)/dist
|
|||||||
##### Global variables #####
|
##### Global variables #####
|
||||||
include $(CURDIR)/versions.mk
|
include $(CURDIR)/versions.mk
|
||||||
|
|
||||||
ifeq ($(IMAGE_NAME),)
|
|
||||||
REGISTRY ?= nvidia
|
|
||||||
IMAGE_NAME := $(REGISTRY)/container-toolkit
|
|
||||||
endif
|
|
||||||
|
|
||||||
VERSION ?= $(LIB_VERSION)$(if $(LIB_TAG),-$(LIB_TAG))
|
|
||||||
IMAGE_VERSION := $(VERSION)
|
IMAGE_VERSION := $(VERSION)
|
||||||
|
|
||||||
IMAGE_TAG ?= $(VERSION)-$(DIST)
|
IMAGE_TAG ?= $(VERSION)-$(DIST)
|
||||||
@@ -49,6 +43,7 @@ DISTRIBUTIONS := ubuntu20.04 ubi8
|
|||||||
|
|
||||||
META_TARGETS := packaging
|
META_TARGETS := packaging
|
||||||
|
|
||||||
|
IMAGE_TARGETS := $(patsubst %,image-%,$(DISTRIBUTIONS) $(META_TARGETS))
|
||||||
BUILD_TARGETS := $(patsubst %,build-%,$(DISTRIBUTIONS) $(META_TARGETS))
|
BUILD_TARGETS := $(patsubst %,build-%,$(DISTRIBUTIONS) $(META_TARGETS))
|
||||||
PUSH_TARGETS := $(patsubst %,push-%,$(DISTRIBUTIONS) $(META_TARGETS))
|
PUSH_TARGETS := $(patsubst %,push-%,$(DISTRIBUTIONS) $(META_TARGETS))
|
||||||
TEST_TARGETS := $(patsubst %,test-%,$(DISTRIBUTIONS))
|
TEST_TARGETS := $(patsubst %,test-%,$(DISTRIBUTIONS))
|
||||||
@@ -89,7 +84,7 @@ build-%: DOCKERFILE = $(CURDIR)/deployments/container/Dockerfile.$(DOCKERFILE_SU
|
|||||||
ARTIFACTS_ROOT ?= $(shell realpath --relative-to=$(CURDIR) $(DIST_DIR))
|
ARTIFACTS_ROOT ?= $(shell realpath --relative-to=$(CURDIR) $(DIST_DIR))
|
||||||
|
|
||||||
# Use a generic build target to build the relevant images
|
# Use a generic build target to build the relevant images
|
||||||
$(BUILD_TARGETS): build-%: $(ARTIFACTS_ROOT)
|
$(IMAGE_TARGETS): image-%: $(ARTIFACTS_ROOT)
|
||||||
DOCKER_BUILDKIT=1 \
|
DOCKER_BUILDKIT=1 \
|
||||||
$(DOCKER) $(BUILDX) build --pull \
|
$(DOCKER) $(BUILDX) build --pull \
|
||||||
--provenance=false --sbom=false \
|
--provenance=false --sbom=false \
|
||||||
@@ -108,7 +103,6 @@ $(BUILD_TARGETS): build-%: $(ARTIFACTS_ROOT)
|
|||||||
-f $(DOCKERFILE) \
|
-f $(DOCKERFILE) \
|
||||||
$(CURDIR)
|
$(CURDIR)
|
||||||
|
|
||||||
|
|
||||||
build-ubuntu%: DOCKERFILE_SUFFIX := ubuntu
|
build-ubuntu%: DOCKERFILE_SUFFIX := ubuntu
|
||||||
build-ubuntu%: PACKAGE_DIST = ubuntu18.04
|
build-ubuntu%: PACKAGE_DIST = ubuntu18.04
|
||||||
|
|
||||||
@@ -122,7 +116,13 @@ build-packaging: PACKAGE_DIST = all
|
|||||||
# Test targets
|
# Test targets
|
||||||
test-%: DIST = $(*)
|
test-%: DIST = $(*)
|
||||||
|
|
||||||
TEST_CASES ?= toolkit docker crio containerd
|
# Handle the default build target.
|
||||||
|
.PHONY: build
|
||||||
|
build: $(DEFAULT_PUSH_TARGET)
|
||||||
|
$(DEFAULT_PUSH_TARGET): build-$(DEFAULT_PUSH_TARGET)
|
||||||
|
$(DEFAULT_PUSH_TARGET): DIST = $(DEFAULT_PUSH_TARGET)
|
||||||
|
|
||||||
|
TEST_CASES ?= docker crio containerd
|
||||||
$(TEST_TARGETS): test-%:
|
$(TEST_TARGETS): test-%:
|
||||||
TEST_CASES="$(TEST_CASES)" bash -x $(CURDIR)/test/container/main.sh run \
|
TEST_CASES="$(TEST_CASES)" bash -x $(CURDIR)/test/container/main.sh run \
|
||||||
$(CURDIR)/shared-$(*) \
|
$(CURDIR)/shared-$(*) \
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ PUSH_ON_BUILD ?= false
|
|||||||
DOCKER_BUILD_OPTIONS = --output=type=image,push=$(PUSH_ON_BUILD)
|
DOCKER_BUILD_OPTIONS = --output=type=image,push=$(PUSH_ON_BUILD)
|
||||||
DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64,linux/arm64
|
DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64,linux/arm64
|
||||||
|
|
||||||
# We only generate amd64 image for ubuntu18.04
|
$(BUILD_TARGETS): build-%: image-%
|
||||||
build-ubuntu18.04: DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64
|
|
||||||
|
|
||||||
# We only generate a single image for packaging targets
|
# We only generate a single image for packaging targets
|
||||||
build-packaging: DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64
|
build-packaging: DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64
|
||||||
|
|||||||
@@ -12,4 +12,22 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/amd64
|
PUSH_ON_BUILD ?= false
|
||||||
|
ARCH ?= $(shell uname -m)
|
||||||
|
DOCKER_BUILD_PLATFORM_OPTIONS = --platform=linux/$(ARCH)
|
||||||
|
|
||||||
|
ifeq ($(PUSH_ON_BUILD),true)
|
||||||
|
DOCKER_BUILD_OPTIONS = --output=type=image,push=$(PUSH_ON_BUILD)
|
||||||
|
$(BUILD_TARGETS): build-%: image-%
|
||||||
|
$(DOCKER) push "$(IMAGE)"
|
||||||
|
else
|
||||||
|
$(BUILD_TARGETS): build-%: image-%
|
||||||
|
endif
|
||||||
|
|
||||||
|
# For the default distribution we also retag the image.
|
||||||
|
# Note: This needs to be updated for multi-arch images.
|
||||||
|
ifeq ($(IMAGE_TAG),$(VERSION)-$(DIST))
|
||||||
|
$(DEFAULT_PUSH_TARGET):
|
||||||
|
$(DOCKER) image inspect $(IMAGE) > /dev/null || $(DOCKER) pull $(IMAGE)
|
||||||
|
$(DOCKER) tag $(IMAGE) $(subst :$(IMAGE_TAG),:$(VERSION),$(IMAGE))
|
||||||
|
endif
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
# This Dockerfile is also used to define the golang version used in this project
|
# This Dockerfile is also used to define the golang version used in this project
|
||||||
# This allows dependabot to manage this version in addition to other images.
|
# This allows dependabot to manage this version in addition to other images.
|
||||||
FROM golang:1.23.2
|
FROM golang:1.24.0
|
||||||
|
|
||||||
WORKDIR /work
|
WORKDIR /work
|
||||||
COPY * .
|
COPY * .
|
||||||
|
|||||||
@@ -1,60 +1,61 @@
|
|||||||
module github.com/NVIDIA/k8s-device-plugin/deployments/devel
|
module github.com/NVIDIA/k8s-device-plugin/deployments/devel
|
||||||
|
|
||||||
go 1.23
|
go 1.24
|
||||||
|
|
||||||
toolchain go1.23.1
|
toolchain go1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golangci/golangci-lint v1.61.0
|
github.com/golangci/golangci-lint v1.64.6
|
||||||
github.com/matryer/moq v0.5.0
|
github.com/matryer/moq v0.5.3
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
4d63.com/gocheckcompilerdirectives v1.2.1 // indirect
|
4d63.com/gocheckcompilerdirectives v1.3.0 // indirect
|
||||||
4d63.com/gochecknoglobals v0.2.1 // indirect
|
4d63.com/gochecknoglobals v0.2.2 // indirect
|
||||||
github.com/4meepo/tagalign v1.3.4 // indirect
|
github.com/4meepo/tagalign v1.4.2 // indirect
|
||||||
github.com/Abirdcfly/dupword v0.1.1 // indirect
|
github.com/Abirdcfly/dupword v0.1.3 // indirect
|
||||||
github.com/Antonboom/errname v0.1.13 // indirect
|
github.com/Antonboom/errname v1.0.0 // indirect
|
||||||
github.com/Antonboom/nilnil v0.1.9 // indirect
|
github.com/Antonboom/nilnil v1.0.1 // indirect
|
||||||
github.com/Antonboom/testifylint v1.4.3 // indirect
|
github.com/Antonboom/testifylint v1.5.2 // indirect
|
||||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
|
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
|
||||||
github.com/Crocmagnon/fatcontext v0.5.2 // indirect
|
github.com/Crocmagnon/fatcontext v0.7.1 // indirect
|
||||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
|
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
|
||||||
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect
|
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
||||||
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect
|
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect
|
||||||
github.com/alecthomas/go-check-sumtype v0.1.4 // indirect
|
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
|
||||||
github.com/alexkohler/nakedret/v2 v2.0.4 // indirect
|
github.com/alexkohler/nakedret/v2 v2.0.5 // indirect
|
||||||
github.com/alexkohler/prealloc v1.0.0 // indirect
|
github.com/alexkohler/prealloc v1.0.0 // indirect
|
||||||
github.com/alingse/asasalint v0.0.11 // indirect
|
github.com/alingse/asasalint v0.0.11 // indirect
|
||||||
|
github.com/alingse/nilnesserr v0.1.2 // indirect
|
||||||
github.com/ashanbrown/forbidigo v1.6.0 // indirect
|
github.com/ashanbrown/forbidigo v1.6.0 // indirect
|
||||||
github.com/ashanbrown/makezero v1.1.1 // indirect
|
github.com/ashanbrown/makezero v1.2.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bkielbasa/cyclop v1.2.1 // indirect
|
github.com/bkielbasa/cyclop v1.2.3 // indirect
|
||||||
github.com/blizzy78/varnamelen v0.8.0 // indirect
|
github.com/blizzy78/varnamelen v0.8.0 // indirect
|
||||||
github.com/bombsimon/wsl/v4 v4.4.1 // indirect
|
github.com/bombsimon/wsl/v4 v4.5.0 // indirect
|
||||||
github.com/breml/bidichk v0.2.7 // indirect
|
github.com/breml/bidichk v0.3.2 // indirect
|
||||||
github.com/breml/errchkjson v0.3.6 // indirect
|
github.com/breml/errchkjson v0.4.0 // indirect
|
||||||
github.com/butuzov/ireturn v0.3.0 // indirect
|
github.com/butuzov/ireturn v0.3.1 // indirect
|
||||||
github.com/butuzov/mirror v1.2.0 // indirect
|
github.com/butuzov/mirror v1.3.0 // indirect
|
||||||
github.com/catenacyber/perfsprint v0.7.1 // indirect
|
github.com/catenacyber/perfsprint v0.8.2 // indirect
|
||||||
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
|
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/charithe/durationcheck v0.0.10 // indirect
|
github.com/charithe/durationcheck v0.0.10 // indirect
|
||||||
github.com/chavacava/garif v0.1.0 // indirect
|
github.com/chavacava/garif v0.1.0 // indirect
|
||||||
github.com/ckaznocha/intrange v0.2.0 // indirect
|
github.com/ckaznocha/intrange v0.3.0 // indirect
|
||||||
github.com/curioswitch/go-reassign v0.2.0 // indirect
|
github.com/curioswitch/go-reassign v0.3.0 // indirect
|
||||||
github.com/daixiang0/gci v0.13.5 // indirect
|
github.com/daixiang0/gci v0.13.5 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/denis-tingaikin/go-header v0.5.0 // indirect
|
github.com/denis-tingaikin/go-header v0.5.0 // indirect
|
||||||
github.com/ettle/strcase v0.2.0 // indirect
|
github.com/ettle/strcase v0.2.0 // indirect
|
||||||
github.com/fatih/color v1.17.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/fatih/structtag v1.2.0 // indirect
|
github.com/fatih/structtag v1.2.0 // indirect
|
||||||
github.com/firefart/nonamedreturns v1.0.5 // indirect
|
github.com/firefart/nonamedreturns v1.0.5 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||||
github.com/fzipp/gocyclo v0.6.0 // indirect
|
github.com/fzipp/gocyclo v0.6.0 // indirect
|
||||||
github.com/ghostiam/protogetter v0.3.6 // indirect
|
github.com/ghostiam/protogetter v0.3.9 // indirect
|
||||||
github.com/go-critic/go-critic v0.11.4 // indirect
|
github.com/go-critic/go-critic v0.12.0 // indirect
|
||||||
github.com/go-toolsmith/astcast v1.1.0 // indirect
|
github.com/go-toolsmith/astcast v1.1.0 // indirect
|
||||||
github.com/go-toolsmith/astcopy v1.1.0 // indirect
|
github.com/go-toolsmith/astcopy v1.1.0 // indirect
|
||||||
github.com/go-toolsmith/astequal v1.2.0 // indirect
|
github.com/go-toolsmith/astequal v1.2.0 // indirect
|
||||||
@@ -62,66 +63,68 @@ require (
|
|||||||
github.com/go-toolsmith/astp v1.1.0 // indirect
|
github.com/go-toolsmith/astp v1.1.0 // indirect
|
||||||
github.com/go-toolsmith/strparse v1.1.0 // indirect
|
github.com/go-toolsmith/strparse v1.1.0 // indirect
|
||||||
github.com/go-toolsmith/typep v1.1.0 // indirect
|
github.com/go-toolsmith/typep v1.1.0 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.1.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||||
github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
|
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/gofrs/flock v0.12.1 // indirect
|
github.com/gofrs/flock v0.12.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
|
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
|
||||||
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect
|
github.com/golangci/go-printf-func-name v0.1.0 // indirect
|
||||||
|
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect
|
||||||
github.com/golangci/misspell v0.6.0 // indirect
|
github.com/golangci/misspell v0.6.0 // indirect
|
||||||
github.com/golangci/modinfo v0.3.4 // indirect
|
|
||||||
github.com/golangci/plugin-module-register v0.1.1 // indirect
|
github.com/golangci/plugin-module-register v0.1.1 // indirect
|
||||||
github.com/golangci/revgrep v0.5.3 // indirect
|
github.com/golangci/revgrep v0.8.0 // indirect
|
||||||
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
|
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/gordonklaus/ineffassign v0.1.0 // indirect
|
github.com/gordonklaus/ineffassign v0.1.0 // indirect
|
||||||
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
|
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
|
||||||
github.com/gostaticanalysis/comment v1.4.2 // indirect
|
github.com/gostaticanalysis/comment v1.5.0 // indirect
|
||||||
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
|
github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect
|
||||||
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
|
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
|
||||||
|
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
|
||||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jgautheron/goconst v1.7.1 // indirect
|
github.com/jgautheron/goconst v1.7.1 // indirect
|
||||||
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
|
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
|
||||||
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
|
github.com/jjti/go-spancheck v0.6.4 // indirect
|
||||||
github.com/jjti/go-spancheck v0.6.2 // indirect
|
github.com/julz/importas v0.2.0 // indirect
|
||||||
github.com/julz/importas v0.1.0 // indirect
|
github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect
|
||||||
github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect
|
github.com/kisielk/errcheck v1.9.0 // indirect
|
||||||
github.com/kisielk/errcheck v1.7.0 // indirect
|
github.com/kkHAIKE/contextcheck v1.1.6 // indirect
|
||||||
github.com/kkHAIKE/contextcheck v1.1.5 // indirect
|
|
||||||
github.com/kulti/thelper v0.6.3 // indirect
|
github.com/kulti/thelper v0.6.3 // indirect
|
||||||
github.com/kunwardeep/paralleltest v1.0.10 // indirect
|
github.com/kunwardeep/paralleltest v1.0.10 // indirect
|
||||||
github.com/kyoh86/exportloopref v0.1.11 // indirect
|
github.com/lasiar/canonicalheader v1.1.2 // indirect
|
||||||
github.com/lasiar/canonicalheader v1.1.1 // indirect
|
github.com/ldez/exptostd v0.4.2 // indirect
|
||||||
github.com/ldez/gomoddirectives v0.2.4 // indirect
|
github.com/ldez/gomoddirectives v0.6.1 // indirect
|
||||||
github.com/ldez/tagliatelle v0.5.0 // indirect
|
github.com/ldez/grignotin v0.9.0 // indirect
|
||||||
|
github.com/ldez/tagliatelle v0.7.1 // indirect
|
||||||
|
github.com/ldez/usetesting v0.4.2 // indirect
|
||||||
github.com/leonklingele/grouper v1.1.2 // indirect
|
github.com/leonklingele/grouper v1.1.2 // indirect
|
||||||
github.com/lufeee/execinquery v1.2.1 // indirect
|
|
||||||
github.com/macabu/inamedparam v0.1.3 // indirect
|
github.com/macabu/inamedparam v0.1.3 // indirect
|
||||||
github.com/magiconair/properties v1.8.6 // indirect
|
github.com/magiconair/properties v1.8.6 // indirect
|
||||||
github.com/maratori/testableexamples v1.0.0 // indirect
|
github.com/maratori/testableexamples v1.0.0 // indirect
|
||||||
github.com/maratori/testpackage v1.1.1 // indirect
|
github.com/maratori/testpackage v1.1.1 // indirect
|
||||||
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect
|
github.com/matoous/godox v1.1.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
github.com/mgechev/revive v1.3.9 // indirect
|
github.com/mgechev/revive v1.7.0 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/moricho/tparallel v0.3.2 // indirect
|
github.com/moricho/tparallel v0.3.2 // indirect
|
||||||
github.com/nakabonne/nestif v0.3.1 // indirect
|
github.com/nakabonne/nestif v0.3.1 // indirect
|
||||||
github.com/nishanths/exhaustive v0.12.0 // indirect
|
github.com/nishanths/exhaustive v0.12.0 // indirect
|
||||||
github.com/nishanths/predeclared v0.2.2 // indirect
|
github.com/nishanths/predeclared v0.2.2 // indirect
|
||||||
github.com/nunnatsa/ginkgolinter v0.16.2 // indirect
|
github.com/nunnatsa/ginkgolinter v0.19.1 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/polyfloyd/go-errorlint v1.6.0 // indirect
|
github.com/polyfloyd/go-errorlint v1.7.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.12.1 // indirect
|
github.com/prometheus/client_golang v1.12.1 // indirect
|
||||||
github.com/prometheus/client_model v0.2.0 // indirect
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
github.com/prometheus/common v0.32.1 // indirect
|
github.com/prometheus/common v0.32.1 // indirect
|
||||||
@@ -131,62 +134,64 @@ require (
|
|||||||
github.com/quasilyte/gogrep v0.5.0 // indirect
|
github.com/quasilyte/gogrep v0.5.0 // indirect
|
||||||
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
|
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
|
||||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
|
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
|
||||||
|
github.com/raeperd/recvcheck v0.2.0 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
github.com/ryancurrah/gomodguard v1.3.5 // indirect
|
github.com/ryancurrah/gomodguard v1.3.5 // indirect
|
||||||
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
|
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
|
||||||
github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect
|
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
|
||||||
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
|
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
|
||||||
github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect
|
github.com/sashamelentyev/usestdlibvars v1.28.0 // indirect
|
||||||
github.com/securego/gosec/v2 v2.21.2 // indirect
|
github.com/securego/gosec/v2 v2.22.1 // indirect
|
||||||
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
|
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/sivchari/containedctx v1.0.3 // indirect
|
github.com/sivchari/containedctx v1.0.3 // indirect
|
||||||
github.com/sivchari/tenv v1.10.0 // indirect
|
github.com/sivchari/tenv v1.12.1 // indirect
|
||||||
github.com/sonatard/noctx v0.0.2 // indirect
|
github.com/sonatard/noctx v0.1.0 // indirect
|
||||||
github.com/sourcegraph/go-diff v0.7.0 // indirect
|
github.com/sourcegraph/go-diff v0.7.0 // indirect
|
||||||
github.com/spf13/afero v1.11.0 // indirect
|
github.com/spf13/afero v1.12.0 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
github.com/spf13/cobra v1.8.1 // indirect
|
github.com/spf13/cobra v1.9.1 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
github.com/spf13/viper v1.12.0 // indirect
|
github.com/spf13/viper v1.12.0 // indirect
|
||||||
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
|
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
|
||||||
github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
|
github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/stretchr/testify v1.9.0 // indirect
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
github.com/subosito/gotenv v1.4.1 // indirect
|
github.com/subosito/gotenv v1.4.1 // indirect
|
||||||
github.com/tdakkota/asciicheck v0.2.0 // indirect
|
github.com/tdakkota/asciicheck v0.4.1 // indirect
|
||||||
github.com/tetafro/godot v1.4.17 // indirect
|
github.com/tetafro/godot v1.5.0 // indirect
|
||||||
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect
|
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 // indirect
|
||||||
github.com/timonwong/loggercheck v0.9.4 // indirect
|
github.com/timonwong/loggercheck v0.10.1 // indirect
|
||||||
github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect
|
github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect
|
||||||
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
|
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
|
||||||
github.com/ultraware/funlen v0.1.0 // indirect
|
github.com/ultraware/funlen v0.2.0 // indirect
|
||||||
github.com/ultraware/whitespace v0.1.1 // indirect
|
github.com/ultraware/whitespace v0.2.0 // indirect
|
||||||
github.com/uudashr/gocognit v1.1.3 // indirect
|
github.com/uudashr/gocognit v1.2.0 // indirect
|
||||||
|
github.com/uudashr/iface v1.3.1 // indirect
|
||||||
github.com/xen0n/gosmopolitan v1.2.2 // indirect
|
github.com/xen0n/gosmopolitan v1.2.2 // indirect
|
||||||
github.com/yagipy/maintidx v1.0.0 // indirect
|
github.com/yagipy/maintidx v1.0.0 // indirect
|
||||||
github.com/yeya24/promlinter v0.3.0 // indirect
|
github.com/yeya24/promlinter v0.3.0 // indirect
|
||||||
github.com/ykadowak/zerologlint v0.1.5 // indirect
|
github.com/ykadowak/zerologlint v0.1.5 // indirect
|
||||||
gitlab.com/bosi/decorder v0.4.2 // indirect
|
gitlab.com/bosi/decorder v0.4.2 // indirect
|
||||||
go-simpler.org/musttag v0.12.2 // indirect
|
go-simpler.org/musttag v0.13.0 // indirect
|
||||||
go-simpler.org/sloglint v0.7.2 // indirect
|
go-simpler.org/sloglint v0.9.0 // indirect
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
go.uber.org/automaxprocs v1.5.3 // indirect
|
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
go.uber.org/zap v1.24.0 // indirect
|
go.uber.org/zap v1.24.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
|
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
|
||||||
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect
|
golang.org/x/mod v0.23.0 // indirect
|
||||||
golang.org/x/mod v0.21.0 // indirect
|
golang.org/x/sync v0.11.0 // indirect
|
||||||
golang.org/x/sync v0.8.0 // indirect
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
golang.org/x/sys v0.25.0 // indirect
|
golang.org/x/text v0.22.0 // indirect
|
||||||
golang.org/x/text v0.18.0 // indirect
|
golang.org/x/tools v0.30.0 // indirect
|
||||||
golang.org/x/tools v0.24.0 // indirect
|
google.golang.org/protobuf v1.36.4 // indirect
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
honnef.co/go/tools v0.5.1 // indirect
|
honnef.co/go/tools v0.6.0 // indirect
|
||||||
mvdan.cc/gofumpt v0.7.0 // indirect
|
mvdan.cc/gofumpt v0.7.0 // indirect
|
||||||
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
|
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA=
|
4d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A=
|
||||||
4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs=
|
4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY=
|
||||||
4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc=
|
4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU=
|
||||||
4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU=
|
4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0=
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
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.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.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
@@ -35,79 +35,82 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
|||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
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=
|
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=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8=
|
github.com/4meepo/tagalign v1.4.2 h1:0hcLHPGMjDyM1gHG58cS73aQF8J4TdVR96TZViorO9E=
|
||||||
github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0=
|
github.com/4meepo/tagalign v1.4.2/go.mod h1:+p4aMyFM+ra7nb41CnFG6aSDXqRxU/w1VQqScKqDARI=
|
||||||
github.com/Abirdcfly/dupword v0.1.1 h1:Bsxe0fIw6OwBtXMIncaTxCLHYO5BB+3mcsR5E8VXloY=
|
github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE=
|
||||||
github.com/Abirdcfly/dupword v0.1.1/go.mod h1:B49AcJdTYYkpd4HjgAcutNGG9HZ2JWwKunH9Y2BA6sM=
|
github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw=
|
||||||
github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHOVvM=
|
github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA=
|
||||||
github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns=
|
github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI=
|
||||||
github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ=
|
github.com/Antonboom/nilnil v1.0.1 h1:C3Tkm0KUxgfO4Duk3PM+ztPncTFlOf0b2qadmS0s4xs=
|
||||||
github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ=
|
github.com/Antonboom/nilnil v1.0.1/go.mod h1:CH7pW2JsRNFgEh8B2UaPZTEPhCMuFowP/e8Udp9Nnb0=
|
||||||
github.com/Antonboom/testifylint v1.4.3 h1:ohMt6AHuHgttaQ1xb6SSnxCeK4/rnK7KKzbvs7DmEck=
|
github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk=
|
||||||
github.com/Antonboom/testifylint v1.4.3/go.mod h1:+8Q9+AOLsz5ZiQiiYujJKs9mNz398+M6UgslP4qgJLA=
|
github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
|
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
|
||||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/Crocmagnon/fatcontext v0.5.2 h1:vhSEg8Gqng8awhPju2w7MKHqMlg4/NI+gSDHtR3xgwA=
|
github.com/Crocmagnon/fatcontext v0.7.1 h1:SC/VIbRRZQeQWj/TcQBS6JmrXcfA+BU4OGSVUt54PjM=
|
||||||
github.com/Crocmagnon/fatcontext v0.5.2/go.mod h1:87XhRMaInHP44Q7Tlc7jkgKKB7kZAOPiDkFMdKCC+74=
|
github.com/Crocmagnon/fatcontext v0.7.1/go.mod h1:1wMvv3NXEBJucFGfwOJBxSVWcoIO6emV215SMkW9MFU=
|
||||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
|
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
|
||||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
|
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
|
||||||
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU=
|
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 h1:Sz1JIXEcSfhz7fUi7xHnhpIE0thVASYjvosApmHuD2k=
|
||||||
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao=
|
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1/go.mod h1:n/LSCXNuIYqVfBlVXyHfMQkZDdp1/mmxfSjADd3z1Zg=
|
||||||
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
|
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
|
||||||
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA=
|
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA=
|
||||||
github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ=
|
github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ=
|
||||||
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
|
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||||
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
|
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||||
github.com/alecthomas/go-check-sumtype v0.1.4 h1:WCvlB3l5Vq5dZQTFmodqL2g68uHiSwwlWcT5a2FGK0c=
|
github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU=
|
||||||
github.com/alecthomas/go-check-sumtype v0.1.4/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ=
|
github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E=
|
||||||
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||||
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/alexkohler/nakedret/v2 v2.0.4 h1:yZuKmjqGi0pSmjGpOC016LtPJysIL0WEUiaXW5SUnNg=
|
github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU=
|
||||||
github.com/alexkohler/nakedret/v2 v2.0.4/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU=
|
github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU=
|
||||||
github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw=
|
github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw=
|
||||||
github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
|
github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
|
||||||
github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=
|
github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=
|
||||||
github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=
|
github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=
|
||||||
|
github.com/alingse/nilnesserr v0.1.2 h1:Yf8Iwm3z2hUUrP4muWfW83DF4nE3r1xZ26fGWUKCZlo=
|
||||||
|
github.com/alingse/nilnesserr v0.1.2/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg=
|
||||||
github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY=
|
github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY=
|
||||||
github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
|
github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
|
||||||
github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s=
|
github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU=
|
||||||
github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI=
|
github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY=
|
github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w=
|
||||||
github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM=
|
github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo=
|
||||||
github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=
|
github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=
|
||||||
github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
|
github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
|
||||||
github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw=
|
github.com/bombsimon/wsl/v4 v4.5.0 h1:iZRsEvDdyhd2La0FVi5k6tYehpOR/R7qIUjmKk7N74A=
|
||||||
github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo=
|
github.com/bombsimon/wsl/v4 v4.5.0/go.mod h1:NOQ3aLF4nD7N5YPXMruR6ZXDOAqLoM0GEpLwTdvmOSc=
|
||||||
github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY=
|
github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs=
|
||||||
github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ=
|
github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos=
|
||||||
github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA=
|
github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk=
|
||||||
github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U=
|
github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8=
|
||||||
github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0=
|
github.com/butuzov/ireturn v0.3.1 h1:mFgbEI6m+9W8oP/oDdfA34dLisRFCj2G6o/yiI1yZrY=
|
||||||
github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA=
|
github.com/butuzov/ireturn v0.3.1/go.mod h1:ZfRp+E7eJLC0NQmk1Nrm1LOrn/gQlOykv+cVPdiXH5M=
|
||||||
github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs=
|
github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc=
|
||||||
github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ=
|
github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI=
|
||||||
github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc=
|
github.com/catenacyber/perfsprint v0.8.2 h1:+o9zVmCSVa7M4MvabsWvESEhpsMkhfE7k0sHNGL95yw=
|
||||||
github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50=
|
github.com/catenacyber/perfsprint v0.8.2/go.mod h1:q//VWC2fWbcdSLEY1R3l8n0zQCDPdE4IjZwyY1HMunM=
|
||||||
github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
|
github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
|
||||||
github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
|
github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4=
|
github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4=
|
||||||
github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
|
github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
|
||||||
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||||
@@ -115,13 +118,13 @@ github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+U
|
|||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
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/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/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/ckaznocha/intrange v0.2.0 h1:FykcZuJ8BD7oX93YbO1UY9oZtkRbp+1/kJcDjkefYLs=
|
github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY=
|
||||||
github.com/ckaznocha/intrange v0.2.0/go.mod h1:r5I7nUlAAG56xmkOpw4XVr16BXhwYTUdcuRFeevn1oE=
|
github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
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-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo=
|
github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs=
|
||||||
github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc=
|
github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88=
|
||||||
github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
|
github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
|
||||||
github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
|
github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -129,14 +132,16 @@ 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
|
github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
|
||||||
github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
|
github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
|
||||||
|
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||||
|
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
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.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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q=
|
github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q=
|
||||||
github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A=
|
github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A=
|
||||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||||
github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA=
|
github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA=
|
||||||
@@ -147,10 +152,10 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV
|
|||||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||||
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
||||||
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
||||||
github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk=
|
github.com/ghostiam/protogetter v0.3.9 h1:j+zlLLWzqLay22Cz/aYwTHKQ88GE2DQ6GkWSYFOI4lQ=
|
||||||
github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw=
|
github.com/ghostiam/protogetter v0.3.9/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
|
||||||
github.com/go-critic/go-critic v0.11.4 h1:O7kGOCx0NDIni4czrkRIXTnit0mkyKOCePh3My6OyEU=
|
github.com/go-critic/go-critic v0.12.0 h1:iLosHZuye812wnkEz1Xu3aBwn5ocCPfc9yqmFG9pa6w=
|
||||||
github.com/go-critic/go-critic v0.11.4/go.mod h1:2QAdo4iuLik5S9YG0rT4wcZ8QxwHYkrr6/2MWAiv/vc=
|
github.com/go-critic/go-critic v0.12.0/go.mod h1:DpE0P6OVc6JzVYzmM5gq5jMU31zLr4am5mB/VfFK64w=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
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-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/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
@@ -186,10 +191,10 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi
|
|||||||
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
|
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
|
||||||
github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
|
github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
|
||||||
github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
|
github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
|
||||||
github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w=
|
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||||
github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
|
github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY=
|
||||||
github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
||||||
@@ -226,18 +231,18 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
|
|||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
|
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
|
||||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
|
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
|
||||||
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME=
|
github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU=
|
||||||
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE=
|
github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s=
|
||||||
github.com/golangci/golangci-lint v1.61.0 h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8=
|
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE=
|
||||||
github.com/golangci/golangci-lint v1.61.0/go.mod h1:e4lztIrJJgLPhWvFPDkhiMwEFRrWlmFbrZea3FsJyN8=
|
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY=
|
||||||
|
github.com/golangci/golangci-lint v1.64.6 h1:jOLaQN41IV7bMzXuNC4UnQGll7N1xY6eFDXkXEPGKAs=
|
||||||
|
github.com/golangci/golangci-lint v1.64.6/go.mod h1:Wz9q+6EVuqGQ94GQ96RB2mjpcZYTOGhBhbt4O7REPu4=
|
||||||
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
||||||
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
||||||
github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA=
|
|
||||||
github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM=
|
|
||||||
github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c=
|
github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c=
|
||||||
github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc=
|
github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc=
|
||||||
github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs=
|
github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s=
|
||||||
github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k=
|
github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k=
|
||||||
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs=
|
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs=
|
||||||
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ=
|
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@@ -254,8 +259,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.5/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/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
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 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.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
@@ -266,8 +271,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
|||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/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-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-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA=
|
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||||
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
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/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
@@ -276,20 +281,27 @@ github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it
|
|||||||
github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=
|
github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=
|
||||||
github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc=
|
github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc=
|
||||||
github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado=
|
github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado=
|
||||||
github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q=
|
|
||||||
github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM=
|
github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM=
|
||||||
github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70=
|
github.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytmEpgnKIDu8=
|
||||||
github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak=
|
github.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc=
|
||||||
|
github.com/gostaticanalysis/forcetypeassert v0.2.0 h1:uSnWrrUEYDr86OCxWa4/Tp2jeYDlogZiZHzGkWFefTk=
|
||||||
|
github.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY=
|
||||||
github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk=
|
github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk=
|
||||||
github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A=
|
github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A=
|
||||||
github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
|
github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
|
||||||
github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY=
|
github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8=
|
||||||
github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU=
|
github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs=
|
||||||
|
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo=
|
||||||
|
github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
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/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
@@ -301,10 +313,8 @@ github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5
|
|||||||
github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
|
github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
|
||||||
github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
|
github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
|
||||||
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
|
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
|
||||||
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48=
|
github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc=
|
||||||
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
|
github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk=
|
||||||
github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk=
|
|
||||||
github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA=
|
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
@@ -314,15 +324,15 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
|||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY=
|
github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ=
|
||||||
github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0=
|
github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY=
|
||||||
github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos=
|
github.com/karamaru-alpha/copyloopvar v1.2.1 h1:wmZaZYIjnJ0b5UoKDjUHrikcV0zuPyyxI4SVplLd2CI=
|
||||||
github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k=
|
github.com/karamaru-alpha/copyloopvar v1.2.1/go.mod h1:nFmMlFNlClC2BPvNaHMdkirmTJxVCY0lhxBtlfOypMM=
|
||||||
github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0=
|
github.com/kisielk/errcheck v1.9.0 h1:9xt1zI9EBfcYBvdU1nVrzMzzUPUtPKs9bVSIM3TAb3M=
|
||||||
github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
|
github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg=
|
github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE=
|
||||||
github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA=
|
github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
@@ -337,18 +347,20 @@ github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs=
|
|||||||
github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I=
|
github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I=
|
||||||
github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs=
|
github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs=
|
||||||
github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY=
|
github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY=
|
||||||
github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ=
|
github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4=
|
||||||
github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA=
|
github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI=
|
||||||
github.com/lasiar/canonicalheader v1.1.1 h1:wC+dY9ZfiqiPwAexUApFush/csSPXeIi4QqyxXmng8I=
|
github.com/ldez/exptostd v0.4.2 h1:l5pOzHBz8mFOlbcifTxzfyYbgEmoUqjxLFHZkjlbHXs=
|
||||||
github.com/lasiar/canonicalheader v1.1.1/go.mod h1:cXkb3Dlk6XXy+8MVQnF23CYKWlyA7kfQhSw2CcZtZb0=
|
github.com/ldez/exptostd v0.4.2/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ=
|
||||||
github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg=
|
github.com/ldez/gomoddirectives v0.6.1 h1:Z+PxGAY+217f/bSGjNZr/b2KTXcyYLgiWI6geMBN2Qc=
|
||||||
github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g=
|
github.com/ldez/gomoddirectives v0.6.1/go.mod h1:cVBiu3AHR9V31em9u2kwfMKD43ayN5/XDgr+cdaFaKs=
|
||||||
github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo=
|
github.com/ldez/grignotin v0.9.0 h1:MgOEmjZIVNn6p5wPaGp/0OKWyvq42KnzAt/DAb8O4Ow=
|
||||||
github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4=
|
github.com/ldez/grignotin v0.9.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk=
|
||||||
|
github.com/ldez/tagliatelle v0.7.1 h1:bTgKjjc2sQcsgPiT902+aadvMjCeMHrY7ly2XKFORIk=
|
||||||
|
github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I=
|
||||||
|
github.com/ldez/usetesting v0.4.2 h1:J2WwbrFGk3wx4cZwSMiCQQ00kjGR0+tuuyW0Lqm4lwA=
|
||||||
|
github.com/ldez/usetesting v0.4.2/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ=
|
||||||
github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
|
github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
|
||||||
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
|
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
|
||||||
github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM=
|
|
||||||
github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM=
|
|
||||||
github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk=
|
github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk=
|
||||||
github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
|
github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
|
||||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||||
@@ -357,23 +369,23 @@ github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s
|
|||||||
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
|
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
|
||||||
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
|
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
|
||||||
github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc=
|
github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc=
|
||||||
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE=
|
github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4=
|
||||||
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs=
|
||||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
github.com/matryer/moq v0.5.0 h1:h2PJUYjZSiyEahzVogDRmrgL9Bsx9xYAl8l+LPfmwL8=
|
github.com/matryer/moq v0.5.3 h1:4femQCFmBUwFPYs8VfM5ID7AI67/DTEDRBbTtSWy7GU=
|
||||||
github.com/matryer/moq v0.5.0/go.mod h1:39GTnrD0mVWHPvWdYj5ki/lxfhLQEtHcLh+tWoYF/iE=
|
github.com/matryer/moq v0.5.3/go.mod h1:8288Qkw7gMZhUP3cIN86GG7g5p9jRuZH8biXLW4RXvQ=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
|
github.com/mgechev/revive v1.7.0 h1:JyeQ4yO5K8aZhIKf5rec56u0376h8AlKNQEmjfkjKlY=
|
||||||
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
|
github.com/mgechev/revive v1.7.0/go.mod h1:qZnwcNhoguE58dfi96IJeSTPeZQejNeoMQLUZGi4SW4=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
@@ -393,14 +405,14 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK
|
|||||||
github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs=
|
github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs=
|
||||||
github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
|
github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
|
||||||
github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
|
github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
|
||||||
github.com/nunnatsa/ginkgolinter v0.16.2 h1:8iLqHIZvN4fTLDC0Ke9tbSZVcyVHoBs0HIbnVSxfHJk=
|
github.com/nunnatsa/ginkgolinter v0.19.1 h1:mjwbOlDQxZi9Cal+KfbEJTCz327OLNfwNvoZ70NJ+c4=
|
||||||
github.com/nunnatsa/ginkgolinter v0.16.2/go.mod h1:4tWRinDN1FeJgU+iJANW/kz7xKN5nYRAOfJDQUS9dOQ=
|
github.com/nunnatsa/ginkgolinter v0.19.1/go.mod h1:jkQ3naZDmxaZMXPWaS9rblH+i+GWXQCaS/JFIWcOH2s=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
|
||||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
|
||||||
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
|
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||||
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
|
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||||
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
|
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
|
||||||
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
|
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
|
||||||
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
|
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
|
||||||
@@ -418,8 +430,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg8/OwcYY=
|
github.com/polyfloyd/go-errorlint v1.7.1 h1:RyLVXIbosq1gBdk/pChWA8zWYLsq9UEw7a1L5TVMCnA=
|
||||||
github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw=
|
github.com/polyfloyd/go-errorlint v1.7.1/go.mod h1:aXjNb1x2TNhoLsk26iv1yl7a+zTnXPhwEMtEXukiLR8=
|
||||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
@@ -454,26 +466,29 @@ github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl
|
|||||||
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
|
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
|
||||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
|
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
|
||||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
|
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
|
||||||
|
github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI=
|
||||||
|
github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
|
github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
|
||||||
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
|
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
|
||||||
github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
|
github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
|
||||||
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
|
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
|
||||||
github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc=
|
github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0=
|
||||||
github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
|
github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4=
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||||
github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
|
github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
|
||||||
github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
|
github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
|
||||||
github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI=
|
github.com/sashamelentyev/usestdlibvars v1.28.0 h1:jZnudE2zKCtYlGzLVreNp5pmCdOxXUzwsMDBkR21cyQ=
|
||||||
github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
|
github.com/sashamelentyev/usestdlibvars v1.28.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
|
||||||
github.com/securego/gosec/v2 v2.21.2 h1:deZp5zmYf3TWwU7A7cR2+SolbTpZ3HQiwFqnzQyEl3M=
|
github.com/securego/gosec/v2 v2.22.1 h1:IcBt3TpI5Y9VN1YlwjSpM2cHu0i3Iw52QM+PQeg7jN8=
|
||||||
github.com/securego/gosec/v2 v2.21.2/go.mod h1:au33kg78rNseF5PwPnTWhuYBFf534bvJRvOrgZ/bFzU=
|
github.com/securego/gosec/v2 v2.22.1/go.mod h1:4bb95X4Jz7VSEPdVjC0hD7C/yR6kdeUBvCPOy9gDQ0g=
|
||||||
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU=
|
|
||||||
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
|
|
||||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
@@ -483,28 +498,29 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
|||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE=
|
github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE=
|
||||||
github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4=
|
github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4=
|
||||||
github.com/sivchari/tenv v1.10.0 h1:g/hzMA+dBCKqGXgW8AV/1xIWhAvDrx0zFKNR48NFMg0=
|
github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY=
|
||||||
github.com/sivchari/tenv v1.10.0/go.mod h1:tdY24masnVoZFxYrHv/nD6Tc8FbkEtAQEEziXpyMgqY=
|
github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw=
|
||||||
github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00=
|
github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM=
|
||||||
github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo=
|
github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c=
|
||||||
github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
|
github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
|
||||||
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
|
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
|
||||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
|
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
|
||||||
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
|
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
|
||||||
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
|
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
|
||||||
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
|
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
|
||||||
github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc=
|
github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4=
|
||||||
github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I=
|
github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
@@ -519,32 +535,34 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||||
github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM=
|
github.com/tdakkota/asciicheck v0.4.1 h1:bm0tbcmi0jezRA2b5kg4ozmMuGAFotKI3RZfrhfovg8=
|
||||||
github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg=
|
github.com/tdakkota/asciicheck v0.4.1/go.mod h1:0k7M3rCfRXb0Z6bwgvkEIMleKH3kXNz9UqJ9Xuqopr8=
|
||||||
github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
|
github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
|
||||||
github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
|
github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
|
||||||
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=
|
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=
|
||||||
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
|
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
|
||||||
github.com/tetafro/godot v1.4.17 h1:pGzu+Ye7ZUEFx7LHU0dAKmCOXWsPjl7qA6iMGndsjPs=
|
github.com/tetafro/godot v1.5.0 h1:aNwfVI4I3+gdxjMgYPus9eHmoBeJIbnajOyqZYStzuw=
|
||||||
github.com/tetafro/godot v1.4.17/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
|
github.com/tetafro/godot v1.5.0/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
|
||||||
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M=
|
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 h1:y4mJRFlM6fUyPhoXuFg/Yu02fg/nIPFMOY8tOqppoFg=
|
||||||
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ=
|
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460=
|
||||||
github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4=
|
github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg=
|
||||||
github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg=
|
github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8=
|
||||||
github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4=
|
github.com/tomarrell/wrapcheck/v2 v2.10.0 h1:SzRCryzy4IrAH7bVGG4cK40tNUhmVmMDuJujy4XwYDg=
|
||||||
github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
|
github.com/tomarrell/wrapcheck/v2 v2.10.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
|
||||||
github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
|
github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
|
||||||
github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
|
github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
|
||||||
github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI=
|
github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI=
|
||||||
github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4=
|
github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA=
|
||||||
github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ=
|
github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g=
|
||||||
github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
|
github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
|
||||||
github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM=
|
github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA=
|
||||||
github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U=
|
github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU=
|
||||||
|
github.com/uudashr/iface v1.3.1 h1:bA51vmVx1UIhiIsQFSNq6GZ6VPTk3WNMZgRiCe9R29U=
|
||||||
|
github.com/uudashr/iface v1.3.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
|
||||||
github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
|
github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
|
||||||
github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
|
github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
|
||||||
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
|
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
|
||||||
@@ -564,10 +582,10 @@ gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo=
|
|||||||
gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8=
|
gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8=
|
||||||
go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ=
|
go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ=
|
||||||
go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28=
|
go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28=
|
||||||
go-simpler.org/musttag v0.12.2 h1:J7lRc2ysXOq7eM8rwaTYnNrHd5JwjppzB6mScysB2Cs=
|
go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE=
|
||||||
go-simpler.org/musttag v0.12.2/go.mod h1:uN1DVIasMTQKk6XSik7yrJoEysGtR2GRqvWnI9S7TYM=
|
go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM=
|
||||||
go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY=
|
go-simpler.org/sloglint v0.9.0 h1:/40NQtjRx9txvsB/RN022KsUJU+zaaSb/9q9BSefSrE=
|
||||||
go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo=
|
go-simpler.org/sloglint v0.9.0/go.mod h1:G/OrAF6uxj48sHahCzrbarVMptL2kjWTaUeC8+fOGww=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
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.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
@@ -575,8 +593,8 @@ 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.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
|
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||||
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
|
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
@@ -590,7 +608,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/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/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
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-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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -601,12 +620,12 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/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-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/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
|
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
|
||||||
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
|
||||||
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||||
golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||||
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8=
|
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac h1:TSSpLIG4v+p0rPv1pNOQtl1I8knsO4S9trOxNMOLVP4=
|
||||||
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
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/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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@@ -629,14 +648,15 @@ 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.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.1/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=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
|
||||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||||
|
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -671,12 +691,14 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
|||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
|
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||||
|
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
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-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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -696,8 +718,10 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||||
|
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -731,7 +755,6 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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-20201119102817-f84b799fce68/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -745,20 +768,22 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -767,10 +792,12 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
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-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/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -780,7 +807,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
|
|||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
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-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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
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-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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
@@ -788,10 +814,8 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
|
|||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/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-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-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/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-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-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/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-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-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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
@@ -822,20 +846,19 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
|
|||||||
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
|
||||||
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
|
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
|
||||||
golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
|
golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
|
||||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
|
||||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||||
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
|
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||||
|
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||||
|
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -915,8 +938,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
|||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
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-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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -943,8 +966,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
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.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
|
honnef.co/go/tools v0.6.0 h1:TAODvD3knlq75WCp2nyGJtT4LeRV/o7NN9nYPeVJXf8=
|
||||||
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
|
honnef.co/go/tools v0.6.0/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4=
|
||||||
mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
|
mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
|
||||||
mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=
|
mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=
|
||||||
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U=
|
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U=
|
||||||
|
|||||||
25
go.mod
25
go.mod
@@ -1,31 +1,32 @@
|
|||||||
module github.com/NVIDIA/nvidia-container-toolkit
|
module github.com/NVIDIA/nvidia-container-toolkit
|
||||||
|
|
||||||
go 1.20
|
go 1.23.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/NVIDIA/go-nvlib v0.6.1
|
github.com/NVIDIA/go-nvlib v0.7.1
|
||||||
github.com/NVIDIA/go-nvml v0.12.4-0
|
github.com/NVIDIA/go-nvml v0.12.4-1
|
||||||
github.com/fsnotify/fsnotify v1.7.0
|
|
||||||
github.com/moby/sys/symlink v0.3.0
|
github.com/moby/sys/symlink v0.3.0
|
||||||
github.com/opencontainers/runtime-spec v1.2.0
|
github.com/opencontainers/runc v1.2.5
|
||||||
|
github.com/opencontainers/runtime-spec v1.2.1
|
||||||
github.com/pelletier/go-toml v1.9.5
|
github.com/pelletier/go-toml v1.9.5
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/urfave/cli/v2 v2.27.4
|
github.com/urfave/cli/v2 v2.27.6
|
||||||
golang.org/x/mod v0.20.0
|
golang.org/x/mod v0.24.0
|
||||||
golang.org/x/sys v0.26.0
|
golang.org/x/sys v0.31.0
|
||||||
tags.cncf.io/container-device-interface v0.8.0
|
tags.cncf.io/container-device-interface v0.8.1
|
||||||
tags.cncf.io/container-device-interface/specs-go v0.8.0
|
tags.cncf.io/container-device-interface/specs-go v0.8.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||||
|
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect
|
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect
|
||||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||||
|
|||||||
40
go.sum
40
go.sum
@@ -1,12 +1,14 @@
|
|||||||
github.com/NVIDIA/go-nvlib v0.6.1 h1:0/5FvaKvDJoJeJ+LFlh+NDQMxMlVw9wOXrOVrGXttfE=
|
github.com/NVIDIA/go-nvlib v0.7.1 h1:7HHPZxoCjSLm1NgaRRjuhI8ffMCpc5Vgpg5yxQYUff8=
|
||||||
github.com/NVIDIA/go-nvlib v0.6.1/go.mod h1:9UrsLGx/q1OrENygXjOuM5Ey5KCtiZhbvBlbUIxtGWY=
|
github.com/NVIDIA/go-nvlib v0.7.1/go.mod h1:2Kh2kYSP5IJ8EKf0/SYDzHiQKb9EJkwOf2LQzu6pXzY=
|
||||||
github.com/NVIDIA/go-nvml v0.12.4-0 h1:4tkbB3pT1O77JGr0gQ6uD8FrsUPqP1A/EOEm2wI1TUg=
|
github.com/NVIDIA/go-nvml v0.12.4-1 h1:WKUvqshhWSNTfm47ETRhv0A0zJyr1ncCuHiXwoTrBEc=
|
||||||
github.com/NVIDIA/go-nvml v0.12.4-0/go.mod h1:8Llmj+1Rr+9VGGwZuRer5N/aCjxGuR5nPb/9ebBiIEQ=
|
github.com/NVIDIA/go-nvml v0.12.4-1/go.mod h1:8Llmj+1Rr+9VGGwZuRer5N/aCjxGuR5nPb/9ebBiIEQ=
|
||||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -31,9 +33,11 @@ github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34
|
|||||||
github.com/moby/sys/symlink v0.3.0 h1:GZX89mEZ9u53f97npBy4Rc3vJKj7JBDj/PN2I22GrNU=
|
github.com/moby/sys/symlink v0.3.0 h1:GZX89mEZ9u53f97npBy4Rc3vJKj7JBDj/PN2I22GrNU=
|
||||||
github.com/moby/sys/symlink v0.3.0/go.mod h1:3eNdhduHmYPcgsJtZXW1W4XUJdZGBIkttZ8xKqPUJq0=
|
github.com/moby/sys/symlink v0.3.0/go.mod h1:3eNdhduHmYPcgsJtZXW1W4XUJdZGBIkttZ8xKqPUJq0=
|
||||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||||
|
github.com/opencontainers/runc v1.2.5 h1:8KAkq3Wrem8bApgOHyhRI/8IeLXIfmZ6Qaw6DNSLnA4=
|
||||||
|
github.com/opencontainers/runc v1.2.5/go.mod h1:dOQeFo29xZKBNeRBI0B19mJtfHv68YgCTh1X+YphA+4=
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
|
||||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0=
|
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0=
|
||||||
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI=
|
github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI=
|
||||||
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||||
@@ -55,13 +59,13 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
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/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.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8=
|
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
|
||||||
github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ=
|
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
@@ -71,13 +75,13 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
|
|||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
@@ -88,7 +92,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
tags.cncf.io/container-device-interface v0.8.0 h1:8bCFo/g9WODjWx3m6EYl3GfUG31eKJbaggyBDxEldRc=
|
tags.cncf.io/container-device-interface v0.8.1 h1:c0jN4Mt6781jD67NdPajmZlD1qrqQyov/Xfoab37lj0=
|
||||||
tags.cncf.io/container-device-interface v0.8.0/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y=
|
tags.cncf.io/container-device-interface v0.8.1/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y=
|
||||||
tags.cncf.io/container-device-interface/specs-go v0.8.0 h1:QYGFzGxvYK/ZLMrjhvY0RjpUavIn4KcmRmVP/JjdBTA=
|
tags.cncf.io/container-device-interface/specs-go v0.8.0 h1:QYGFzGxvYK/ZLMrjhvY0RjpUavIn4KcmRmVP/JjdBTA=
|
||||||
tags.cncf.io/container-device-interface/specs-go v0.8.0/go.mod h1:BhJIkjjPh4qpys+qm4DAYtUyryaTDg9zris+AczXyws=
|
tags.cncf.io/container-device-interface/specs-go v0.8.0/go.mod h1:BhJIkjjPh4qpys+qm4DAYtUyryaTDg9zris+AczXyws=
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -34,29 +35,62 @@ type ContainerCLIConfig struct {
|
|||||||
NoPivot bool `toml:"no-pivot,omitempty"`
|
NoPivot bool `toml:"no-pivot,omitempty"`
|
||||||
NoCgroups bool `toml:"no-cgroups"`
|
NoCgroups bool `toml:"no-cgroups"`
|
||||||
User string `toml:"user"`
|
User string `toml:"user"`
|
||||||
Ldconfig string `toml:"ldconfig"`
|
// Ldconfig represents the path to the ldconfig binary to be used to update
|
||||||
|
// the ldcache in a container as it is being created.
|
||||||
|
// If this path starts with a '@' the path is relative to the host and if
|
||||||
|
// not it is treated as a container path.
|
||||||
|
//
|
||||||
|
// Note that the use of container paths are disabled by default and if this
|
||||||
|
// is required, the features.allow-ldconfig-from-container feature gate must
|
||||||
|
// be enabled explicitly.
|
||||||
|
Ldconfig ldconfigPath `toml:"ldconfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NormalizeLDConfigPath returns the resolved path of the configured LDConfig binary.
|
// NormalizeLDConfigPath returns the resolved path of the configured LDConfig binary.
|
||||||
// This is only done for host LDConfigs and is required to handle systems where
|
// This is only done for host LDConfigs and is required to handle systems where
|
||||||
// /sbin/ldconfig is a wrapper around /sbin/ldconfig.real.
|
// /sbin/ldconfig is a wrapper around /sbin/ldconfig.real.
|
||||||
func (c *ContainerCLIConfig) NormalizeLDConfigPath() string {
|
func (c *ContainerCLIConfig) NormalizeLDConfigPath() string {
|
||||||
return NormalizeLDConfigPath(c.Ldconfig)
|
return string(c.Ldconfig.normalize())
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ldconfigPath is used to represent the path to ldconfig.
|
||||||
|
type ldconfigPath string
|
||||||
|
|
||||||
|
func (p ldconfigPath) assertValid(allowContainerRelativePath bool) error {
|
||||||
|
if p.isHostRelative() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if allowContainerRelativePath {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("nvidia-container-cli.ldconfig value %q is not host-relative (does not start with a '@')", p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p ldconfigPath) isHostRelative() bool {
|
||||||
|
return strings.HasPrefix(string(p), "@")
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize returns the resolved path of the configured LDConfig binary.
|
||||||
|
// This is only done for host LDConfigs and is required to handle systems where
|
||||||
|
// /sbin/ldconfig is a wrapper around /sbin/ldconfig.real.
|
||||||
|
func (p ldconfigPath) normalize() ldconfigPath {
|
||||||
|
if !p.isHostRelative() {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
path := string(p)
|
||||||
|
trimmedPath := strings.TrimSuffix(strings.TrimPrefix(path, "@"), ".real")
|
||||||
|
// If the .real path exists, we return that.
|
||||||
|
if _, err := os.Stat(trimmedPath + ".real"); err == nil {
|
||||||
|
return ldconfigPath("@" + trimmedPath + ".real")
|
||||||
|
}
|
||||||
|
// If the .real path does not exists (or cannot be read) we return the non-.real path.
|
||||||
|
return ldconfigPath("@" + trimmedPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NormalizeLDConfigPath returns the resolved path of the configured LDConfig binary.
|
// NormalizeLDConfigPath returns the resolved path of the configured LDConfig binary.
|
||||||
// This is only done for host LDConfigs and is required to handle systems where
|
// This is only done for host LDConfigs and is required to handle systems where
|
||||||
// /sbin/ldconfig is a wrapper around /sbin/ldconfig.real.
|
// /sbin/ldconfig is a wrapper around /sbin/ldconfig.real.
|
||||||
func NormalizeLDConfigPath(path string) string {
|
func NormalizeLDConfigPath(path string) string {
|
||||||
if !strings.HasPrefix(path, "@") {
|
return string(ldconfigPath(path).normalize())
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
trimmedPath := strings.TrimSuffix(strings.TrimPrefix(path, "@"), ".real")
|
|
||||||
// If the .real path exists, we return that.
|
|
||||||
if _, err := os.Stat(trimmedPath + ".real"); err == nil {
|
|
||||||
return "@" + trimmedPath + ".real"
|
|
||||||
}
|
|
||||||
// If the .real path does not exists (or cannot be read) we return the non-.real path.
|
|
||||||
return "@" + trimmedPath
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func TestNormalizeLDConfigPath(t *testing.T) {
|
|||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
ldconfig string
|
ldconfig ldconfigPath
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -51,12 +51,12 @@ func TestNormalizeLDConfigPath(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "host .real file exists is returned",
|
description: "host .real file exists is returned",
|
||||||
ldconfig: "@" + filepath.Join(testDir, "exists.real"),
|
ldconfig: ldconfigPath("@" + filepath.Join(testDir, "exists.real")),
|
||||||
expected: "@" + filepath.Join(testDir, "exists.real"),
|
expected: "@" + filepath.Join(testDir, "exists.real"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "host resolves .real file",
|
description: "host resolves .real file",
|
||||||
ldconfig: "@" + filepath.Join(testDir, "exists"),
|
ldconfig: ldconfigPath("@" + filepath.Join(testDir, "exists")),
|
||||||
expected: "@" + filepath.Join(testDir, "exists.real"),
|
expected: "@" + filepath.Join(testDir, "exists.real"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -51,6 +52,8 @@ var (
|
|||||||
NVIDIAContainerToolkitExecutable = "nvidia-container-toolkit"
|
NVIDIAContainerToolkitExecutable = "nvidia-container-toolkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errInvalidConfig = errors.New("invalid config value")
|
||||||
|
|
||||||
// Config represents the contents of the config.toml file for the NVIDIA Container Toolkit
|
// Config represents the contents of the config.toml file for the NVIDIA Container Toolkit
|
||||||
// Note: This is currently duplicated by the HookConfig in cmd/nvidia-container-toolkit/hook_config.go
|
// Note: This is currently duplicated by the HookConfig in cmd/nvidia-container-toolkit/hook_config.go
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -118,6 +121,9 @@ func GetDefault() (*Config, error) {
|
|||||||
AnnotationPrefixes: []string{cdi.AnnotationPrefix},
|
AnnotationPrefixes: []string{cdi.AnnotationPrefix},
|
||||||
SpecDirs: cdi.DefaultSpecDirs,
|
SpecDirs: cdi.DefaultSpecDirs,
|
||||||
},
|
},
|
||||||
|
JitCDI: jitCDIModeConfig{
|
||||||
|
LoadKernelModules: []string{"nvidia", "nvidia-uvm", "nvidia-modeset"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||||
@@ -127,8 +133,20 @@ func GetDefault() (*Config, error) {
|
|||||||
return &d, nil
|
return &d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLdConfigPath() string {
|
// assertValid checks for a valid config.
|
||||||
return NormalizeLDConfigPath("@/sbin/ldconfig")
|
func (c *Config) assertValid() error {
|
||||||
|
err := c.NVIDIAContainerCLIConfig.Ldconfig.assertValid(c.Features.AllowLDConfigFromContainer.IsEnabled())
|
||||||
|
if err != nil {
|
||||||
|
return errors.Join(err, errInvalidConfig)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getLdConfigPath allows us to override this function for testing.
|
||||||
|
var getLdConfigPath = getLdConfigPathStub
|
||||||
|
|
||||||
|
func getLdConfigPathStub() ldconfigPath {
|
||||||
|
return ldconfigPath("@/sbin/ldconfig").normalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserGroup() string {
|
func getUserGroup() string {
|
||||||
|
|||||||
@@ -44,23 +44,21 @@ func TestGetConfigWithCustomConfig(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetConfig(t *testing.T) {
|
func TestGetConfig(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
contents []string
|
contents []string
|
||||||
expectedError error
|
expectedError error
|
||||||
inspectLdconfig bool
|
distIdsLike []string
|
||||||
distIdsLike []string
|
expectedConfig *Config
|
||||||
expectedConfig *Config
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
description: "empty config is default",
|
description: "empty config is default",
|
||||||
inspectLdconfig: true,
|
|
||||||
expectedConfig: &Config{
|
expectedConfig: &Config{
|
||||||
AcceptEnvvarUnprivileged: true,
|
AcceptEnvvarUnprivileged: true,
|
||||||
SupportedDriverCapabilities: "compat32,compute,display,graphics,ngx,utility,video",
|
SupportedDriverCapabilities: "compat32,compute,display,graphics,ngx,utility,video",
|
||||||
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
Root: "",
|
Root: "",
|
||||||
LoadKmods: true,
|
LoadKmods: true,
|
||||||
Ldconfig: "WAS_CHECKED",
|
Ldconfig: "@/test/ld/config/path",
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
||||||
DebugFilePath: "/dev/null",
|
DebugFilePath: "/dev/null",
|
||||||
@@ -76,6 +74,9 @@ func TestGetConfig(t *testing.T) {
|
|||||||
AnnotationPrefixes: []string{"cdi.k8s.io/"},
|
AnnotationPrefixes: []string{"cdi.k8s.io/"},
|
||||||
SpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
|
SpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
|
||||||
},
|
},
|
||||||
|
JitCDI: jitCDIModeConfig{
|
||||||
|
LoadKernelModules: []string{"nvidia", "nvidia-uvm", "nvidia-modeset"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||||
@@ -93,7 +94,7 @@ func TestGetConfig(t *testing.T) {
|
|||||||
"supported-driver-capabilities = \"compute,utility\"",
|
"supported-driver-capabilities = \"compute,utility\"",
|
||||||
"nvidia-container-cli.root = \"/bar/baz\"",
|
"nvidia-container-cli.root = \"/bar/baz\"",
|
||||||
"nvidia-container-cli.load-kmods = false",
|
"nvidia-container-cli.load-kmods = false",
|
||||||
"nvidia-container-cli.ldconfig = \"/foo/bar/ldconfig\"",
|
"nvidia-container-cli.ldconfig = \"@/foo/bar/ldconfig\"",
|
||||||
"nvidia-container-cli.user = \"foo:bar\"",
|
"nvidia-container-cli.user = \"foo:bar\"",
|
||||||
"nvidia-container-runtime.debug = \"/foo/bar\"",
|
"nvidia-container-runtime.debug = \"/foo/bar\"",
|
||||||
"nvidia-container-runtime.discover-mode = \"not-legacy\"",
|
"nvidia-container-runtime.discover-mode = \"not-legacy\"",
|
||||||
@@ -104,6 +105,7 @@ func TestGetConfig(t *testing.T) {
|
|||||||
"nvidia-container-runtime.modes.cdi.annotation-prefixes = [\"cdi.k8s.io/\", \"example.vendor.com/\",]",
|
"nvidia-container-runtime.modes.cdi.annotation-prefixes = [\"cdi.k8s.io/\", \"example.vendor.com/\",]",
|
||||||
"nvidia-container-runtime.modes.cdi.spec-dirs = [\"/except/etc/cdi\", \"/not/var/run/cdi\",]",
|
"nvidia-container-runtime.modes.cdi.spec-dirs = [\"/except/etc/cdi\", \"/not/var/run/cdi\",]",
|
||||||
"nvidia-container-runtime.modes.csv.mount-spec-path = \"/not/etc/nvidia-container-runtime/host-files-for-container.d\"",
|
"nvidia-container-runtime.modes.csv.mount-spec-path = \"/not/etc/nvidia-container-runtime/host-files-for-container.d\"",
|
||||||
|
"nvidia-container-runtime.modes.jit-cdi.load-kernel-modules = [\"foo\"]",
|
||||||
"nvidia-container-runtime-hook.path = \"/foo/bar/nvidia-container-runtime-hook\"",
|
"nvidia-container-runtime-hook.path = \"/foo/bar/nvidia-container-runtime-hook\"",
|
||||||
"nvidia-ctk.path = \"/foo/bar/nvidia-ctk\"",
|
"nvidia-ctk.path = \"/foo/bar/nvidia-ctk\"",
|
||||||
},
|
},
|
||||||
@@ -113,7 +115,7 @@ func TestGetConfig(t *testing.T) {
|
|||||||
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
Root: "/bar/baz",
|
Root: "/bar/baz",
|
||||||
LoadKmods: false,
|
LoadKmods: false,
|
||||||
Ldconfig: "/foo/bar/ldconfig",
|
Ldconfig: "@/foo/bar/ldconfig",
|
||||||
User: "foo:bar",
|
User: "foo:bar",
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
||||||
@@ -136,6 +138,9 @@ func TestGetConfig(t *testing.T) {
|
|||||||
"/not/var/run/cdi",
|
"/not/var/run/cdi",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
JitCDI: jitCDIModeConfig{
|
||||||
|
LoadKernelModules: []string{"foo"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||||
@@ -146,6 +151,56 @@ func TestGetConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "feature allows ldconfig to be overridden",
|
||||||
|
contents: []string{
|
||||||
|
"[nvidia-container-cli]",
|
||||||
|
"ldconfig = \"/foo/bar/ldconfig\"",
|
||||||
|
"[features]",
|
||||||
|
"allow-ldconfig-from-container = true",
|
||||||
|
},
|
||||||
|
expectedConfig: &Config{
|
||||||
|
AcceptEnvvarUnprivileged: true,
|
||||||
|
SupportedDriverCapabilities: "compat32,compute,display,graphics,ngx,utility,video",
|
||||||
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
|
Ldconfig: "/foo/bar/ldconfig",
|
||||||
|
LoadKmods: true,
|
||||||
|
},
|
||||||
|
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
||||||
|
DebugFilePath: "/dev/null",
|
||||||
|
LogLevel: "info",
|
||||||
|
Runtimes: []string{"docker-runc", "runc", "crun"},
|
||||||
|
Mode: "auto",
|
||||||
|
Modes: modesConfig{
|
||||||
|
CSV: csvModeConfig{
|
||||||
|
MountSpecPath: "/etc/nvidia-container-runtime/host-files-for-container.d",
|
||||||
|
},
|
||||||
|
CDI: cdiModeConfig{
|
||||||
|
DefaultKind: "nvidia.com/gpu",
|
||||||
|
AnnotationPrefixes: []string{
|
||||||
|
"cdi.k8s.io/",
|
||||||
|
},
|
||||||
|
SpecDirs: []string{
|
||||||
|
"/etc/cdi",
|
||||||
|
"/var/run/cdi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
JitCDI: jitCDIModeConfig{
|
||||||
|
LoadKernelModules: []string{"nvidia", "nvidia-uvm", "nvidia-modeset"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||||
|
Path: "nvidia-container-runtime-hook",
|
||||||
|
},
|
||||||
|
NVIDIACTKConfig: CTKConfig{
|
||||||
|
Path: "nvidia-ctk",
|
||||||
|
},
|
||||||
|
Features: features{
|
||||||
|
AllowLDConfigFromContainer: ptr(feature(true)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "config options set in section",
|
description: "config options set in section",
|
||||||
contents: []string{
|
contents: []string{
|
||||||
@@ -154,7 +209,7 @@ func TestGetConfig(t *testing.T) {
|
|||||||
"[nvidia-container-cli]",
|
"[nvidia-container-cli]",
|
||||||
"root = \"/bar/baz\"",
|
"root = \"/bar/baz\"",
|
||||||
"load-kmods = false",
|
"load-kmods = false",
|
||||||
"ldconfig = \"/foo/bar/ldconfig\"",
|
"ldconfig = \"@/foo/bar/ldconfig\"",
|
||||||
"user = \"foo:bar\"",
|
"user = \"foo:bar\"",
|
||||||
"[nvidia-container-runtime]",
|
"[nvidia-container-runtime]",
|
||||||
"debug = \"/foo/bar\"",
|
"debug = \"/foo/bar\"",
|
||||||
@@ -168,6 +223,8 @@ func TestGetConfig(t *testing.T) {
|
|||||||
"spec-dirs = [\"/except/etc/cdi\", \"/not/var/run/cdi\",]",
|
"spec-dirs = [\"/except/etc/cdi\", \"/not/var/run/cdi\",]",
|
||||||
"[nvidia-container-runtime.modes.csv]",
|
"[nvidia-container-runtime.modes.csv]",
|
||||||
"mount-spec-path = \"/not/etc/nvidia-container-runtime/host-files-for-container.d\"",
|
"mount-spec-path = \"/not/etc/nvidia-container-runtime/host-files-for-container.d\"",
|
||||||
|
"[nvidia-container-runtime.modes.jit-cdi]",
|
||||||
|
"load-kernel-modules = [\"foo\"]",
|
||||||
"[nvidia-container-runtime-hook]",
|
"[nvidia-container-runtime-hook]",
|
||||||
"path = \"/foo/bar/nvidia-container-runtime-hook\"",
|
"path = \"/foo/bar/nvidia-container-runtime-hook\"",
|
||||||
"[nvidia-ctk]",
|
"[nvidia-ctk]",
|
||||||
@@ -179,7 +236,7 @@ func TestGetConfig(t *testing.T) {
|
|||||||
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
Root: "/bar/baz",
|
Root: "/bar/baz",
|
||||||
LoadKmods: false,
|
LoadKmods: false,
|
||||||
Ldconfig: "/foo/bar/ldconfig",
|
Ldconfig: "@/foo/bar/ldconfig",
|
||||||
User: "foo:bar",
|
User: "foo:bar",
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
||||||
@@ -202,6 +259,9 @@ func TestGetConfig(t *testing.T) {
|
|||||||
"/not/var/run/cdi",
|
"/not/var/run/cdi",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
JitCDI: jitCDIModeConfig{
|
||||||
|
LoadKernelModules: []string{"foo"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||||
@@ -213,16 +273,15 @@ func TestGetConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "suse config",
|
description: "suse config",
|
||||||
distIdsLike: []string{"suse", "opensuse"},
|
distIdsLike: []string{"suse", "opensuse"},
|
||||||
inspectLdconfig: true,
|
|
||||||
expectedConfig: &Config{
|
expectedConfig: &Config{
|
||||||
AcceptEnvvarUnprivileged: true,
|
AcceptEnvvarUnprivileged: true,
|
||||||
SupportedDriverCapabilities: "compat32,compute,display,graphics,ngx,utility,video",
|
SupportedDriverCapabilities: "compat32,compute,display,graphics,ngx,utility,video",
|
||||||
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
Root: "",
|
Root: "",
|
||||||
LoadKmods: true,
|
LoadKmods: true,
|
||||||
Ldconfig: "WAS_CHECKED",
|
Ldconfig: "@/test/ld/config/path",
|
||||||
User: "root:video",
|
User: "root:video",
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
||||||
@@ -239,6 +298,9 @@ func TestGetConfig(t *testing.T) {
|
|||||||
AnnotationPrefixes: []string{"cdi.k8s.io/"},
|
AnnotationPrefixes: []string{"cdi.k8s.io/"},
|
||||||
SpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
|
SpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
|
||||||
},
|
},
|
||||||
|
JitCDI: jitCDIModeConfig{
|
||||||
|
LoadKernelModules: []string{"nvidia", "nvidia-uvm", "nvidia-modeset"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||||
@@ -250,9 +312,8 @@ func TestGetConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "suse config overrides user",
|
description: "suse config overrides user",
|
||||||
distIdsLike: []string{"suse", "opensuse"},
|
distIdsLike: []string{"suse", "opensuse"},
|
||||||
inspectLdconfig: true,
|
|
||||||
contents: []string{
|
contents: []string{
|
||||||
"nvidia-container-cli.user = \"foo:bar\"",
|
"nvidia-container-cli.user = \"foo:bar\"",
|
||||||
},
|
},
|
||||||
@@ -262,7 +323,7 @@ func TestGetConfig(t *testing.T) {
|
|||||||
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
Root: "",
|
Root: "",
|
||||||
LoadKmods: true,
|
LoadKmods: true,
|
||||||
Ldconfig: "WAS_CHECKED",
|
Ldconfig: "@/test/ld/config/path",
|
||||||
User: "foo:bar",
|
User: "foo:bar",
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
NVIDIAContainerRuntimeConfig: RuntimeConfig{
|
||||||
@@ -279,6 +340,9 @@ func TestGetConfig(t *testing.T) {
|
|||||||
AnnotationPrefixes: []string{"cdi.k8s.io/"},
|
AnnotationPrefixes: []string{"cdi.k8s.io/"},
|
||||||
SpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
|
SpecDirs: []string{"/etc/cdi", "/var/run/cdi"},
|
||||||
},
|
},
|
||||||
|
JitCDI: jitCDIModeConfig{
|
||||||
|
LoadKernelModules: []string{"nvidia", "nvidia-uvm", "nvidia-modeset"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
NVIDIAContainerRuntimeHookConfig: RuntimeHookConfig{
|
||||||
@@ -293,6 +357,7 @@ func TestGetConfig(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
defer setGetLdConfigPathForTest()()
|
||||||
defer setGetDistIDLikeForTest(tc.distIdsLike)()
|
defer setGetDistIDLikeForTest(tc.distIdsLike)()
|
||||||
reader := strings.NewReader(strings.Join(tc.contents, "\n"))
|
reader := strings.NewReader(strings.Join(tc.contents, "\n"))
|
||||||
|
|
||||||
@@ -305,21 +370,63 @@ func TestGetConfig(t *testing.T) {
|
|||||||
cfg, err := tomlCfg.Config()
|
cfg, err := tomlCfg.Config()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We first handle the ldconfig path since this is currently system-dependent.
|
|
||||||
if tc.inspectLdconfig {
|
|
||||||
ldconfig := cfg.NVIDIAContainerCLIConfig.Ldconfig
|
|
||||||
require.True(t, strings.HasPrefix(ldconfig, "@/sbin/ldconfig"))
|
|
||||||
remaining := strings.TrimPrefix(ldconfig, "@/sbin/ldconfig")
|
|
||||||
require.True(t, remaining == ".real" || remaining == "")
|
|
||||||
|
|
||||||
cfg.NVIDIAContainerCLIConfig.Ldconfig = "WAS_CHECKED"
|
|
||||||
}
|
|
||||||
|
|
||||||
require.EqualValues(t, tc.expectedConfig, cfg)
|
require.EqualValues(t, tc.expectedConfig, cfg)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAssertValid(t *testing.T) {
|
||||||
|
defer setGetLdConfigPathForTest()()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
config *Config
|
||||||
|
expectedError error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "default is valid",
|
||||||
|
config: func() *Config {
|
||||||
|
config, _ := GetDefault()
|
||||||
|
return config
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "alternative host ldconfig path is valid",
|
||||||
|
config: &Config{
|
||||||
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
|
Ldconfig: "@/some/host/path",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "non-host path is invalid",
|
||||||
|
config: &Config{
|
||||||
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
|
Ldconfig: "/non/host/path",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: errInvalidConfig,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "feature flag allows non-host path",
|
||||||
|
config: &Config{
|
||||||
|
NVIDIAContainerCLIConfig: ContainerCLIConfig{
|
||||||
|
Ldconfig: "/non/host/path",
|
||||||
|
},
|
||||||
|
Features: features{
|
||||||
|
AllowLDConfigFromContainer: ptr(feature(true)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
require.ErrorIs(t, tc.config.assertValid(), tc.expectedError)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// setGetDistIDsLikeForTest overrides the distribution IDs that would normally be read from the /etc/os-release file.
|
// setGetDistIDsLikeForTest overrides the distribution IDs that would normally be read from the /etc/os-release file.
|
||||||
func setGetDistIDLikeForTest(ids []string) func() {
|
func setGetDistIDLikeForTest(ids []string) func() {
|
||||||
if ids == nil {
|
if ids == nil {
|
||||||
@@ -335,3 +442,18 @@ func setGetDistIDLikeForTest(ids []string) func() {
|
|||||||
getDistIDLike = original
|
getDistIDLike = original
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prt returns a reference to whatever type is passed into it
|
||||||
|
func ptr[T any](x T) *T {
|
||||||
|
return &x
|
||||||
|
}
|
||||||
|
|
||||||
|
func setGetLdConfigPathForTest() func() {
|
||||||
|
previous := getLdConfigPath
|
||||||
|
getLdConfigPath = func() ldconfigPath {
|
||||||
|
return "@/test/ld/config/path"
|
||||||
|
}
|
||||||
|
return func() {
|
||||||
|
getLdConfigPath = previous
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,17 +18,35 @@ package config
|
|||||||
|
|
||||||
// features specifies a set of named features.
|
// features specifies a set of named features.
|
||||||
type features struct {
|
type features struct {
|
||||||
|
// AllowCUDACompatLibsFromContainer allows CUDA compat libs from a container
|
||||||
|
// to override certain driver library mounts from the host.
|
||||||
|
AllowCUDACompatLibsFromContainer *feature `toml:"allow-cuda-compat-libs-from-container,omitempty"`
|
||||||
|
// AllowLDConfigFromContainer allows non-host ldconfig paths to be used.
|
||||||
|
// If this feature flag is not set to 'true' only host-rooted config paths
|
||||||
|
// (i.e. paths starting with an '@' are considered valid)
|
||||||
|
AllowLDConfigFromContainer *feature `toml:"allow-ldconfig-from-container,omitempty"`
|
||||||
|
// DisableCUDACompatLibHook, when enabled skips the injection of a specific
|
||||||
|
// hook to process CUDA compatibility libraries.
|
||||||
|
//
|
||||||
|
// Note: Since this mechanism replaces the logic in the `nvidia-container-cli`,
|
||||||
|
// toggling this feature has no effect if `allow-cuda-compat-libs-from-container` is enabled.
|
||||||
|
DisableCUDACompatLibHook *feature `toml:"disable-cuda-compat-lib-hook,omitempty"`
|
||||||
// DisableImexChannelCreation ensures that the implicit creation of
|
// DisableImexChannelCreation ensures that the implicit creation of
|
||||||
// requested IMEX channels is skipped when invoking the nvidia-container-cli.
|
// requested IMEX channels is skipped when invoking the nvidia-container-cli.
|
||||||
DisableImexChannelCreation *feature `toml:"disable-imex-channel-creation,omitempty"`
|
DisableImexChannelCreation *feature `toml:"disable-imex-channel-creation,omitempty"`
|
||||||
|
// IgnoreImexChannelRequests configures the NVIDIA Container Toolkit to
|
||||||
|
// ignore IMEX channel requests through the NVIDIA_IMEX_CHANNELS envvar or
|
||||||
|
// volume mounts.
|
||||||
|
// This ensures that the NVIDIA Container Toolkit cannot be used to provide
|
||||||
|
// access to an IMEX channel by simply specifying an environment variable,
|
||||||
|
// possibly bypassing other checks by an orchestration system such as
|
||||||
|
// kubernetes.
|
||||||
|
IgnoreImexChannelRequests *feature `toml:"ignore-imex-channel-requests,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
|
||||||
type feature bool
|
type feature bool
|
||||||
|
|
||||||
// IsEnabled checks whether a feature is explicitly enabled.
|
// IsEnabled checks whether a feature is explicitly enabled.
|
||||||
//
|
|
||||||
//nolint:unused
|
|
||||||
func (f *feature) IsEnabled() bool {
|
func (f *feature) IsEnabled() bool {
|
||||||
if f != nil {
|
if f != nil {
|
||||||
return bool(*f)
|
return bool(*f)
|
||||||
|
|||||||
@@ -24,13 +24,3 @@ type RuntimeHookConfig struct {
|
|||||||
// SkipModeDetection disables the mode check for the runtime hook.
|
// SkipModeDetection disables the mode check for the runtime hook.
|
||||||
SkipModeDetection bool `toml:"skip-mode-detection"`
|
SkipModeDetection bool `toml:"skip-mode-detection"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultRuntimeHookConfig defines the default values for the config
|
|
||||||
func GetDefaultRuntimeHookConfig() (*RuntimeHookConfig, error) {
|
|
||||||
cfg, err := GetDefault()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cfg.NVIDIAContainerRuntimeHookConfig, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -292,7 +292,11 @@ func (i CUDA) CDIDevicesFromMounts() []string {
|
|||||||
|
|
||||||
// ImexChannelsFromEnvVar returns the list of IMEX channels requested for the image.
|
// ImexChannelsFromEnvVar returns the list of IMEX channels requested for the image.
|
||||||
func (i CUDA) ImexChannelsFromEnvVar() []string {
|
func (i CUDA) ImexChannelsFromEnvVar() []string {
|
||||||
return i.DevicesFromEnvvars(EnvVarNvidiaImexChannels).List()
|
imexChannels := i.DevicesFromEnvvars(EnvVarNvidiaImexChannels).List()
|
||||||
|
if len(imexChannels) == 1 && imexChannels[0] == "all" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return imexChannels
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImexChannelsFromMounts returns the list of IMEX channels requested for the image.
|
// ImexChannelsFromMounts returns the list of IMEX channels requested for the image.
|
||||||
|
|||||||
@@ -203,6 +203,37 @@ func TestGetVisibleDevicesFromMounts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImexChannelsFromEnvVar(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
env []string
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "no imex channels specified",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "imex channel specified",
|
||||||
|
env: []string{
|
||||||
|
"NVIDIA_IMEX_CHANNELS=3,4",
|
||||||
|
},
|
||||||
|
expected: []string{"3", "4"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
for id, baseEnvvars := range map[string][]string{"": nil, "legacy": {"CUDA_VERSION=1.2.3"}} {
|
||||||
|
t.Run(tc.description+id, func(t *testing.T) {
|
||||||
|
i, err := NewCUDAImageFromEnv(append(baseEnvvars, tc.env...))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
channels := i.ImexChannelsFromEnvVar()
|
||||||
|
require.EqualValues(t, tc.expected, channels)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func makeTestMounts(paths ...string) []specs.Mount {
|
func makeTestMounts(paths ...string) []specs.Mount {
|
||||||
var mounts []specs.Mount
|
var mounts []specs.Mount
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
|
|||||||
@@ -29,8 +29,9 @@ type RuntimeConfig struct {
|
|||||||
|
|
||||||
// modesConfig defines (optional) per-mode configs
|
// modesConfig defines (optional) per-mode configs
|
||||||
type modesConfig struct {
|
type modesConfig struct {
|
||||||
CSV csvModeConfig `toml:"csv"`
|
CSV csvModeConfig `toml:"csv"`
|
||||||
CDI cdiModeConfig `toml:"cdi"`
|
CDI cdiModeConfig `toml:"cdi"`
|
||||||
|
JitCDI jitCDIModeConfig `toml:"jit-cdi"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type cdiModeConfig struct {
|
type cdiModeConfig struct {
|
||||||
@@ -46,12 +47,10 @@ type csvModeConfig struct {
|
|||||||
MountSpecPath string `toml:"mount-spec-path"`
|
MountSpecPath string `toml:"mount-spec-path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultRuntimeConfig defines the default values for the config
|
type jitCDIModeConfig struct {
|
||||||
func GetDefaultRuntimeConfig() (*RuntimeConfig, error) {
|
// LoadKernelModules defines the names of the kernel modules that should be
|
||||||
cfg, err := GetDefault()
|
// loaded before generating a just-in-time CDI specification.
|
||||||
if err != nil {
|
// The module names must start with `nvidia` and if no modules are specified
|
||||||
return nil, err
|
// no kernel modules are loaded.
|
||||||
}
|
LoadKernelModules []string `toml:"load-kernel-modules"`
|
||||||
|
|
||||||
return &cfg.NVIDIAContainerRuntimeConfig, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,19 @@ func loadConfigTomlFrom(reader io.Reader) (*Toml, error) {
|
|||||||
|
|
||||||
// Config returns the typed config associated with the toml tree.
|
// Config returns the typed config associated with the toml tree.
|
||||||
func (t *Toml) Config() (*Config, error) {
|
func (t *Toml) Config() (*Config, error) {
|
||||||
|
cfg, err := t.configNoOverrides()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := cfg.assertValid(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// configNoOverrides returns the typed config associated with the toml tree.
|
||||||
|
// This config does not include feature-specific overrides.
|
||||||
|
func (t *Toml) configNoOverrides() (*Config, error) {
|
||||||
cfg, err := GetDefault()
|
cfg, err := GetDefault()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -74,6 +74,9 @@ spec-dirs = ["/etc/cdi", "/var/run/cdi"]
|
|||||||
[nvidia-container-runtime.modes.csv]
|
[nvidia-container-runtime.modes.csv]
|
||||||
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
mount-spec-path = "/etc/nvidia-container-runtime/host-files-for-container.d"
|
||||||
|
|
||||||
|
[nvidia-container-runtime.modes.jit-cdi]
|
||||||
|
load-kernel-modules = ["nvidia", "nvidia-uvm", "nvidia-modeset"]
|
||||||
|
|
||||||
[nvidia-container-runtime-hook]
|
[nvidia-container-runtime-hook]
|
||||||
path = "nvidia-container-runtime-hook"
|
path = "nvidia-container-runtime-hook"
|
||||||
skip-mode-detection = false
|
skip-mode-detection = false
|
||||||
@@ -198,9 +201,12 @@ func TestTomlContents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigFromToml(t *testing.T) {
|
func TestConfigFromToml(t *testing.T) {
|
||||||
|
defer setGetLdConfigPathForTest()()
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
description string
|
description string
|
||||||
contents map[string]interface{}
|
contents map[string]interface{}
|
||||||
|
expectedError error
|
||||||
expectedConfig *Config
|
expectedConfig *Config
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -226,13 +232,39 @@ func TestConfigFromToml(t *testing.T) {
|
|||||||
return c
|
return c
|
||||||
}(),
|
}(),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "invalid ldconfig value raises error",
|
||||||
|
contents: map[string]interface{}{
|
||||||
|
"nvidia-container-cli": map[string]interface{}{
|
||||||
|
"ldconfig": "/some/ldconfig/path",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: errInvalidConfig,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "feature allows ldconfig override",
|
||||||
|
contents: map[string]interface{}{
|
||||||
|
"nvidia-container-cli": map[string]interface{}{
|
||||||
|
"ldconfig": "/some/ldconfig/path",
|
||||||
|
},
|
||||||
|
"features": map[string]interface{}{
|
||||||
|
"allow-ldconfig-from-container": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedConfig: func() *Config {
|
||||||
|
c, _ := GetDefault()
|
||||||
|
c.NVIDIAContainerCLIConfig.Ldconfig = "/some/ldconfig/path"
|
||||||
|
c.Features.AllowLDConfigFromContainer = ptr(feature(true))
|
||||||
|
return c
|
||||||
|
}(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
tomlCfg := fromMap(tc.contents)
|
tomlCfg := fromMap(tc.contents)
|
||||||
config, err := tomlCfg.Config()
|
config, err := tomlCfg.Config()
|
||||||
require.NoError(t, err)
|
require.ErrorIs(t, err, tc.expectedError)
|
||||||
require.EqualValues(t, tc.expectedConfig, config)
|
require.EqualValues(t, tc.expectedConfig, config)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
24
internal/discover/compat_libs.go
Normal file
24
internal/discover/compat_libs.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package discover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCUDACompatHookDiscoverer creates a discoverer for a enable-cuda-compat hook.
|
||||||
|
// This hook is responsible for setting up CUDA compatibility in the container and depends on the host driver version.
|
||||||
|
func NewCUDACompatHookDiscoverer(logger logger.Interface, nvidiaCDIHookPath string, driver *root.Driver) Discover {
|
||||||
|
_, cudaVersionPattern := getCUDALibRootAndVersionPattern(logger, driver)
|
||||||
|
var args []string
|
||||||
|
if !strings.Contains(cudaVersionPattern, "*") {
|
||||||
|
args = append(args, "--host-driver-version="+cudaVersionPattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateNvidiaCDIHook(
|
||||||
|
nvidiaCDIHookPath,
|
||||||
|
"enable-cuda-compat",
|
||||||
|
args...,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -28,9 +28,15 @@ const (
|
|||||||
// NewCharDeviceLocator creates a Locator that can be used to find char devices at the specified root. A logger is
|
// NewCharDeviceLocator creates a Locator that can be used to find char devices at the specified root. A logger is
|
||||||
// also specified.
|
// also specified.
|
||||||
func NewCharDeviceLocator(opts ...Option) Locator {
|
func NewCharDeviceLocator(opts ...Option) Locator {
|
||||||
|
filter := assertCharDevice
|
||||||
|
// TODO: We should have a better way to inject this logic than this envvar.
|
||||||
|
if os.Getenv("__NVCT_TESTING_DEVICES_ARE_FILES") == "true" {
|
||||||
|
filter = assertFile
|
||||||
|
}
|
||||||
|
|
||||||
opts = append(opts,
|
opts = append(opts,
|
||||||
WithSearchPaths("", devRoot),
|
WithSearchPaths("", devRoot),
|
||||||
WithFilter(assertCharDevice),
|
WithFilter(filter),
|
||||||
)
|
)
|
||||||
return NewFileLocator(
|
return NewFileLocator(
|
||||||
opts...,
|
opts...,
|
||||||
|
|||||||
@@ -17,12 +17,15 @@
|
|||||||
package root
|
package root
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/system/nvmodules"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Driver represents a filesystem in which a set of drivers or devices is defined.
|
// Driver represents a filesystem in which a set of drivers or devices is defined.
|
||||||
@@ -125,3 +128,20 @@ func xdgDataDirs() []string {
|
|||||||
|
|
||||||
return []string{"/usr/local/share", "/usr/share"}
|
return []string{"/usr/local/share", "/usr/share"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadKmods loads the specified kernel modules in the driver root.
|
||||||
|
// Errors in loading a module do not prevent other modules from being attempted.
|
||||||
|
func (r *Driver) LoadKernelModules(moduleNames ...string) error {
|
||||||
|
modules := nvmodules.New(
|
||||||
|
nvmodules.WithLogger(r.logger),
|
||||||
|
nvmodules.WithRoot(r.Root),
|
||||||
|
)
|
||||||
|
|
||||||
|
var errs error
|
||||||
|
for _, moduleName := range moduleNames {
|
||||||
|
if err := modules.Load(moduleName); err != nil {
|
||||||
|
errs = errors.Join(errs, fmt.Errorf("failed to load kernel module %q: %w", moduleName, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/modifier/cdi"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/modifier/cdi"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/nvcdi"
|
||||||
@@ -34,7 +35,7 @@ import (
|
|||||||
// NewCDIModifier creates an OCI spec modifier that determines the modifications to make based on the
|
// NewCDIModifier creates an OCI spec modifier that determines the modifications to make based on the
|
||||||
// CDI specifications available on the system. The NVIDIA_VISIBLE_DEVICES environment variable is
|
// CDI specifications available on the system. The NVIDIA_VISIBLE_DEVICES environment variable is
|
||||||
// used to select the devices to include.
|
// used to select the devices to include.
|
||||||
func NewCDIModifier(logger logger.Interface, cfg *config.Config, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
func NewCDIModifier(logger logger.Interface, cfg *config.Config, driver *root.Driver, ociSpec oci.Spec) (oci.SpecModifier, error) {
|
||||||
devices, err := getDevicesFromSpec(logger, ociSpec, cfg)
|
devices, err := getDevicesFromSpec(logger, ociSpec, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get required devices from OCI specification: %v", err)
|
return nil, fmt.Errorf("failed to get required devices from OCI specification: %v", err)
|
||||||
@@ -50,7 +51,7 @@ func NewCDIModifier(logger logger.Interface, cfg *config.Config, ociSpec oci.Spe
|
|||||||
return nil, fmt.Errorf("requesting a CDI device with vendor 'runtime.nvidia.com' is not supported when requesting other CDI devices")
|
return nil, fmt.Errorf("requesting a CDI device with vendor 'runtime.nvidia.com' is not supported when requesting other CDI devices")
|
||||||
}
|
}
|
||||||
if len(automaticDevices) > 0 {
|
if len(automaticDevices) > 0 {
|
||||||
automaticModifier, err := newAutomaticCDISpecModifier(logger, cfg, automaticDevices)
|
automaticModifier, err := newAutomaticCDISpecModifier(logger, cfg, driver, automaticDevices)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return automaticModifier, nil
|
return automaticModifier, nil
|
||||||
}
|
}
|
||||||
@@ -163,9 +164,9 @@ func filterAutomaticDevices(devices []string) []string {
|
|||||||
return automatic
|
return automatic
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAutomaticCDISpecModifier(logger logger.Interface, cfg *config.Config, devices []string) (oci.SpecModifier, error) {
|
func newAutomaticCDISpecModifier(logger logger.Interface, cfg *config.Config, driver *root.Driver, devices []string) (oci.SpecModifier, error) {
|
||||||
logger.Debugf("Generating in-memory CDI specs for devices %v", devices)
|
logger.Debugf("Generating in-memory CDI specs for devices %v", devices)
|
||||||
spec, err := generateAutomaticCDISpec(logger, cfg, devices)
|
spec, err := generateAutomaticCDISpec(logger, cfg, driver, devices)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate CDI spec: %w", err)
|
return nil, fmt.Errorf("failed to generate CDI spec: %w", err)
|
||||||
}
|
}
|
||||||
@@ -180,7 +181,7 @@ func newAutomaticCDISpecModifier(logger logger.Interface, cfg *config.Config, de
|
|||||||
return cdiModifier, nil
|
return cdiModifier, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateAutomaticCDISpec(logger logger.Interface, cfg *config.Config, devices []string) (spec.Interface, error) {
|
func generateAutomaticCDISpec(logger logger.Interface, cfg *config.Config, driver *root.Driver, devices []string) (spec.Interface, error) {
|
||||||
cdilib, err := nvcdi.New(
|
cdilib, err := nvcdi.New(
|
||||||
nvcdi.WithLogger(logger),
|
nvcdi.WithLogger(logger),
|
||||||
nvcdi.WithNVIDIACDIHookPath(cfg.NVIDIACTKConfig.Path),
|
nvcdi.WithNVIDIACDIHookPath(cfg.NVIDIACTKConfig.Path),
|
||||||
@@ -192,6 +193,11 @@ func generateAutomaticCDISpec(logger logger.Interface, cfg *config.Config, devic
|
|||||||
return nil, fmt.Errorf("failed to construct CDI library: %w", err)
|
return nil, fmt.Errorf("failed to construct CDI library: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Consider moving this into the nvcdi API.
|
||||||
|
if err := driver.LoadKernelModules(cfg.NVIDIAContainerRuntimeConfig.Modes.JitCDI.LoadKernelModules...); err != nil {
|
||||||
|
logger.Warningf("Ignoring error(s) loading kernel modules: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
identifiers := []string{}
|
identifiers := []string{}
|
||||||
for _, device := range devices {
|
for _, device := range devices {
|
||||||
_, _, id := parser.ParseDevice(device)
|
_, _, id := parser.ParseDevice(device)
|
||||||
|
|||||||
@@ -68,20 +68,10 @@ func NewCSVModifier(logger logger.Interface, cfg *config.Config, container image
|
|||||||
return nil, fmt.Errorf("failed to get CDI spec: %v", err)
|
return nil, fmt.Errorf("failed to get CDI spec: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cdiModifier, err := cdi.New(
|
return cdi.New(
|
||||||
cdi.WithLogger(logger),
|
cdi.WithLogger(logger),
|
||||||
cdi.WithSpec(spec.Raw()),
|
cdi.WithSpec(spec.Raw()),
|
||||||
)
|
)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to construct CDI modifier: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiers := Merge(
|
|
||||||
nvidiaContainerRuntimeHookRemover{logger},
|
|
||||||
cdiModifier,
|
|
||||||
)
|
|
||||||
|
|
||||||
return modifiers, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkRequirements(logger logger.Interface, image image.CUDA) error {
|
func checkRequirements(logger logger.Interface, image image.CUDA) error {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package modifier
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/opencontainers/runtime-spec/specs-go"
|
|
||||||
testlog "github.com/sirupsen/logrus/hooks/test"
|
testlog "github.com/sirupsen/logrus/hooks/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@@ -74,66 +73,3 @@ func TestNewCSVModifier(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCSVModifierRemovesHook(t *testing.T) {
|
|
||||||
logger, _ := testlog.NewNullLogger()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
description string
|
|
||||||
spec *specs.Spec
|
|
||||||
expectedError error
|
|
||||||
expectedSpec *specs.Spec
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
description: "modification removes existing nvidia-container-runtime-hook",
|
|
||||||
spec: &specs.Spec{
|
|
||||||
Hooks: &specs.Hooks{
|
|
||||||
Prestart: []specs.Hook{
|
|
||||||
{
|
|
||||||
Path: "/path/to/nvidia-container-runtime-hook",
|
|
||||||
Args: []string{"/path/to/nvidia-container-runtime-hook", "prestart"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedSpec: &specs.Spec{
|
|
||||||
Hooks: &specs.Hooks{
|
|
||||||
Prestart: []specs.Hook{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "modification removes existing nvidia-container-toolkit",
|
|
||||||
spec: &specs.Spec{
|
|
||||||
Hooks: &specs.Hooks{
|
|
||||||
Prestart: []specs.Hook{
|
|
||||||
{
|
|
||||||
Path: "/path/to/nvidia-container-toolkit",
|
|
||||||
Args: []string{"/path/to/nvidia-container-toolkit", "prestart"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedSpec: &specs.Spec{
|
|
||||||
Hooks: &specs.Hooks{
|
|
||||||
Prestart: []specs.Hook{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
|
||||||
m := nvidiaContainerRuntimeHookRemover{logger: logger}
|
|
||||||
|
|
||||||
err := m.Modify(tc.spec)
|
|
||||||
if tc.expectedError != nil {
|
|
||||||
require.Error(t, err)
|
|
||||||
} else {
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Empty(t, tc.spec.Hooks.Prestart)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ import (
|
|||||||
// NVIDIA_GDRCOPY=enabled
|
// NVIDIA_GDRCOPY=enabled
|
||||||
//
|
//
|
||||||
// If not devices are selected, no changes are made.
|
// If not devices are selected, no changes are made.
|
||||||
func NewFeatureGatedModifier(logger logger.Interface, cfg *config.Config, image image.CUDA) (oci.SpecModifier, error) {
|
func NewFeatureGatedModifier(logger logger.Interface, cfg *config.Config, image image.CUDA, driver *root.Driver) (oci.SpecModifier, error) {
|
||||||
if devices := image.VisibleDevicesFromEnvVar(); len(devices) == 0 {
|
if devices := image.VisibleDevicesFromEnvVar(); len(devices) == 0 {
|
||||||
logger.Infof("No modification required; no devices requested")
|
logger.Infof("No modification required; no devices requested")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -78,5 +79,24 @@ func NewFeatureGatedModifier(logger logger.Interface, cfg *config.Config, image
|
|||||||
discoverers = append(discoverers, d)
|
discoverers = append(discoverers, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !cfg.Features.AllowCUDACompatLibsFromContainer.IsEnabled() && !cfg.Features.DisableCUDACompatLibHook.IsEnabled() {
|
||||||
|
compatLibHookDiscoverer := discover.NewCUDACompatHookDiscoverer(logger, cfg.NVIDIACTKConfig.Path, driver)
|
||||||
|
discoverers = append(discoverers, compatLibHookDiscoverer)
|
||||||
|
// For legacy mode, we also need to inject a hook to update the LDCache
|
||||||
|
// after we have modifed the configuration.
|
||||||
|
if cfg.NVIDIAContainerRuntimeConfig.Mode == "legacy" {
|
||||||
|
ldcacheUpdateHookDiscoverer, err := discover.NewLDCacheUpdateHook(
|
||||||
|
logger,
|
||||||
|
discover.None{},
|
||||||
|
cfg.NVIDIACTKConfig.Path,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to construct ldcache update discoverer: %w", err)
|
||||||
|
}
|
||||||
|
discoverers = append(discoverers, ldcacheUpdateHookDiscoverer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NewModifierFromDiscoverer(logger, discover.Merge(discoverers...))
|
return NewModifierFromDiscoverer(logger, discover.Merge(discoverers...))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,13 @@ type nvidiaContainerRuntimeHookRemover struct {
|
|||||||
|
|
||||||
var _ oci.SpecModifier = (*nvidiaContainerRuntimeHookRemover)(nil)
|
var _ oci.SpecModifier = (*nvidiaContainerRuntimeHookRemover)(nil)
|
||||||
|
|
||||||
|
// NewNvidiaContainerRuntimeHookRemover creates a modifier that removes any NVIDIA Container Runtime hooks from the provided spec.
|
||||||
|
func NewNvidiaContainerRuntimeHookRemover(logger logger.Interface) oci.SpecModifier {
|
||||||
|
return nvidiaContainerRuntimeHookRemover{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Modify removes any NVIDIA Container Runtime hooks from the provided spec
|
// Modify removes any NVIDIA Container Runtime hooks from the provided spec
|
||||||
func (m nvidiaContainerRuntimeHookRemover) Modify(spec *specs.Spec) error {
|
func (m nvidiaContainerRuntimeHookRemover) Modify(spec *specs.Spec) error {
|
||||||
if spec == nil {
|
if spec == nil {
|
||||||
|
|||||||
@@ -22,14 +22,12 @@ import (
|
|||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||||
)
|
)
|
||||||
|
|
||||||
type list struct {
|
type List []oci.SpecModifier
|
||||||
modifiers []oci.SpecModifier
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge merges a set of OCI specification modifiers as a list.
|
// Merge merges a set of OCI specification modifiers as a list.
|
||||||
// This can be used to compose modifiers.
|
// This can be used to compose modifiers.
|
||||||
func Merge(modifiers ...oci.SpecModifier) oci.SpecModifier {
|
func Merge(modifiers ...oci.SpecModifier) oci.SpecModifier {
|
||||||
var filteredModifiers []oci.SpecModifier
|
var filteredModifiers List
|
||||||
for _, m := range modifiers {
|
for _, m := range modifiers {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
continue
|
continue
|
||||||
@@ -37,19 +35,19 @@ func Merge(modifiers ...oci.SpecModifier) oci.SpecModifier {
|
|||||||
filteredModifiers = append(filteredModifiers, m)
|
filteredModifiers = append(filteredModifiers, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
return list{
|
return filteredModifiers
|
||||||
modifiers: filteredModifiers,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modify applies a list of modifiers in sequence and returns on any errors encountered.
|
// Modify applies a list of modifiers in sequence and returns on any errors encountered.
|
||||||
func (m list) Modify(spec *specs.Spec) error {
|
func (m List) Modify(spec *specs.Spec) error {
|
||||||
for _, mm := range m.modifiers {
|
for _, mm := range m {
|
||||||
|
if mm == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
err := mm.Modify(spec)
|
err := mm.Modify(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ func TestMaintainSpec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
inputSpecPath := filepath.Join(moduleRoot, "test/input", f)
|
inputSpecPath := filepath.Join(moduleRoot, "tests/input", f)
|
||||||
|
|
||||||
spec := NewFileSpec(inputSpecPath).(*fileSpec)
|
spec := NewFileSpec(inputSpecPath).(*fileSpec)
|
||||||
|
|
||||||
_, err := spec.Load()
|
_, err := spec.Load()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
outputSpecPath := filepath.Join(moduleRoot, "test/output", f)
|
outputSpecPath := filepath.Join(moduleRoot, "tests/output", f)
|
||||||
spec.path = outputSpecPath
|
spec.path = outputSpecPath
|
||||||
spec.Flush()
|
spec.Flush()
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func TestGetFileList(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
description: "returns list of CSV files",
|
description: "returns list of CSV files",
|
||||||
root: "test/input/csv_samples/",
|
root: "tests/input/csv_samples/",
|
||||||
files: []string{
|
files: []string{
|
||||||
"jetson.csv",
|
"jetson.csv",
|
||||||
"simple_wrong.csv",
|
"simple_wrong.csv",
|
||||||
@@ -46,15 +46,15 @@ func TestGetFileList(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "handles empty folder",
|
description: "handles empty folder",
|
||||||
root: "test/input/csv_samples/empty",
|
root: "tests/input/csv_samples/empty",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "handles non-existent folder",
|
description: "handles non-existent folder",
|
||||||
root: "test/input/csv_samples/NONEXISTENT",
|
root: "tests/input/csv_samples/NONEXISTENT",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "handles non-existent folder root",
|
description: "handles non-existent folder root",
|
||||||
root: "/NONEXISTENT/test/input/csv_samples/",
|
root: "/NONEXISTENT/tests/input/csv_samples/",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,42 +75,61 @@ func newSpecModifier(logger logger.Interface, cfg *config.Config, ociSpec oci.Sp
|
|||||||
}
|
}
|
||||||
|
|
||||||
mode := info.ResolveAutoMode(logger, cfg.NVIDIAContainerRuntimeConfig.Mode, image)
|
mode := info.ResolveAutoMode(logger, cfg.NVIDIAContainerRuntimeConfig.Mode, image)
|
||||||
modeModifier, err := newModeModifier(logger, mode, cfg, ociSpec, image)
|
// We update the mode here so that we can continue passing just the config to other functions.
|
||||||
if err != nil {
|
cfg.NVIDIAContainerRuntimeConfig.Mode = mode
|
||||||
return nil, err
|
modeModifier, err := newModeModifier(logger, mode, cfg, driver, ociSpec, image)
|
||||||
}
|
|
||||||
// For CDI mode we make no additional modifications.
|
|
||||||
if mode == "cdi" {
|
|
||||||
return modeModifier, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
graphicsModifier, err := modifier.NewGraphicsModifier(logger, cfg, image, driver)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
featureModifier, err := modifier.NewFeatureGatedModifier(logger, cfg, image)
|
var modifiers modifier.List
|
||||||
if err != nil {
|
for _, modifierType := range supportedModifierTypes(mode) {
|
||||||
return nil, err
|
switch modifierType {
|
||||||
|
case "mode":
|
||||||
|
modifiers = append(modifiers, modeModifier)
|
||||||
|
case "nvidia-hook-remover":
|
||||||
|
modifiers = append(modifiers, modifier.NewNvidiaContainerRuntimeHookRemover(logger))
|
||||||
|
case "graphics":
|
||||||
|
graphicsModifier, err := modifier.NewGraphicsModifier(logger, cfg, image, driver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
modifiers = append(modifiers, graphicsModifier)
|
||||||
|
case "feature-gated":
|
||||||
|
featureGatedModifier, err := modifier.NewFeatureGatedModifier(logger, cfg, image, driver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
modifiers = append(modifiers, featureGatedModifier)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiers := modifier.Merge(
|
|
||||||
modeModifier,
|
|
||||||
graphicsModifier,
|
|
||||||
featureModifier,
|
|
||||||
)
|
|
||||||
return modifiers, nil
|
return modifiers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newModeModifier(logger logger.Interface, mode string, cfg *config.Config, ociSpec oci.Spec, image image.CUDA) (oci.SpecModifier, error) {
|
func newModeModifier(logger logger.Interface, mode string, cfg *config.Config, driver *root.Driver, ociSpec oci.Spec, image image.CUDA) (oci.SpecModifier, error) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case "legacy":
|
case "legacy":
|
||||||
return modifier.NewStableRuntimeModifier(logger, cfg.NVIDIAContainerRuntimeHookConfig.Path), nil
|
return modifier.NewStableRuntimeModifier(logger, cfg.NVIDIAContainerRuntimeHookConfig.Path), nil
|
||||||
case "csv":
|
case "csv":
|
||||||
return modifier.NewCSVModifier(logger, cfg, image)
|
return modifier.NewCSVModifier(logger, cfg, image)
|
||||||
case "cdi":
|
case "cdi":
|
||||||
return modifier.NewCDIModifier(logger, cfg, ociSpec)
|
return modifier.NewCDIModifier(logger, cfg, driver, ociSpec)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("invalid runtime mode: %v", cfg.NVIDIAContainerRuntimeConfig.Mode)
|
return nil, fmt.Errorf("invalid runtime mode: %v", cfg.NVIDIAContainerRuntimeConfig.Mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// supportedModifierTypes returns the modifiers supported for a specific runtime mode.
|
||||||
|
func supportedModifierTypes(mode string) []string {
|
||||||
|
switch mode {
|
||||||
|
case "cdi":
|
||||||
|
// For CDI mode we make no additional modifications.
|
||||||
|
return []string{"nvidia-hook-remover", "mode"}
|
||||||
|
case "csv":
|
||||||
|
// For CSV mode we support mode and feature-gated modification.
|
||||||
|
return []string{"nvidia-hook-remover", "feature-gated", "mode"}
|
||||||
|
default:
|
||||||
|
return []string{"feature-gated", "graphics", "mode"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import (
|
|||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/config"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root"
|
||||||
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/test"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ func TestMain(m *testing.M) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error in test setup: could not get module root: %v", err)
|
log.Fatalf("error in test setup: could not get module root: %v", err)
|
||||||
}
|
}
|
||||||
testBinPath := filepath.Join(moduleRoot, "test", "bin")
|
testBinPath := filepath.Join(moduleRoot, "tests", "bin")
|
||||||
|
|
||||||
// Set the environment variables for the test
|
// Set the environment variables for the test
|
||||||
os.Setenv("PATH", test.PrependToPath(testBinPath, moduleRoot))
|
os.Setenv("PATH", test.PrependToPath(testBinPath, moduleRoot))
|
||||||
@@ -165,3 +166,181 @@ func TestFactoryMethod(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewSpecModifier(t *testing.T) {
|
||||||
|
logger, _ := testlog.NewNullLogger()
|
||||||
|
driver := root.New(
|
||||||
|
root.WithDriverRoot("/nvidia/driver/root"),
|
||||||
|
)
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
config *config.Config
|
||||||
|
spec *specs.Spec
|
||||||
|
expectedSpec *specs.Spec
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "csv mode removes nvidia-container-runtime-hook",
|
||||||
|
config: &config.Config{
|
||||||
|
NVIDIAContainerRuntimeConfig: config.RuntimeConfig{
|
||||||
|
Mode: "csv",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: []specs.Hook{
|
||||||
|
{
|
||||||
|
Path: "/path/to/nvidia-container-runtime-hook",
|
||||||
|
Args: []string{"/path/to/nvidia-container-runtime-hook", "prestart"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSpec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "csv mode removes nvidia-container-toolkit",
|
||||||
|
config: &config.Config{
|
||||||
|
NVIDIAContainerRuntimeConfig: config.RuntimeConfig{
|
||||||
|
Mode: "csv",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: []specs.Hook{
|
||||||
|
{
|
||||||
|
Path: "/path/to/nvidia-container-toolkit",
|
||||||
|
Args: []string{"/path/to/nvidia-container-toolkit", "prestart"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSpec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "cdi mode removes nvidia-container-runtime-hook",
|
||||||
|
config: &config.Config{
|
||||||
|
NVIDIAContainerRuntimeConfig: config.RuntimeConfig{
|
||||||
|
Mode: "cdi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: []specs.Hook{
|
||||||
|
{
|
||||||
|
Path: "/path/to/nvidia-container-runtime-hook",
|
||||||
|
Args: []string{"/path/to/nvidia-container-runtime-hook", "prestart"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSpec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "cdi mode removes nvidia-container-toolkit",
|
||||||
|
config: &config.Config{
|
||||||
|
NVIDIAContainerRuntimeConfig: config.RuntimeConfig{
|
||||||
|
Mode: "cdi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: []specs.Hook{
|
||||||
|
{
|
||||||
|
Path: "/path/to/nvidia-container-toolkit",
|
||||||
|
Args: []string{"/path/to/nvidia-container-toolkit", "prestart"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSpec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "legacy mode keeps nvidia-container-runtime-hook",
|
||||||
|
config: &config.Config{
|
||||||
|
NVIDIAContainerRuntimeConfig: config.RuntimeConfig{
|
||||||
|
Mode: "legacy",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: []specs.Hook{
|
||||||
|
{
|
||||||
|
Path: "/path/to/nvidia-container-runtime-hook",
|
||||||
|
Args: []string{"/path/to/nvidia-container-runtime-hook", "prestart"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSpec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: []specs.Hook{
|
||||||
|
{
|
||||||
|
Path: "/path/to/nvidia-container-runtime-hook",
|
||||||
|
Args: []string{"/path/to/nvidia-container-runtime-hook", "prestart"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "legacy mode keeps nvidia-container-toolkit",
|
||||||
|
config: &config.Config{
|
||||||
|
NVIDIAContainerRuntimeConfig: config.RuntimeConfig{
|
||||||
|
Mode: "legacy",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: []specs.Hook{
|
||||||
|
{
|
||||||
|
Path: "/path/to/nvidia-container-toolkit",
|
||||||
|
Args: []string{"/path/to/nvidia-container-toolkit", "prestart"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedSpec: &specs.Spec{
|
||||||
|
Hooks: &specs.Hooks{
|
||||||
|
Prestart: []specs.Hook{
|
||||||
|
{
|
||||||
|
Path: "/path/to/nvidia-container-toolkit",
|
||||||
|
Args: []string{"/path/to/nvidia-container-toolkit", "prestart"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
spec := &oci.SpecMock{
|
||||||
|
LoadFunc: func() (*specs.Spec, error) {
|
||||||
|
return tc.spec, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
m, err := newSpecModifier(logger, tc.config, spec, driver)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = m.Modify(tc.spec)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, tc.expectedSpec, tc.spec)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package nvdevices
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -66,7 +65,7 @@ func New(opts ...Option) (*Interface, error) {
|
|||||||
if i.dryRun {
|
if i.dryRun {
|
||||||
i.mknoder = &mknodLogger{i.logger}
|
i.mknoder = &mknodLogger{i.logger}
|
||||||
} else {
|
} else {
|
||||||
i.mknoder = &mknodUnix{}
|
i.mknoder = &mknodUnix{i.logger}
|
||||||
}
|
}
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
@@ -107,13 +106,6 @@ func (m *Interface) CreateNVIDIADevice(node string) error {
|
|||||||
// If a devRoot is configured, this is prepended to the path.
|
// If a devRoot is configured, this is prepended to the path.
|
||||||
func (m *Interface) createDeviceNode(path string, major int, minor int) error {
|
func (m *Interface) createDeviceNode(path string, major int, minor int) error {
|
||||||
path = filepath.Join(m.devRoot, path)
|
path = filepath.Join(m.devRoot, path)
|
||||||
if _, err := os.Stat(path); err == nil {
|
|
||||||
m.logger.Infof("Skipping: %s already exists", path)
|
|
||||||
return nil
|
|
||||||
} else if !os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("failed to stat %s: %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.Mknode(path, major, minor)
|
return m.Mknode(path, major, minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
package nvdevices
|
package nvdevices
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
@@ -36,9 +39,19 @@ func (m *mknodLogger) Mknode(path string, major, minor int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type mknodUnix struct{}
|
type mknodUnix struct {
|
||||||
|
logger logger.Interface
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mknodUnix) Mknode(path string, major, minor int) error {
|
func (m *mknodUnix) Mknode(path string, major, minor int) error {
|
||||||
|
// TODO: Ensure that the existing device node has the correct properties.
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
m.logger.Infof("Skipping: %s already exists", path)
|
||||||
|
return nil
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("failed to stat %s: %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
err := unix.Mknod(path, unix.S_IFCHR, int(unix.Mkdev(uint32(major), uint32(minor))))
|
err := unix.Mknod(path, unix.S_IFCHR, int(unix.Mkdev(uint32(major), uint32(minor))))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -18,12 +18,13 @@ package engine
|
|||||||
|
|
||||||
// Interface defines the API for a runtime config updater.
|
// Interface defines the API for a runtime config updater.
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
DefaultRuntime() string
|
|
||||||
AddRuntime(string, string, bool) error
|
AddRuntime(string, string, bool) error
|
||||||
Set(string, interface{})
|
DefaultRuntime() string
|
||||||
|
EnableCDI()
|
||||||
|
GetRuntimeConfig(string) (RuntimeConfig, error)
|
||||||
RemoveRuntime(string) error
|
RemoveRuntime(string) error
|
||||||
Save(string) (int64, error)
|
Save(string) (int64, error)
|
||||||
GetRuntimeConfig(string) (RuntimeConfig, error)
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuntimeConfig defines the interface to query container runtime handler configuration
|
// RuntimeConfig defines the interface to query container runtime handler configuration
|
||||||
|
|||||||
@@ -30,40 +30,40 @@ func (c *Config) AddRuntime(name string, path string, setAsDefault bool) error {
|
|||||||
}
|
}
|
||||||
config := *c.Tree
|
config := *c.Tree
|
||||||
|
|
||||||
config.Set("version", int64(2))
|
config.Set("version", c.Version)
|
||||||
|
|
||||||
runtimeNamesForConfig := engine.GetLowLevelRuntimes(c)
|
runtimeNamesForConfig := engine.GetLowLevelRuntimes(c)
|
||||||
for _, r := range runtimeNamesForConfig {
|
for _, r := range runtimeNamesForConfig {
|
||||||
options := config.GetSubtreeByPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", r})
|
options := config.GetSubtreeByPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", r})
|
||||||
if options == nil {
|
if options == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.Logger.Debugf("using options from runtime %v: %v", r, options)
|
c.Logger.Debugf("using options from runtime %v: %v", r, options)
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name}, options.Copy())
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name}, options.Copy())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name}) == nil {
|
if config.GetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name}) == nil {
|
||||||
c.Logger.Warningf("could not infer options from runtimes %v; using defaults", runtimeNamesForConfig)
|
c.Logger.Warningf("could not infer options from runtimes %v; using defaults", runtimeNamesForConfig)
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "runtime_type"}, c.RuntimeType)
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name, "runtime_type"}, c.RuntimeType)
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "runtime_root"}, "")
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name, "runtime_root"}, "")
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "runtime_engine"}, "")
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name, "runtime_engine"}, "")
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "privileged_without_host_devices"}, false)
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name, "privileged_without_host_devices"}, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.ContainerAnnotations) > 0 {
|
if len(c.ContainerAnnotations) > 0 {
|
||||||
annotations, err := c.getRuntimeAnnotations([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "container_annotations"})
|
annotations, err := c.getRuntimeAnnotations([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name, "container_annotations"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
annotations = append(c.ContainerAnnotations, annotations...)
|
annotations = append(c.ContainerAnnotations, annotations...)
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "container_annotations"}, annotations)
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name, "container_annotations"}, annotations)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name, "options", "BinaryName"}, path)
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name, "options", "BinaryName"}, path)
|
||||||
|
|
||||||
if setAsDefault {
|
if setAsDefault {
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"}, name)
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "default_runtime_name"}, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
*c.Tree = config
|
*c.Tree = config
|
||||||
@@ -96,21 +96,21 @@ func (c *Config) getRuntimeAnnotations(path []string) ([]string, error) {
|
|||||||
return annotations, nil
|
return annotations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the specified containerd option.
|
|
||||||
func (c *Config) Set(key string, value interface{}) {
|
|
||||||
config := *c.Tree
|
|
||||||
config.SetPath([]string{"plugins", "io.containerd.grpc.v1.cri", key}, value)
|
|
||||||
*c.Tree = config
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultRuntime returns the default runtime for the cri-o config
|
// DefaultRuntime returns the default runtime for the cri-o config
|
||||||
func (c Config) DefaultRuntime() string {
|
func (c Config) DefaultRuntime() string {
|
||||||
if runtime, ok := c.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"}).(string); ok {
|
if runtime, ok := c.GetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "default_runtime_name"}).(string); ok {
|
||||||
return runtime
|
return runtime
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnableCDI sets the enable_cdi field in the Containerd config to true.
|
||||||
|
func (c *Config) EnableCDI() {
|
||||||
|
config := *c.Tree
|
||||||
|
config.SetPath([]string{"plugins", c.CRIRuntimePluginName, "enable_cdi"}, true)
|
||||||
|
*c.Tree = config
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveRuntime removes a runtime from the docker config
|
// RemoveRuntime removes a runtime from the docker config
|
||||||
func (c *Config) RemoveRuntime(name string) error {
|
func (c *Config) RemoveRuntime(name string) error {
|
||||||
if c == nil || c.Tree == nil {
|
if c == nil || c.Tree == nil {
|
||||||
@@ -119,14 +119,14 @@ func (c *Config) RemoveRuntime(name string) error {
|
|||||||
|
|
||||||
config := *c.Tree
|
config := *c.Tree
|
||||||
|
|
||||||
config.DeletePath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name})
|
config.DeletePath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name})
|
||||||
if runtime, ok := config.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"}).(string); ok {
|
if runtime, ok := config.GetPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "default_runtime_name"}).(string); ok {
|
||||||
if runtime == name {
|
if runtime == name {
|
||||||
config.DeletePath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"})
|
config.DeletePath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "default_runtime_name"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimePath := []string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name}
|
runtimePath := []string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name}
|
||||||
for i := 0; i < len(runtimePath); i++ {
|
for i := 0; i < len(runtimePath); i++ {
|
||||||
if runtimes, ok := config.GetPath(runtimePath[:len(runtimePath)-i]).(*toml.Tree); ok {
|
if runtimes, ok := config.GetPath(runtimePath[:len(runtimePath)-i]).(*toml.Tree); ok {
|
||||||
if len(runtimes.Keys()) == 0 {
|
if len(runtimes.Keys()) == 0 {
|
||||||
@@ -46,7 +46,7 @@ func TestAddRuntime(t *testing.T) {
|
|||||||
privileged_without_host_devices = false
|
privileged_without_host_devices = false
|
||||||
runtime_engine = ""
|
runtime_engine = ""
|
||||||
runtime_root = ""
|
runtime_root = ""
|
||||||
runtime_type = ""
|
runtime_type = "io.containerd.runc.v2"
|
||||||
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.test.options]
|
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.test.options]
|
||||||
BinaryName = "/usr/bin/test"
|
BinaryName = "/usr/bin/test"
|
||||||
`,
|
`,
|
||||||
@@ -195,24 +195,85 @@ func TestAddRuntime(t *testing.T) {
|
|||||||
SystemdCgroup = false
|
SystemdCgroup = false
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "empty v3 spec is supported",
|
||||||
|
config: `
|
||||||
|
version = 3
|
||||||
|
`,
|
||||||
|
expectedConfig: `
|
||||||
|
version = 3
|
||||||
|
[plugins]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime"]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.test]
|
||||||
|
privileged_without_host_devices = false
|
||||||
|
runtime_engine = ""
|
||||||
|
runtime_root = ""
|
||||||
|
runtime_type = "io.containerd.runc.v2"
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.test.options]
|
||||||
|
BinaryName = "/usr/bin/test"
|
||||||
|
`,
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "v3 spec is supported",
|
||||||
|
config: `
|
||||||
|
version = 3
|
||||||
|
[plugins]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime"]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.runc]
|
||||||
|
privileged_without_host_devices = true
|
||||||
|
runtime_engine = "engine"
|
||||||
|
runtime_root = "root"
|
||||||
|
runtime_type = "type"
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.runc.options]
|
||||||
|
BinaryName = "/usr/bin/runc"
|
||||||
|
SystemdCgroup = true
|
||||||
|
`,
|
||||||
|
expectedConfig: `
|
||||||
|
version = 3
|
||||||
|
[plugins]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime"]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes]
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.runc]
|
||||||
|
privileged_without_host_devices = true
|
||||||
|
runtime_engine = "engine"
|
||||||
|
runtime_root = "root"
|
||||||
|
runtime_type = "type"
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.runc.options]
|
||||||
|
BinaryName = "/usr/bin/runc"
|
||||||
|
SystemdCgroup = true
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.test]
|
||||||
|
privileged_without_host_devices = true
|
||||||
|
runtime_engine = "engine"
|
||||||
|
runtime_root = "root"
|
||||||
|
runtime_type = "type"
|
||||||
|
[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.test.options]
|
||||||
|
BinaryName = "/usr/bin/test"
|
||||||
|
SystemdCgroup = true
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
cfg, err := toml.Load(tc.config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
expectedConfig, err := toml.Load(tc.expectedConfig)
|
expectedConfig, err := toml.Load(tc.expectedConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
c := &Config{
|
c, err := New(
|
||||||
Logger: logger,
|
WithLogger(logger),
|
||||||
Tree: cfg,
|
WithConfigSource(toml.FromString(tc.config)),
|
||||||
}
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = c.AddRuntime("test", "/usr/bin/test", tc.setAsDefault)
|
err = c.AddRuntime("test", "/usr/bin/test", tc.setAsDefault)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.EqualValues(t, expectedConfig.String(), cfg.String())
|
require.EqualValues(t, expectedConfig.String(), c.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,13 +360,13 @@ func TestGetRuntimeConfig(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
cfg, err := toml.Load(config)
|
|
||||||
|
c, err := New(
|
||||||
|
WithLogger(logger),
|
||||||
|
WithConfigSource(toml.FromString(config)),
|
||||||
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
c := &Config{
|
|
||||||
Logger: logger,
|
|
||||||
Tree: cfg,
|
|
||||||
}
|
|
||||||
rc, err := c.GetRuntimeConfig(tc.runtime)
|
rc, err := c.GetRuntimeConfig(tc.runtime)
|
||||||
require.Equal(t, tc.expectedError, err)
|
require.Equal(t, tc.expectedError, err)
|
||||||
require.Equal(t, tc.expected, rc.GetBinaryPath())
|
require.Equal(t, tc.expected, rc.GetBinaryPath())
|
||||||
@@ -70,18 +70,20 @@ func (c *ConfigV1) AddRuntime(name string, path string, setAsDefault bool) error
|
|||||||
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "options", "BinaryName"}, path)
|
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "options", "BinaryName"}, path)
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "options", "Runtime"}, path)
|
config.SetPath([]string{"plugins", "cri", "containerd", "runtimes", name, "options", "Runtime"}, path)
|
||||||
|
|
||||||
if setAsDefault && c.UseDefaultRuntimeName {
|
if setAsDefault {
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime_name"}, name)
|
if !c.UseLegacyConfig {
|
||||||
} else if setAsDefault {
|
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime_name"}, name)
|
||||||
// Note: This is deprecated in containerd 1.4.0 and will be removed in 1.5.0
|
} else {
|
||||||
if config.GetPath([]string{"plugins", "cri", "containerd", "default_runtime"}) == nil {
|
// Note: This is deprecated in containerd 1.4.0 and will be removed in 1.5.0
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "runtime_type"}, c.RuntimeType)
|
if config.GetPath([]string{"plugins", "cri", "containerd", "default_runtime"}) == nil {
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "runtime_root"}, "")
|
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "runtime_type"}, c.RuntimeType)
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "runtime_engine"}, "")
|
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "runtime_root"}, "")
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "privileged_without_host_devices"}, false)
|
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "runtime_engine"}, "")
|
||||||
|
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "privileged_without_host_devices"}, false)
|
||||||
|
}
|
||||||
|
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "options", "BinaryName"}, path)
|
||||||
|
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "options", "Runtime"}, path)
|
||||||
}
|
}
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "options", "BinaryName"}, path)
|
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", "default_runtime", "options", "Runtime"}, path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*c.Tree = config
|
*c.Tree = config
|
||||||
@@ -141,13 +143,6 @@ func (c *ConfigV1) RemoveRuntime(name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the specified containerd option.
|
|
||||||
func (c *ConfigV1) Set(key string, value interface{}) {
|
|
||||||
config := *c.Tree
|
|
||||||
config.SetPath([]string{"plugins", "cri", "containerd", key}, value)
|
|
||||||
*c.Tree = config
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save writes the config to a file
|
// Save writes the config to a file
|
||||||
func (c ConfigV1) Save(path string) (int64, error) {
|
func (c ConfigV1) Save(path string) (int64, error) {
|
||||||
return (Config)(c).Save(path)
|
return (Config)(c).Save(path)
|
||||||
@@ -163,3 +158,9 @@ func (c *ConfigV1) GetRuntimeConfig(name string) (engine.RuntimeConfig, error) {
|
|||||||
tree: runtimeData,
|
tree: runtimeData,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ConfigV1) EnableCDI() {
|
||||||
|
config := *c.Tree
|
||||||
|
config.SetPath([]string{"plugins", "cri", "containerd", "enable_cdi"}, true)
|
||||||
|
*c.Tree = config
|
||||||
|
}
|
||||||
|
|||||||
@@ -200,20 +200,21 @@ func TestAddRuntimeV1(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
cfg, err := toml.Load(tc.config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
expectedConfig, err := toml.Load(tc.expectedConfig)
|
expectedConfig, err := toml.Load(tc.expectedConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
c := &ConfigV1{
|
c, err := New(
|
||||||
Logger: logger,
|
WithLogger(logger),
|
||||||
Tree: cfg,
|
WithConfigSource(toml.FromString(tc.config)),
|
||||||
}
|
WithUseLegacyConfig(true),
|
||||||
|
WithRuntimeType(""),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = c.AddRuntime("test", "/usr/bin/test", tc.setAsDefault)
|
err = c.AddRuntime("test", "/usr/bin/test", tc.setAsDefault)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.EqualValues(t, expectedConfig.String(), cfg.String())
|
require.EqualValues(t, expectedConfig.String(), c.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,28 @@ import (
|
|||||||
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultConfigVersion = 2
|
||||||
|
defaultRuntimeType = "io.containerd.runc.v2"
|
||||||
|
)
|
||||||
|
|
||||||
// Config represents the containerd config
|
// Config represents the containerd config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
*toml.Tree
|
*toml.Tree
|
||||||
Logger logger.Interface
|
Version int64
|
||||||
RuntimeType string
|
Logger logger.Interface
|
||||||
UseDefaultRuntimeName bool
|
RuntimeType string
|
||||||
ContainerAnnotations []string
|
ContainerAnnotations []string
|
||||||
|
// UseLegacyConfig indicates whether a config file pre v1.3 should be generated.
|
||||||
|
// For version 1 config prior to containerd v1.4 the default runtime was
|
||||||
|
// specified in a containerd.runtimes.default_runtime section.
|
||||||
|
// This was deprecated in v1.4 in favour of containerd.default_runtime_name.
|
||||||
|
// Support for this section has been removed in v2.0.
|
||||||
|
UseLegacyConfig bool
|
||||||
|
// CRIRuntimePluginName represents the fully qualified name of the containerd plugin
|
||||||
|
// for the CRI runtime service. The name of this plugin was changed in v3 of the
|
||||||
|
// containerd configuration file.
|
||||||
|
CRIRuntimePluginName string
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ engine.Interface = (*Config)(nil)
|
var _ engine.Interface = (*Config)(nil)
|
||||||
@@ -55,7 +70,8 @@ func (c *containerdCfgRuntime) GetBinaryPath() string {
|
|||||||
// New creates a containerd config with the specified options
|
// New creates a containerd config with the specified options
|
||||||
func New(opts ...Option) (engine.Interface, error) {
|
func New(opts ...Option) (engine.Interface, error) {
|
||||||
b := &builder{
|
b := &builder{
|
||||||
runtimeType: defaultRuntimeType,
|
configVersion: defaultConfigVersion,
|
||||||
|
runtimeType: defaultRuntimeType,
|
||||||
}
|
}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(b)
|
opt(b)
|
||||||
@@ -72,55 +88,74 @@ func New(opts ...Option) (engine.Interface, error) {
|
|||||||
return nil, fmt.Errorf("failed to load config: %v", err)
|
return nil, fmt.Errorf("failed to load config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configVersion, err := b.parseVersion(tomlConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse config version: %w", err)
|
||||||
|
}
|
||||||
|
b.logger.Infof("Using config version %v", configVersion)
|
||||||
|
|
||||||
|
criRuntimePluginName, err := b.criRuntimePluginName(configVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get CRI runtime plugin name: %w", err)
|
||||||
|
}
|
||||||
|
b.logger.Infof("Using CRI runtime plugin name %q", criRuntimePluginName)
|
||||||
|
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
Tree: tomlConfig,
|
Tree: tomlConfig,
|
||||||
Logger: b.logger,
|
Version: configVersion,
|
||||||
RuntimeType: b.runtimeType,
|
CRIRuntimePluginName: criRuntimePluginName,
|
||||||
UseDefaultRuntimeName: b.useLegacyConfig,
|
Logger: b.logger,
|
||||||
ContainerAnnotations: b.containerAnnotations,
|
RuntimeType: b.runtimeType,
|
||||||
|
UseLegacyConfig: b.useLegacyConfig,
|
||||||
|
ContainerAnnotations: b.containerAnnotations,
|
||||||
}
|
}
|
||||||
|
|
||||||
version, err := cfg.parseVersion(b.useLegacyConfig)
|
switch configVersion {
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse config version: %v", err)
|
|
||||||
}
|
|
||||||
switch version {
|
|
||||||
case 1:
|
case 1:
|
||||||
return (*ConfigV1)(cfg), nil
|
return (*ConfigV1)(cfg), nil
|
||||||
case 2:
|
default:
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("unsupported config version: %v", version)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseVersion returns the version of the config
|
// parseVersion returns the version of the config
|
||||||
func (c *Config) parseVersion(useLegacyConfig bool) (int, error) {
|
func (b *builder) parseVersion(c *toml.Tree) (int64, error) {
|
||||||
defaultVersion := 2
|
if c == nil || len(c.Keys()) == 0 {
|
||||||
if useLegacyConfig {
|
// No config exists, or the config file is empty.
|
||||||
defaultVersion = 1
|
if b.useLegacyConfig {
|
||||||
|
// If a legacy config is explicitly requested, we default to a v1 config.
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
// Use the requested version.
|
||||||
|
return int64(b.configVersion), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v := c.Get("version").(type) {
|
switch v := c.Get("version").(type) {
|
||||||
case nil:
|
case nil:
|
||||||
switch len(c.Keys()) {
|
return 1, nil
|
||||||
case 0: // No config exists, or the config file is empty, use version inferred from containerd
|
|
||||||
return defaultVersion, nil
|
|
||||||
default: // A config file exists, has content, and no version is set
|
|
||||||
return 1, nil
|
|
||||||
}
|
|
||||||
case int64:
|
case int64:
|
||||||
return int(v), nil
|
return v, nil
|
||||||
default:
|
default:
|
||||||
return -1, fmt.Errorf("unsupported type for version field: %v", v)
|
return -1, fmt.Errorf("unsupported type for version field: %v", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *builder) criRuntimePluginName(configVersion int64) (string, error) {
|
||||||
|
switch configVersion {
|
||||||
|
case 1:
|
||||||
|
return "cri", nil
|
||||||
|
case 2:
|
||||||
|
return "io.containerd.grpc.v1.cri", nil
|
||||||
|
default:
|
||||||
|
return "io.containerd.cri.v1.runtime", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) GetRuntimeConfig(name string) (engine.RuntimeConfig, error) {
|
func (c *Config) GetRuntimeConfig(name string) (engine.RuntimeConfig, error) {
|
||||||
if c == nil || c.Tree == nil {
|
if c == nil || c.Tree == nil {
|
||||||
return nil, fmt.Errorf("config is nil")
|
return nil, fmt.Errorf("config is nil")
|
||||||
}
|
}
|
||||||
runtimeData := c.GetSubtreeByPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "runtimes", name})
|
runtimeData := c.GetSubtreeByPath([]string{"plugins", c.CRIRuntimePluginName, "containerd", "runtimes", name})
|
||||||
return &containerdCfgRuntime{
|
return &containerdCfgRuntime{
|
||||||
tree: runtimeData,
|
tree: runtimeData,
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user