mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2024-11-24 21:14:00 +00:00
48d68e4eff
Signed-off-by: Evan Lezar <elezar@nvidia.com>
171 lines
4.5 KiB
Go
171 lines
4.5 KiB
Go
/**
|
|
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
**/
|
|
|
|
package container
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
|
|
"github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine"
|
|
"github.com/NVIDIA/nvidia-container-toolkit/tools/container/operator"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
const (
|
|
restartModeNone = "none"
|
|
restartModeSignal = "signal"
|
|
restartModeSystemd = "systemd"
|
|
)
|
|
|
|
// Options defines the shared options for the CLIs to configure containers runtimes.
|
|
type Options struct {
|
|
Config string
|
|
Socket string
|
|
RuntimeName string
|
|
RuntimeDir string
|
|
SetAsDefault bool
|
|
RestartMode string
|
|
HostRootMount string
|
|
}
|
|
|
|
// ParseArgs parses the command line arguments to the CLI
|
|
func ParseArgs(c *cli.Context, o *Options) error {
|
|
if o.RuntimeDir != "" {
|
|
logrus.Debug("Runtime directory already set; ignoring arguments")
|
|
return nil
|
|
}
|
|
|
|
args := c.Args()
|
|
|
|
logrus.Infof("Parsing arguments: %v", args.Slice())
|
|
if c.NArg() != 1 {
|
|
return fmt.Errorf("incorrect number of arguments")
|
|
}
|
|
|
|
o.RuntimeDir = args.Get(0)
|
|
|
|
logrus.Infof("Successfully parsed arguments")
|
|
|
|
return nil
|
|
}
|
|
|
|
// Configure applies the options to the specified config
|
|
func (o Options) Configure(cfg engine.Interface) error {
|
|
err := o.UpdateConfig(cfg)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to update config: %v", err)
|
|
}
|
|
return o.flush(cfg)
|
|
}
|
|
|
|
// Unconfigure removes the options from the specified config
|
|
func (o Options) Unconfigure(cfg engine.Interface) error {
|
|
err := o.RevertConfig(cfg)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to update config: %v", err)
|
|
}
|
|
return o.flush(cfg)
|
|
}
|
|
|
|
// flush flushes the specified config to disk
|
|
func (o Options) flush(cfg engine.Interface) error {
|
|
logrus.Infof("Flushing config to %v", o.Config)
|
|
n, err := cfg.Save(o.Config)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to flush config: %v", err)
|
|
}
|
|
if n == 0 {
|
|
logrus.Infof("Config file is empty, removed")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UpdateConfig updates the specified config to include the nvidia runtimes
|
|
func (o Options) UpdateConfig(cfg engine.Interface) error {
|
|
runtimes := operator.GetRuntimes(
|
|
operator.WithNvidiaRuntimeName(o.RuntimeName),
|
|
operator.WithSetAsDefault(o.SetAsDefault),
|
|
operator.WithRoot(o.RuntimeDir),
|
|
)
|
|
for name, runtime := range runtimes {
|
|
err := cfg.AddRuntime(name, runtime.Path, runtime.SetAsDefault)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update runtime %q: %v", name, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RevertConfig reverts the specified config to remove the nvidia runtimes
|
|
func (o Options) RevertConfig(cfg engine.Interface) error {
|
|
runtimes := operator.GetRuntimes(
|
|
operator.WithNvidiaRuntimeName(o.RuntimeName),
|
|
operator.WithSetAsDefault(o.SetAsDefault),
|
|
operator.WithRoot(o.RuntimeDir),
|
|
)
|
|
for name := range runtimes {
|
|
err := cfg.RemoveRuntime(name)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to remove runtime %q: %v", name, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Restart restarts the specified service
|
|
func (o Options) Restart(service string, withSignal func(string) error) error {
|
|
switch o.RestartMode {
|
|
case restartModeNone:
|
|
logrus.Warningf("Skipping restart of %v due to --restart-mode=%v", service, o.RestartMode)
|
|
return nil
|
|
case restartModeSignal:
|
|
return withSignal(o.Socket)
|
|
case restartModeSystemd:
|
|
return o.SystemdRestart(service)
|
|
}
|
|
|
|
return fmt.Errorf("invalid restart mode specified: %v", o.RestartMode)
|
|
}
|
|
|
|
// SystemdRestart restarts the specified service using systemd
|
|
func (o Options) SystemdRestart(service string) error {
|
|
var args []string
|
|
var msg string
|
|
if o.HostRootMount != "" {
|
|
msg = " on host"
|
|
args = append(args, "chroot", o.HostRootMount)
|
|
}
|
|
args = append(args, "systemctl", "restart", service)
|
|
|
|
logrus.Infof("Restarting %v%v using systemd: %v", service, msg, args)
|
|
|
|
//nolint:gosec // TODO: Can we harden this so that there is less risk of command injection
|
|
cmd := exec.Command(args[0], args[1:]...)
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("error restarting %v using systemd: %v", service, err)
|
|
}
|
|
|
|
return nil
|
|
}
|