Skip to content

Commit

Permalink
support default platform config in nerdctl.toml
Browse files Browse the repository at this point in the history
  • Loading branch information
YangKian committed Jul 3, 2022
1 parent 137f753 commit 05d05be
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 28 deletions.
4 changes: 2 additions & 2 deletions cmd/nerdctl/build.go
Expand Up @@ -38,7 +38,7 @@ import (
"github.com/spf13/cobra"
)

func newBuildCommand() *cobra.Command {
func newBuildCommand(cfg *BuildConfig) *cobra.Command {
var buildCommand = &cobra.Command{
Use: "build",
Short: "Build an image from a Dockerfile. Needs buildkitd to be running.",
Expand All @@ -63,7 +63,7 @@ func newBuildCommand() *cobra.Command {

// #region platform flags
// platform is defined as StringSlice, not StringArray, to allow specifying "--platform=amd64,arm64"
buildCommand.Flags().StringSlice("platform", []string{}, "Set target platform for build (e.g., \"amd64\", \"arm64\")")
buildCommand.Flags().StringSlice("platform", cfg.Platform, "Set target platform for build (e.g., \"amd64\", \"arm64\")")
buildCommand.RegisterFlagCompletionFunc("platform", shellCompletePlatforms)
// #endregion

Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/container.go
Expand Up @@ -31,7 +31,7 @@ func newContainerCommand() *cobra.Command {
}
containerCommand.AddCommand(
newCreateCommand(),
newRunCommand(),
newRunCommand(runConfig()),
newUpdateCommand(),
newExecCommand(),
containerLsCommand(),
Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/create.go
Expand Up @@ -45,7 +45,7 @@ func newCreateCommand() *cobra.Command {
SilenceErrors: true,
}
createCommand.Flags().SetInterspersed(false)
setCreateFlags(createCommand)
setCreateFlags(createCommand, runConfig())
return createCommand
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/nerdctl/image.go
Expand Up @@ -30,7 +30,7 @@ func newImageCommand() *cobra.Command {
SilenceErrors: true,
}
cmd.AddCommand(
newBuildCommand(),
newBuildCommand(buildConfig()),
// commitCommand is in "container", not in "image"
imageLsCommand(),
newHistoryCommand(),
Expand Down
64 changes: 46 additions & 18 deletions cmd/nerdctl/main.go
Expand Up @@ -19,6 +19,7 @@ package main
import (
"errors"
"fmt"
"github.com/containerd/nerdctl/pkg/netutil"
"os"
"runtime"
"strings"
Expand Down Expand Up @@ -87,17 +88,41 @@ func xmain() error {
// Config corresponds to nerdctl.toml .
// See docs/config.md .
type Config struct {
Debug bool `toml:"debug"`
DebugFull bool `toml:"debug_full"`
Address string `toml:"address"`
Namespace string `toml:"namespace"`
Snapshotter string `toml:"snapshotter"`
CNIPath string `toml:"cni_path"`
CNINetConfPath string `toml:"cni_netconfpath"`
DataRoot string `toml:"data_root"`
CgroupManager string `toml:"cgroup_manager"`
InsecureRegistry bool `toml:"insecure_registry"`
HostsDir []string `toml:"hosts_dir"`
Debug bool `toml:"debug"`
DebugFull bool `toml:"debug_full"`
Address string `toml:"address"`
Namespace string `toml:"namespace"`
Snapshotter string `toml:"snapshotter"`
CNIPath string `toml:"cni_path"`
CNINetConfPath string `toml:"cni_netconfpath"`
DataRoot string `toml:"data_root"`
CgroupManager string `toml:"cgroup_manager"`
InsecureRegistry bool `toml:"insecure_registry"`
HostsDir []string `toml:"hosts_dir"`
RunConfig *RunConfig `toml:"default_run_config"`
BuildConfig *BuildConfig `toml:"default_build_config"`
}

type RunConfig struct {
Platform string `toml:"platform"`
Network []string `toml:"network"`
}

func runConfig() *RunConfig {
return &RunConfig{
Platform: "",
Network: []string{netutil.DefaultNetworkName},
}
}

type BuildConfig struct {
Platform []string `toml:"platform"`
}

func buildConfig() *BuildConfig {
return &BuildConfig{
Platform: []string{},
}
}

// NewConfig creates a default Config object statically,
Expand All @@ -115,23 +140,25 @@ func NewConfig() *Config {
CgroupManager: ncdefaults.CgroupManager(),
InsecureRegistry: false,
HostsDir: ncdefaults.HostsDirs(),
RunConfig: runConfig(),
BuildConfig: buildConfig(),
}
}

func initRootCmdFlags(rootCmd *cobra.Command, tomlPath string) error {
func initRootCmdFlags(rootCmd *cobra.Command, tomlPath string) (*Config, error) {
cfg := NewConfig()
if r, err := os.Open(tomlPath); err == nil {
logrus.Debugf("Loading config from %q", tomlPath)
defer r.Close()
dec := toml.NewDecoder(r).Strict(true) // set Strict to detect typo
if err := dec.Decode(cfg); err != nil {
return fmt.Errorf("failed to load nerdctl config (not daemon config) from %q (Hint: don't mix up daemon's `config.toml` with `nerdctl.toml`): %w", tomlPath, err)
return nil, fmt.Errorf("failed to load nerdctl config (not daemon config) from %q (Hint: don't mix up daemon's `config.toml` with `nerdctl.toml`): %w", tomlPath, err)
}
logrus.Debugf("Loaded config %+v", cfg)
} else {
logrus.WithError(err).Debugf("Not loading config from %q", tomlPath)
if !errors.Is(err, os.ErrNotExist) {
return err
return nil, err
}
}
rootCmd.PersistentFlags().Bool("debug", cfg.Debug, "debug mode")
Expand All @@ -152,7 +179,7 @@ func initRootCmdFlags(rootCmd *cobra.Command, tomlPath string) error {
rootCmd.PersistentFlags().Bool("insecure-registry", cfg.InsecureRegistry, "skips verifying HTTPS certs, and allows falling back to plain HTTP")
// hosts-dir is defined as StringSlice, not StringArray, to allow specifying "--hosts-dir=/etc/containerd/certs.d,/etc/docker/certs.d"
rootCmd.PersistentFlags().StringSlice("hosts-dir", cfg.HostsDir, "A directory that contains <HOST:PORT>/hosts.toml (containerd style) or <HOST:PORT>/{ca.cert, cert.pem, key.pem} (docker style)")
return nil
return cfg, nil
}

func newApp() (*cobra.Command, error) {
Expand All @@ -176,7 +203,8 @@ Config file ($NERDCTL_TOML): %s
TraverseChildren: true, // required for global short hands like -a, -H, -n
}
rootCmd.SetUsageTemplate(mainHelpTemplate)
if err := initRootCmdFlags(rootCmd, tomlPath); err != nil {
cfg, err := initRootCmdFlags(rootCmd, tomlPath)
if err != nil {
return nil, err
}

Expand Down Expand Up @@ -219,7 +247,7 @@ Config file ($NERDCTL_TOML): %s
rootCmd.AddCommand(
newCreateCommand(),
// #region Run & Exec
newRunCommand(),
newRunCommand(cfg.RunConfig),
newUpdateCommand(),
newExecCommand(),
// #endregion
Expand All @@ -241,7 +269,7 @@ Config file ($NERDCTL_TOML): %s
// #endregion

// Build
newBuildCommand(),
newBuildCommand(cfg.BuildConfig),

// #region Image management
newImagesCommand(),
Expand Down
57 changes: 57 additions & 0 deletions cmd/nerdctl/main_test.go
Expand Up @@ -17,8 +17,10 @@
package main

import (
"github.com/containerd/nerdctl/pkg/platformutil"
"os"
"path/filepath"
"strings"
"testing"

"github.com/containerd/containerd"
Expand Down Expand Up @@ -88,3 +90,58 @@ version = 2
base.Env = append(base.Env, "NERDCTL_TOML="+tomlPath)
base.Cmd("info").AssertFail()
}

// TestNerdctlSpecificConfig validates the configuration precedence [CLI, TOML, Default].
func TestNerdctlSpecificConfig(t *testing.T) {
testutil.DockerIncompatible(t)
t.Parallel()
tomlPath := filepath.Join(t.TempDir(), "nerdctl.toml")
err := os.WriteFile(tomlPath, []byte(`
[default_run_config]
platform = "arm64"
network = ["host"]
`), 0400)
assert.NilError(t, err)
base := testutil.NewBase(t)
testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64")

// [DEFAULT]
platformAmd64, err := platformutil.NormalizeString("amd64")
assert.NilError(t, err)
base.Cmd("run", testutil.CommonImage, "uname", "-m").AssertOutWithFunc(func(out string) error {
platformOut, err := platformutil.NormalizeString(strings.TrimSuffix(out, "\n"))
assert.NilError(t, err)
assert.Equal(t, platformAmd64, platformOut)
return nil
})

// [CLI, DEFAULT]
platformArm64, err := platformutil.NormalizeString("arm64")
assert.NilError(t, err)
base.Cmd("run", "--platform", "arm64", "--rm", testutil.CommonImage, "uname", "-m").AssertOutWithFunc(func(out string) error {
platformOut, err := platformutil.NormalizeString(strings.TrimSuffix(out, "\n"))
assert.NilError(t, err)
assert.Equal(t, platformArm64, platformOut)
return nil
})

// [TOML, DEFAULT]
if len(base.Env) == 0 {
base.Env = os.Environ()
}
base.Env = append(base.Env, "NERDCTL_TOML="+tomlPath)
base.Cmd("run", "--rm", testutil.CommonImage, "uname", "-m").AssertOutWithFunc(func(out string) error {
platformOut, err := platformutil.NormalizeString(strings.TrimSuffix(out, "\n"))
assert.NilError(t, err)
assert.Equal(t, platformArm64, platformOut)
return nil
})

// [CLI, TOML, DEFAULT]
base.Cmd("run", "--platform", "amd64", "--rm", testutil.CommonImage, "uname", "-m").AssertOutWithFunc(func(out string) error {
platformOut, err := platformutil.NormalizeString(strings.TrimSuffix(out, "\n"))
assert.NilError(t, err)
assert.Equal(t, platformAmd64, platformOut)
return nil
})
}
10 changes: 5 additions & 5 deletions cmd/nerdctl/run.go
Expand Up @@ -62,7 +62,7 @@ const (
tiniInitBinary = "tini"
)

func newRunCommand() *cobra.Command {
func newRunCommand(cfg *RunConfig) *cobra.Command {
shortHelp := "Run a command in a new container. Optionally specify \"ipfs://\" or \"ipns://\" scheme to pull image from IPFS."
longHelp := shortHelp
switch runtime.GOOS {
Expand All @@ -85,14 +85,14 @@ func newRunCommand() *cobra.Command {
}

runCommand.Flags().SetInterspersed(false)
setCreateFlags(runCommand)
setCreateFlags(runCommand, cfg)

runCommand.Flags().BoolP("detach", "d", false, "Run container in background and print container ID")

return runCommand
}

func setCreateFlags(cmd *cobra.Command) {
func setCreateFlags(cmd *cobra.Command, cfg *RunConfig) {

// No "-h" alias for "--help", because "-h" for "--hostname".
cmd.Flags().Bool("help", false, "show help")
Expand All @@ -117,13 +117,13 @@ func setCreateFlags(cmd *cobra.Command) {
// #endregion

// #region platform flags
cmd.Flags().String("platform", "", "Set platform (e.g. \"amd64\", \"arm64\")") // not a slice, and there is no --all-platforms
cmd.Flags().String("platform", cfg.Platform, "Set platform (e.g. \"amd64\", \"arm64\")") // not a slice, and there is no --all-platforms
cmd.RegisterFlagCompletionFunc("platform", shellCompletePlatforms)
// #endregion

// #region network flags
// network (net) is defined as StringSlice, not StringArray, to allow specifying "--network=cni1,cni2"
cmd.Flags().StringSlice("network", []string{netutil.DefaultNetworkName}, `Connect a container to a network ("bridge"|"host"|"none"|<CNI>)`)
cmd.Flags().StringSlice("network", cfg.Network, `Connect a container to a network ("bridge"|"host"|"none"|<CNI>)`)
cmd.RegisterFlagCompletionFunc("network", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return shellCompleteNetworkNames(cmd, []string{})
})
Expand Down

0 comments on commit 05d05be

Please sign in to comment.