mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2024-11-24 13:05:17 +00:00
Allow install root to be set as flag
This change allows the destination / root to be set as the first positional argument OR as a command line flag. This allows for the GPU Operator to transition to a case where on the flag / envvar is used. Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
parent
0a2d8f4d22
commit
dc8972a26a
@ -35,7 +35,6 @@ type options struct {
|
|||||||
noDaemon bool
|
noDaemon bool
|
||||||
runtime string
|
runtime string
|
||||||
runtimeArgs string
|
runtimeArgs string
|
||||||
|
|
||||||
root string
|
root string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,14 +42,18 @@ type options struct {
|
|||||||
var Version = "development"
|
var Version = "development"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
remainingArgs, root, err := ParseArgs(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error: unable to parse arguments: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
options := options{}
|
options := options{}
|
||||||
|
|
||||||
// Create the top-level CLI
|
// Create the top-level CLI
|
||||||
c := cli.NewApp()
|
c := cli.NewApp()
|
||||||
c.Name = "nvidia-toolkit"
|
c.Name = "nvidia-toolkit"
|
||||||
c.Usage = "Install the nvidia-container-toolkit for use by a given runtime"
|
c.Usage = "Install the nvidia-container-toolkit for use by a given runtime"
|
||||||
c.UsageText = "DESTINATION [-n | --no-daemon] [-r | --runtime] [-u | --runtime-args]"
|
c.UsageText = "[DESTINATION] [-n | --no-daemon] [-r | --runtime] [-u | --runtime-args]"
|
||||||
c.Description = "DESTINATION points to the host path underneath which the nvidia-container-toolkit should be installed.\nIt will be installed at ${DESTINATION}/toolkit"
|
c.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.Action = func(ctx *cli.Context) error {
|
c.Action = func(ctx *cli.Context) error {
|
||||||
@ -82,17 +85,17 @@ func main() {
|
|||||||
Destination: &options.runtimeArgs,
|
Destination: &options.runtimeArgs,
|
||||||
EnvVars: []string{"RUNTIME_ARGS"},
|
EnvVars: []string{"RUNTIME_ARGS"},
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "root",
|
||||||
|
Value: root,
|
||||||
|
Usage: "the folder where the NVIDIA Container Toolkit is to be installed. It will be installed to `ROOT`/toolkit",
|
||||||
|
Destination: &options.root,
|
||||||
|
EnvVars: []string{"ROOT"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the CLI
|
// Run the CLI
|
||||||
log.Infof("Starting %v", c.Name)
|
log.Infof("Starting %v", c.Name)
|
||||||
|
|
||||||
remainingArgs, err := ParseArgs(os.Args, &options)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error: unable to parse arguments: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Run(remainingArgs); err != nil {
|
if err := c.Run(remainingArgs); err != nil {
|
||||||
log.Errorf("error running nvidia-toolkit: %v", err)
|
log.Errorf("error running nvidia-toolkit: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@ -139,44 +142,40 @@ func Run(c *cli.Context, o *options) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseArgs parses the command line arguments and returns the remaining arguments
|
// ParseArgs checks if a single positional argument was defined and extracts this the root.
|
||||||
func ParseArgs(args []string, o *options) ([]string, error) {
|
// If no positional arguments are defined, the it is assumed that the root is specified as a flag.
|
||||||
|
func ParseArgs(args []string) ([]string, string, error) {
|
||||||
log.Infof("Parsing arguments")
|
log.Infof("Parsing arguments")
|
||||||
|
|
||||||
numPositionalArgs := 2 // Includes command itself
|
if len(args) < 2 {
|
||||||
|
return args, "", nil
|
||||||
if len(args) < numPositionalArgs {
|
|
||||||
return nil, fmt.Errorf("missing arguments")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, arg := range args {
|
var lastPositionalArg int
|
||||||
if arg == "--help" || arg == "-h" {
|
for i, arg := range args {
|
||||||
return []string{args[0], arg}, nil
|
|
||||||
}
|
|
||||||
if arg == "--version" || arg == "-v" {
|
|
||||||
return []string{args[0], arg}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, arg := range args[:numPositionalArgs] {
|
|
||||||
if strings.HasPrefix(arg, "-") {
|
if strings.HasPrefix(arg, "-") {
|
||||||
return nil, fmt.Errorf("unexpected flag where argument should be")
|
break
|
||||||
}
|
}
|
||||||
|
lastPositionalArg = i
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, arg := range args[numPositionalArgs:] {
|
if lastPositionalArg == 0 {
|
||||||
if !strings.HasPrefix(arg, "-") {
|
return args, "", nil
|
||||||
return nil, fmt.Errorf("unexpected argument where flag should be")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
o.root = args[1]
|
if lastPositionalArg == 1 {
|
||||||
|
return append([]string{args[0]}, args[2:]...), args[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
return append([]string{args[0]}, args[numPositionalArgs:]...), nil
|
return nil, "", fmt.Errorf("unexpected positional argument(s) %v", args[2:lastPositionalArg+1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyFlags(o *options) error {
|
func verifyFlags(o *options) error {
|
||||||
log.Infof("Verifying Flags")
|
log.Infof("Verifying Flags")
|
||||||
|
if o.root == "" {
|
||||||
|
return fmt.Errorf("the install root must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
if _, exists := availableRuntimes[o.runtime]; !exists {
|
if _, exists := availableRuntimes[o.runtime]; !exists {
|
||||||
return fmt.Errorf("unknown runtime: %v", o.runtime)
|
return fmt.Errorf("unknown runtime: %v", o.runtime)
|
||||||
}
|
}
|
||||||
|
84
tools/container/nvidia-toolkit/run_test.go
Normal file
84
tools/container/nvidia-toolkit/run_test.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseArgs(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
args []string
|
||||||
|
expectedRemaining []string
|
||||||
|
expectedRoot string
|
||||||
|
expectedError error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: []string{},
|
||||||
|
expectedRemaining: []string{},
|
||||||
|
expectedRoot: "",
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"app"},
|
||||||
|
expectedRemaining: []string{"app"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"app", "root"},
|
||||||
|
expectedRemaining: []string{"app"},
|
||||||
|
expectedRoot: "root",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"app", "--flag"},
|
||||||
|
expectedRemaining: []string{"app", "--flag"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"app", "root", "--flag"},
|
||||||
|
expectedRemaining: []string{"app", "--flag"},
|
||||||
|
expectedRoot: "root",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"app", "root", "not-root", "--flag"},
|
||||||
|
expectedError: fmt.Errorf("unexpected positional argument(s) [not-root]"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"app", "root", "not-root"},
|
||||||
|
expectedError: fmt.Errorf("unexpected positional argument(s) [not-root]"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: []string{"app", "root", "not-root", "also"},
|
||||||
|
expectedError: fmt.Errorf("unexpected positional argument(s) [not-root also]"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||||
|
remaining, root, err := ParseArgs(tc.args)
|
||||||
|
if tc.expectedError != nil {
|
||||||
|
require.EqualError(t, err, tc.expectedError.Error())
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.ElementsMatch(t, tc.expectedRemaining, remaining)
|
||||||
|
require.Equal(t, tc.expectedRoot, root)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user