From 4abdc2f35d7bba364f00951a303ad283a59e712e Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Tue, 18 Oct 2022 16:44:13 +0200 Subject: [PATCH] Add nvidia-ctk hook chmod command to set permissions This change adds an nvidia-ctk hook chmod command that can be used to update the permissions for paths in the container. This prepends the container root to the paths to allow these to be updated by runtime executables. Signed-off-by: Evan Lezar --- cmd/nvidia-ctk/hook/chmod/chmod.go | 132 +++++++++++++++++++++++++++++ cmd/nvidia-ctk/hook/hook.go | 2 + 2 files changed, 134 insertions(+) create mode 100644 cmd/nvidia-ctk/hook/chmod/chmod.go diff --git a/cmd/nvidia-ctk/hook/chmod/chmod.go b/cmd/nvidia-ctk/hook/chmod/chmod.go new file mode 100644 index 00000000..01567084 --- /dev/null +++ b/cmd/nvidia-ctk/hook/chmod/chmod.go @@ -0,0 +1,132 @@ +/** +# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +**/ + +package chmod + +import ( + "fmt" + "path/filepath" + "strings" + "syscall" + + "github.com/NVIDIA/nvidia-container-toolkit/internal/oci" + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" +) + +type command struct { + logger *logrus.Logger +} + +type config struct { + paths cli.StringSlice + mode string + containerSpec string +} + +// NewCommand constructs a chmod command with the specified logger +func NewCommand(logger *logrus.Logger) *cli.Command { + c := command{ + logger: logger, + } + return c.build() +} + +// build the chmod command +func (m command) build() *cli.Command { + cfg := config{} + + // Create the 'chmod' command + c := cli.Command{ + Name: "chmod", + Usage: "Set the permissions of folders in the container by running chmod. The container root is prefixed to the specified paths.", + Before: func(c *cli.Context) error { + return validateFlags(c, &cfg) + }, + Action: func(c *cli.Context) error { + return m.run(c, &cfg) + }, + } + + c.Flags = []cli.Flag{ + &cli.StringSliceFlag{ + Name: "path", + Usage: "Specifiy a path to apply the specified mode to", + Destination: &cfg.paths, + }, + &cli.StringFlag{ + Name: "mode", + Usage: "Specify the file mode", + Destination: &cfg.mode, + }, + &cli.StringFlag{ + Name: "container-spec", + Usage: "Specify the path to the OCI container spec. If empty or '-' the spec will be read from STDIN", + Destination: &cfg.containerSpec, + }, + } + + return &c +} + +func validateFlags(c *cli.Context, cfg *config) error { + if strings.TrimSpace(cfg.mode) == "" { + return fmt.Errorf("a non-empty mode must be specified") + } + + for _, p := range cfg.paths.Value() { + if strings.TrimSpace(p) == "" { + return fmt.Errorf("paths must not be empty") + } + } + + return nil +} + +func (m command) run(c *cli.Context, cfg *config) error { + s, err := oci.LoadContainerState(cfg.containerSpec) + if err != nil { + return fmt.Errorf("failed to load container state: %v", err) + } + + containerRoot, err := s.GetContainerRoot() + if err != nil { + return fmt.Errorf("failed to determined container root: %v", err) + } + if containerRoot == "" { + return fmt.Errorf("empty container root detected") + } + + paths := m.getPaths(containerRoot, cfg.paths.Value()) + if len(paths) == 0 { + m.logger.Debugf("No paths specified; exiting") + return nil + } + + args := append([]string{"/bin/chmod", cfg.mode}, paths...) + + return syscall.Exec(args[0], args, nil) +} + +// getPaths updates the specified paths relative to the root. +func (m command) getPaths(root string, paths []string) []string { + var pathsInRoot []string + for _, f := range paths { + pathsInRoot = append(pathsInRoot, filepath.Join(root, f)) + } + + return pathsInRoot +} diff --git a/cmd/nvidia-ctk/hook/hook.go b/cmd/nvidia-ctk/hook/hook.go index feac8f5d..7deed271 100644 --- a/cmd/nvidia-ctk/hook/hook.go +++ b/cmd/nvidia-ctk/hook/hook.go @@ -17,6 +17,7 @@ package hook import ( + chmod "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/chmod" symlinks "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/create-symlinks" ldcache "github.com/NVIDIA/nvidia-container-toolkit/cmd/nvidia-ctk/hook/update-ldcache" "github.com/sirupsen/logrus" @@ -46,6 +47,7 @@ func (m hookCommand) build() *cli.Command { hook.Subcommands = []*cli.Command{ ldcache.NewCommand(m.logger), symlinks.NewCommand(m.logger), + chmod.NewCommand(m.logger), } return &hook