Skip to content

Commit

Permalink
Merge pull request #1683 from dcantah/uts-flag
Browse files Browse the repository at this point in the history
run: Add --uts flag
  • Loading branch information
AkihiroSuda authored Dec 28, 2022
2 parents b876456 + 17800d1 commit 723212c
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 25 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ Basic flags:
- :whale: `--pull=(always|missing|never)`: Pull image before running
- Default: "missing"
- :whale: `--pid=(host|container:<container>)`: PID namespace to use
- :whale: `--uts=(host)` : UTS namespace to use
- :whale: `--stop-signal`: Signal to stop a container (default "SIGTERM")
- :whale: `--stop-timeout`: Timeout (in seconds) to stop a container

Expand Down Expand Up @@ -577,7 +578,7 @@ Unimplemented `docker run` flags:
`--attach`, `--blkio-weight-device`, `--cgroup-parent`, `--cpu-rt-*`, `--detach-keys`, `--device-*`,
`--disable-content-trust`, `--domainname`, `--expose`, `--health-*`, `--ip6`, `--isolation`, `--no-healthcheck`,
`--link*`, `--mac-address`, `--publish-all`, `--sig-proxy`, `--storage-opt`,
`--userns`, `--uts`, `--volume-driver`, `--volumes-from`
`--userns`, `--volume-driver`, `--volumes-from`

### :whale: :blue_square: nerdctl exec
Run a command in a running container.
Expand Down
29 changes: 21 additions & 8 deletions cmd/nerdctl/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ func setCreateFlags(cmd *cobra.Command) {
cmd.Flags().Bool("oom-kill-disable", false, "Disable OOM Killer")
cmd.Flags().Int("oom-score-adj", 0, "Tune container’s OOM preferences (-1000 to 1000, rootless: 100 to 1000)")
cmd.Flags().String("pid", "", "PID namespace to use")
cmd.Flags().String("uts", "", "UTS namespace to use")
cmd.RegisterFlagCompletionFunc("pid", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"host"}, cobra.ShellCompDirectiveNoFileComp
})
Expand Down Expand Up @@ -566,18 +567,30 @@ func createContainer(ctx context.Context, cmd *cobra.Command, client *containerd
if err != nil {
return nil, nil, err
}

uts, err := cmd.Flags().GetString("uts")
if err != nil {
return nil, nil, err
}

if customHostname != "" {
// Docker considers this a validation error so keep compat.
if uts != "" {
return nil, nil, errors.New("conflicting options: hostname and UTS mode")
}
hostname = customHostname
}
opts = append(opts, oci.WithHostname(hostname))
internalLabels.hostname = hostname
// `/etc/hostname` does not exist on FreeBSD
if runtime.GOOS == "linux" {
hostnamePath := filepath.Join(stateDir, "hostname")
if err := os.WriteFile(hostnamePath, []byte(hostname+"\n"), 0644); err != nil {
return nil, nil, err
if uts == "" {
opts = append(opts, oci.WithHostname(hostname))
internalLabels.hostname = hostname
// `/etc/hostname` does not exist on FreeBSD
if runtime.GOOS == "linux" {
hostnamePath := filepath.Join(stateDir, "hostname")
if err := os.WriteFile(hostnamePath, []byte(hostname+"\n"), 0644); err != nil {
return nil, nil, err
}
opts = append(opts, withCustomEtcHostname(hostnamePath))
}
opts = append(opts, withCustomEtcHostname(hostnamePath))
}

netOpts, netSlice, ipAddress, ports, macAddress, err := generateNetOpts(cmd, dataStore, stateDir, ns, id)
Expand Down
71 changes: 55 additions & 16 deletions cmd/nerdctl/run_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,6 @@ func setPlatformOptions(
opts = append(opts, oci.WithDevShmSize(shmBytes/1024))
}

pid, err := cmd.Flags().GetString("pid")
if err != nil {
return nil, err
}
pidOpts, pidInternalLabel, err := generatePIDOpts(ctx, client, pid)
if err != nil {
return nil, err
}
internalLabels.pidContainer = pidInternalLabel
opts = append(opts, pidOpts...)

ulimitOpts, err := generateUlimitsOpts(cmd)
if err != nil {
return nil, err
Expand Down Expand Up @@ -175,22 +164,72 @@ func setPlatformOptions(
opts = append(opts, oci.WithRdt(rdtClass, "", ""))
}

nsOpts, err := generateNamespaceOpts(ctx, cmd, client, internalLabels)
if err != nil {
return nil, err
}
opts = append(opts, nsOpts...)

opts, err = setOOMScoreAdj(opts, cmd)
if err != nil {
return nil, err
}

return opts, nil
}

// Helper to validate the namespace options exposed via run and return the correct
// opts.
func generateNamespaceOpts(
ctx context.Context,
cmd *cobra.Command,
client *containerd.Client,
internalLabels *internalLabels,
) ([]oci.SpecOpts, error) {
var opts []oci.SpecOpts

// UTS
uts, err := cmd.Flags().GetString("uts")
if err != nil {
return nil, err
}

switch uts {
case "host":
opts = append(opts, oci.WithHostNamespace(specs.UTSNamespace))
case "":
// Default, do nothing. Every container gets its own UTS ns by default.
default:
return nil, fmt.Errorf("unknown uts value. valid value(s) are 'host', got: %q", uts)
}

// IPC
ipc, err := cmd.Flags().GetString("ipc")
if err != nil {
return nil, err
}
// if nothing is specified, or if private, default to normal behavior
if ipc == "host" {

switch ipc {
case "host":
opts = append(opts, oci.WithHostNamespace(specs.IPCNamespace))
opts = append(opts, withBindMountHostIPC)
} else if ipc != "" && ipc != "private" {
return nil, fmt.Errorf("error: %v", "invalid ipc value, supported values are 'private' or 'host'")
case "private", "":
// If nothing is specified, or if private, default to normal behavior
default:
return nil, fmt.Errorf("unknown ipc value. valid values are 'private' or 'host', got: %q", ipc)
}

opts, err = setOOMScoreAdj(opts, cmd)
// PID
pid, err := cmd.Flags().GetString("pid")
if err != nil {
return nil, err
}
pidOpts, pidLabel, err := generatePIDOpts(ctx, client, pid)
if err != nil {
return nil, err
}
internalLabels.pidContainer = pidLabel
opts = append(opts, pidOpts...)

return opts, nil
}
Expand Down
15 changes: 15 additions & 0 deletions cmd/nerdctl/run_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,21 @@ func TestRunPidHost(t *testing.T) {
base.Cmd("run", "--rm", "--pid=host", testutil.AlpineImage, "ps", "auxw").AssertOutContains(strconv.Itoa(pid))
}

func TestRunUtsHost(t *testing.T) {
t.Parallel()
base := testutil.NewBase(t)

// Was thinking of os.ReadLink("/proc/1/ns/uts")
// but you'd get EPERM for rootless. Just validate the
// hostname is the same.
hostName, err := os.Hostname()
assert.NilError(base.T, err)

base.Cmd("run", "--rm", "--uts=host", testutil.AlpineImage, "hostname").AssertOutContains(hostName)
// Validate we can't provide a hostname with uts=host
base.Cmd("run", "--rm", "--uts=host", "--hostname=foobar", testutil.AlpineImage, "hostname").AssertFail()
}

func TestRunPidContainer(t *testing.T) {
t.Parallel()
base := testutil.NewBase(t)
Expand Down

0 comments on commit 723212c

Please sign in to comment.