From 8ad29421eb739f959d27213718a003b54e6c5cda Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Tue, 15 Feb 2022 16:46:23 +0100 Subject: podman network: add documentation for netavark Add some docs about the different network backends. Also remove the CNI word from network since we refer to either a netavark or CNI config. Signed-off-by: Paul Holzinger --- docs/source/markdown/podman-network-create.1.md | 2 +- docs/source/markdown/podman-network-inspect.1.md | 2 +- docs/source/markdown/podman-network-ls.1.md | 2 +- docs/source/markdown/podman-network-rm.1.md | 2 +- docs/source/markdown/podman-network.1.md | 38 +++++++++++++++--------- docs/source/markdown/podman.1.md | 6 ++-- 6 files changed, 31 insertions(+), 21 deletions(-) (limited to 'docs') diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md index 5be0c2595..357a06cea 100644 --- a/docs/source/markdown/podman-network-create.1.md +++ b/docs/source/markdown/podman-network-create.1.md @@ -1,7 +1,7 @@ % podman-network-create(1) ## NAME -podman\-network-create - Create a Podman CNI network +podman\-network-create - Create a Podman network ## SYNOPSIS **podman network create** [*options*] name diff --git a/docs/source/markdown/podman-network-inspect.1.md b/docs/source/markdown/podman-network-inspect.1.md index 726f167e5..ba9cc94d5 100644 --- a/docs/source/markdown/podman-network-inspect.1.md +++ b/docs/source/markdown/podman-network-inspect.1.md @@ -1,7 +1,7 @@ % podman-network-inspect(1) ## NAME -podman\-network\-inspect - Displays the raw CNI network configuration for one or more networks +podman\-network\-inspect - Displays the raw network configuration for one or more networks ## SYNOPSIS **podman network inspect** [*options*] *network* [*network* ...] diff --git a/docs/source/markdown/podman-network-ls.1.md b/docs/source/markdown/podman-network-ls.1.md index 99b734157..72a3b05e2 100644 --- a/docs/source/markdown/podman-network-ls.1.md +++ b/docs/source/markdown/podman-network-ls.1.md @@ -1,7 +1,7 @@ % podman-network-ls(1) ## NAME -podman\-network\-ls - Display a summary of CNI networks +podman\-network\-ls - Display a summary of networks ## SYNOPSIS **podman network ls** [*options*] diff --git a/docs/source/markdown/podman-network-rm.1.md b/docs/source/markdown/podman-network-rm.1.md index 12102ba5a..c6e33c571 100644 --- a/docs/source/markdown/podman-network-rm.1.md +++ b/docs/source/markdown/podman-network-rm.1.md @@ -1,7 +1,7 @@ % podman-network-rm(1) ## NAME -podman\-network\-rm - Remove one or more CNI networks +podman\-network\-rm - Remove one or more networks ## SYNOPSIS **podman network rm** [*options*] [*network...*] diff --git a/docs/source/markdown/podman-network.1.md b/docs/source/markdown/podman-network.1.md index 29ee70139..bc75cce3b 100644 --- a/docs/source/markdown/podman-network.1.md +++ b/docs/source/markdown/podman-network.1.md @@ -1,27 +1,37 @@ % podman-network(1) ## NAME -podman\-network - Manage Podman CNI networks +podman\-network - Manage Podman networks ## SYNOPSIS **podman network** *subcommand* ## DESCRIPTION -The network command manages CNI networks for Podman. +The network command manages networks for Podman. + +Podman supports two network backends [Netavark](https://github.com/containers/netavark) +and [CNI](https://www.cni.dev/). Support for netavark was added in Podman v4.0. To configure +the network backend use the `network_backend`key under the `[Network]` in +**[containers.conf(5)](https://github.com/containers/common/blob/master/docs/containers.conf.5.md)**. +New systems should use netavark by default, to check what backed is used run +`podman info --format {{.Host.NetworkBackend}}`. + +All network commands work for both backends but CNI and Netavark use different config files +so networks have to be created again after a backend change. ## COMMANDS -| Command | Man Page | Description | -| ---------- | -------------------------------------------------------------- | ------------------------------------------------------------------- | -| connect | [podman-network-connect(1)](podman-network-connect.1.md) | Connect a container to a network | -| create | [podman-network-create(1)](podman-network-create.1.md) | Create a Podman CNI network | -| disconnect | [podman-network-disconnect(1)](podman-network-disconnect.1.md) | Disconnect a container from a network | -| exists | [podman-network-exists(1)](podman-network-exists.1.md) | Check if the given network exists | -| inspect | [podman-network-inspect(1)](podman-network-inspect.1.md) | Displays the raw CNI network configuration for one or more networks | -| ls | [podman-network-ls(1)](podman-network-ls.1.md) | Display a summary of CNI networks | -| prune | [podman-network-prune(1)](podman-network-prune.1.md) | Remove all unused networks | -| reload | [podman-network-reload(1)](podman-network-reload.1.md) | Reload network configuration for containers | -| rm | [podman-network-rm(1)](podman-network-rm.1.md) | Remove one or more CNI networks | +| Command | Man Page | Description | +| ---------- | -------------------------------------------------------------- | --------------------------------------------------------------- | +| connect | [podman-network-connect(1)](podman-network-connect.1.md) | Connect a container to a network | +| create | [podman-network-create(1)](podman-network-create.1.md) | Create a Podman network | +| disconnect | [podman-network-disconnect(1)](podman-network-disconnect.1.md) | Disconnect a container from a network | +| exists | [podman-network-exists(1)](podman-network-exists.1.md) | Check if the given network exists | +| inspect | [podman-network-inspect(1)](podman-network-inspect.1.md) | Displays the raw network configuration for one or more networks | +| ls | [podman-network-ls(1)](podman-network-ls.1.md) | Display a summary of networks | +| prune | [podman-network-prune(1)](podman-network-prune.1.md) | Remove all unused networks | +| reload | [podman-network-reload(1)](podman-network-reload.1.md) | Reload network configuration for containers | +| rm | [podman-network-rm(1)](podman-network-rm.1.md) | Remove one or more networks | ## SEE ALSO -**[podman(1)](podman.1.md)** +**[podman(1)](podman.1.md)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)** diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index a77e1ecbd..b318001e4 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -300,7 +300,7 @@ the exit codes follow the `chroot` standard, see below: | [podman-events(1)](podman-events.1.md) | Monitor Podman events | | [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. | | [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. | -| [podman-generate(1)](podman-generate.1.md) | Generate structured data based on containers, pods or volumes. | +| [podman-generate(1)](podman-generate.1.md) | Generate structured data based on containers, pods or volumes. | | [podman-healthcheck(1)](podman-healthcheck.1.md) | Manage healthchecks for containers | | [podman-history(1)](podman-history.1.md) | Show the history of an image. | | [podman-image(1)](podman-image.1.md) | Manage images. | @@ -317,9 +317,9 @@ the exit codes follow the `chroot` standard, see below: | [podman-machine(1)](podman-machine.1.md) | Manage Podman's virtual machine | | [podman-manifest(1)](podman-manifest.1.md) | Create and manipulate manifest lists and image indexes. | | [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. | -| [podman-network(1)](podman-network.1.md) | Manage Podman CNI networks. | +| [podman-network(1)](podman-network.1.md) | Manage Podman networks. | | [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. | -| [podman-play(1)](podman-play.1.md) | Play containers, pods or volumes based on a structured input file. | +| [podman-play(1)](podman-play.1.md) | Play containers, pods or volumes based on a structured input file. | | [podman-pod(1)](podman-pod.1.md) | Management tool for groups of containers, called pods. | | [podman-port(1)](podman-port.1.md) | List port mappings for a container. | | [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. | -- cgit v1.2.3-54-g00ecf From bd8ac0017ef61144920c305af5cc9bae6803d69b Mon Sep 17 00:00:00 2001 From: Patrycja Guzik Date: Tue, 15 Feb 2022 23:54:45 +0100 Subject: Unify ls --filter docs for networks and pods Signed-off-by: Patrycja Guzik #13078 follow-up --- docs/source/markdown/podman-network-ls.1.md | 34 +++++++++++--------- docs/source/markdown/podman-pod-ps.1.md | 48 +++++++++++++++++------------ 2 files changed, 49 insertions(+), 33 deletions(-) (limited to 'docs') diff --git a/docs/source/markdown/podman-network-ls.1.md b/docs/source/markdown/podman-network-ls.1.md index 72a3b05e2..d5bdb6a39 100644 --- a/docs/source/markdown/podman-network-ls.1.md +++ b/docs/source/markdown/podman-network-ls.1.md @@ -12,20 +12,26 @@ Displays a list of existing podman networks. ## OPTIONS #### **--filter**, **-f**=*filter=value* -Filter output based on conditions given. -Multiple filters can be given with multiple uses of the --filter option. -Filters with the same key work inclusive with the only exception being -`label` which is exclusive. Filters with different keys always work exclusive. - -Valid filters are listed below: - -| **Filter** | **Description** | -| ---------- | ----------------------------------------------------------------- | -| name | [Name] Network name (accepts regex) | -| id | [ID] Full or partial network ID | -| label | [Key] or [Key=Value] Label assigned to a network | -| driver | [Driver] `bridge` or ,`macvlan` is supported | -| until | [Until] Show all networks that were created before the given time | +Provide filter values. + +The *filters* argument format is of `key=value`. If there is more than one *filter*, then pass multiple OPTIONS: **--filter** *foo=bar* **--filter** *bif=baz*. + +Supported filters: + +| **Filter** | **Description** | +| ---------- | ------------------------------------------------------------------------------------------------ | +| driver | Filter by driver type. | +| id | Filter by full or partial network ID. | +| label | Filter by network with (or without, in the case of label!=[...] is used) the specified labels. | +| name | Filter by network name (accepts `regex`). | +| until | Filter by networks created before given timestamp. | + + +The `driver` filter accepts values: `bridge`, `macvlan`, `ipvlan`. + +The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which shows images with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which shows images without the specified labels. + +The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time. #### **--format**=*format* diff --git a/docs/source/markdown/podman-pod-ps.1.md b/docs/source/markdown/podman-pod-ps.1.md index a0581df50..8a9c3f7cc 100644 --- a/docs/source/markdown/podman-pod-ps.1.md +++ b/docs/source/markdown/podman-pod-ps.1.md @@ -86,25 +86,35 @@ Default: created #### **--filter**, **-f**=*filter* -Filter output based on conditions given. -Multiple filters can be given with multiple uses of the --filter flag. -Filters with the same key work inclusive with the only exception being -`label` which is exclusive. Filters with different keys always work exclusive. - -Valid filters are listed below: - -| **Filter** | **Description** | -| ---------- | ------------------------------------------------------------------------------------- | -| id | [ID] Pod's ID (accepts regex) | -| name | [Name] Pod's name (accepts regex) | -| label | [Key] or [Key=Value] Label assigned to a container | -| until | Only list pods created before given timestamp | -| status | Pod's status: `stopped`, `running`, `paused`, `exited`, `dead`, `created`, `degraded` | -| network | [Network] name or full ID of network | -| ctr-names | Container name within the pod (accepts regex) | -| ctr-ids | Container ID within the pod (accepts regex) | -| ctr-status | Container status within the pod | -| ctr-number | Number of containers in the pod | +Provide filter values. + +The *filters* argument format is of `key=value`. If there is more than one *filter*, then pass multiple OPTIONS: **--filter** *foo=bar* **--filter** *bif=baz*. + +Supported filters: + +| Filter | Description | +| ---------- | -------------------------------------------------------------------------------------------------- | +| *ctr-ids* | Filter by container ID within the pod. | +| *ctr-names* | Filter by container name within the pod. | +| *ctr-number*| Filter by number of containers in the pod. | +| *ctr-status*| Filter by container status within the pod. | +| *id* | Filter by pod ID. | +| *label* | Filter by container with (or without, in the case of label!=[...] is used) the specified labels. | +| *name* | Filter by pod name. | +| *network* | Filter by network name or full ID of network. | +| *status* | Filter by pod status. | +| *until* | Filter by pods created before given timestamp. | + +The `ctr-ids`, `ctr-names`, `id`, `name` filters accept `regex` format. + +The `ctr-status` filter accepts values: `created`, `running`, `paused`, `stopped`, `exited`, `unknown`. + +The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes containers with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes containers without the specified labels. + +The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time. + +The `status` filter accepts values: `stopped`, `running`, `paused`, `exited`, `dead`, `created`, `degraded`. + #### **--help**, **-h** -- cgit v1.2.3-54-g00ecf From 1a8c715f1fa3fb417cd7ca3cde5e1c7e5391b3f4 Mon Sep 17 00:00:00 2001 From: "Jason T. Greene" Date: Sat, 29 Jan 2022 03:10:28 -0600 Subject: Introduce podman machine init --root=t|f and podman machine set --root=t|f Switch default to rootless for mac and windows Signed-off-by: Jason T. Greene --- cmd/podman/machine/init.go | 5 +- cmd/podman/machine/set.go | 56 ++++++++++++ docs/source/markdown/podman-machine-init.1.md | 9 ++ docs/source/markdown/podman-machine-set.1.md | 59 +++++++++++++ docs/source/markdown/podman-machine.1.md | 1 + pkg/machine/config.go | 9 +- pkg/machine/connection.go | 25 ++++++ pkg/machine/qemu/config.go | 2 + pkg/machine/qemu/machine.go | 122 ++++++++++++++++++++------ pkg/machine/wsl/machine.go | 70 ++++++++++++--- 10 files changed, 318 insertions(+), 40 deletions(-) create mode 100644 cmd/podman/machine/set.go create mode 100644 docs/source/markdown/podman-machine-set.1.md (limited to 'docs') diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go index 0834aa381..ab13d8651 100644 --- a/cmd/podman/machine/init.go +++ b/cmd/podman/machine/init.go @@ -26,7 +26,7 @@ var ( var ( initOpts = machine.InitOptions{} - defaultMachineName = "podman-machine-default" + defaultMachineName = machine.DefaultMachineName now bool ) @@ -99,6 +99,9 @@ func init() { IgnitionPathFlagName := "ignition-path" flags.StringVar(&initOpts.IgnitionPath, IgnitionPathFlagName, "", "Path to ignition file") _ = initCmd.RegisterFlagCompletionFunc(IgnitionPathFlagName, completion.AutocompleteDefault) + + rootfulFlagName := "rootful" + flags.BoolVar(&initOpts.Rootful, rootfulFlagName, false, "Whether this machine should prefer rootful container exectution") } // TODO should we allow for a users to append to the qemu cmdline? diff --git a/cmd/podman/machine/set.go b/cmd/podman/machine/set.go new file mode 100644 index 000000000..c978206f0 --- /dev/null +++ b/cmd/podman/machine/set.go @@ -0,0 +1,56 @@ +// +build amd64 arm64 + +package machine + +import ( + "github.com/containers/common/pkg/completion" + "github.com/containers/podman/v4/cmd/podman/registry" + "github.com/containers/podman/v4/pkg/machine" + "github.com/spf13/cobra" +) + +var ( + setCmd = &cobra.Command{ + Use: "set [options] [NAME]", + Short: "Sets a virtual machine setting", + Long: "Sets an updatable virtual machine setting", + RunE: setMachine, + Args: cobra.MaximumNArgs(1), + Example: `podman machine set --root=false`, + ValidArgsFunction: completion.AutocompleteNone, + } +) + +var ( + setOpts = machine.SetOptions{} +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Command: setCmd, + Parent: machineCmd, + }) + flags := setCmd.Flags() + + rootfulFlagName := "rootful" + flags.BoolVar(&setOpts.Rootful, rootfulFlagName, false, "Whether this machine should prefer rootful container execution") +} + +func setMachine(cmd *cobra.Command, args []string) error { + var ( + vm machine.VM + err error + ) + + vmName := defaultMachineName + if len(args) > 0 && len(args[0]) > 0 { + vmName = args[0] + } + provider := getSystemDefaultProvider() + vm, err = provider.LoadVMByName(vmName) + if err != nil { + return err + } + + return vm.Set(vmName, setOpts) +} diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md index b515e8763..36db5b1cd 100644 --- a/docs/source/markdown/podman-machine-init.1.md +++ b/docs/source/markdown/podman-machine-init.1.md @@ -55,6 +55,14 @@ Memory (in MB). Start the virtual machine immediately after it has been initialized. +#### **--rootful**=*true|false* + +Whether this machine should prefer rootful (`true`) or rootless (`false`) +container execution. This option will also determine the remote connection default +if there is no existing remote connection configurations. + +API forwarding, if available, will follow this setting. + #### **--timezone** Set the timezone for the machine and containers. Valid values are `local` or @@ -84,6 +92,7 @@ Print usage statement. ``` $ podman machine init $ podman machine init myvm +$ podman machine init --rootful $ podman machine init --disk-size 50 $ podman machine init --memory=1024 myvm $ podman machine init -v /Users:/mnt/Users diff --git a/docs/source/markdown/podman-machine-set.1.md b/docs/source/markdown/podman-machine-set.1.md new file mode 100644 index 000000000..e69779564 --- /dev/null +++ b/docs/source/markdown/podman-machine-set.1.md @@ -0,0 +1,59 @@ +% podman-machine-set(1) + +## NAME +podman\-machine\-set - Sets a virtual machine setting + +## SYNOPSIS +**podman machine set** [*options*] [*name*] + +## DESCRIPTION + +Sets an updatable virtual machine setting. + +Options mirror values passed to `podman machine init`. Only a limited +subset can be changed after machine initialization. + +## OPTIONS + +#### **--rootful**=*true|false* + +Whether this machine should prefer rootful (`true`) or rootless (`false`) +container execution. This option will also update the current podman +remote connection default if it is currently pointing at the specified +machine name (or `podman-machine-default` if no name is specified). + +API forwarding, if available, will follow this setting. + +#### **--help** + +Print usage statement. + +## EXAMPLES + +To switch the default VM `podman-machine-default` from rootless to rootful: + +``` +$ podman machine set --rootful +``` + +or more explicitly: + +``` +$ podman machine set --rootful=true +``` + +To switch the default VM `podman-machine-default` from rootful to rootless: +``` +$ podman machine set --rootful=false +``` + +To switch the VM `myvm` from rootless to rootful: +``` +$ podman machine set --rootful myvm +``` + +## SEE ALSO +**[podman(1)](podman.1.md)**, **[podman-machine(1)](podman-machine.1.md)** + +## HISTORY +February 2022, Originally compiled by Jason Greene diff --git a/docs/source/markdown/podman-machine.1.md b/docs/source/markdown/podman-machine.1.md index 8d9e77ea5..3bdfd0be9 100644 --- a/docs/source/markdown/podman-machine.1.md +++ b/docs/source/markdown/podman-machine.1.md @@ -16,6 +16,7 @@ podman\-machine - Manage Podman's virtual machine | init | [podman-machine-init(1)](podman-machine-init.1.md) | Initialize a new virtual machine | | list | [podman-machine-list(1)](podman-machine-list.1.md) | List virtual machines | | rm | [podman-machine-rm(1)](podman-machine-rm.1.md) | Remove a virtual machine | +| set | [podman-machine-set(1)](podman-machine-set.1.md) | Sets a virtual machine setting | | ssh | [podman-machine-ssh(1)](podman-machine-ssh.1.md) | SSH into a virtual machine | | start | [podman-machine-start(1)](podman-machine-start.1.md) | Start a virtual machine | | stop | [podman-machine-stop(1)](podman-machine-stop.1.md) | Stop a virtual machine | diff --git a/pkg/machine/config.go b/pkg/machine/config.go index 97237f5e5..efb1eda15 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -27,6 +27,7 @@ type InitOptions struct { URI url.URL Username string ReExec bool + Rootful bool } type QemuMachineStatus = string @@ -35,7 +36,8 @@ const ( // Running indicates the qemu vm is running Running QemuMachineStatus = "running" // Stopped indicates the vm has stopped - Stopped QemuMachineStatus = "stopped" + Stopped QemuMachineStatus = "stopped" + DefaultMachineName string = "podman-machine-default" ) type Provider interface { @@ -89,6 +91,10 @@ type ListResponse struct { IdentityPath string } +type SetOptions struct { + Rootful bool +} + type SSHOptions struct { Username string Args []string @@ -107,6 +113,7 @@ type RemoveOptions struct { type VM interface { Init(opts InitOptions) (bool, error) Remove(name string, opts RemoveOptions) (string, func() error, error) + Set(name string, opts SetOptions) error SSH(name string, opts SSHOptions) error Start(name string, opts StartOptions) error Stop(name string, opts StopOptions) error diff --git a/pkg/machine/connection.go b/pkg/machine/connection.go index d28ffcef1..841b2afa6 100644 --- a/pkg/machine/connection.go +++ b/pkg/machine/connection.go @@ -39,6 +39,31 @@ func AddConnection(uri fmt.Stringer, name, identity string, isDefault bool) erro return cfg.Write() } +func AnyConnectionDefault(name ...string) (bool, error) { + cfg, err := config.ReadCustomConfig() + if err != nil { + return false, err + } + for _, n := range name { + if n == cfg.Engine.ActiveService { + return true, nil + } + } + + return false, nil +} + +func ChangeDefault(name string) error { + cfg, err := config.ReadCustomConfig() + if err != nil { + return err + } + + cfg.Engine.ActiveService = name + + return cfg.Write() +} + func RemoveConnection(name string) error { cfg, err := config.ReadCustomConfig() if err != nil { diff --git a/pkg/machine/qemu/config.go b/pkg/machine/qemu/config.go index e76509bb1..c619b7dd4 100644 --- a/pkg/machine/qemu/config.go +++ b/pkg/machine/qemu/config.go @@ -33,6 +33,8 @@ type MachineVM struct { QMPMonitor Monitor // RemoteUsername of the vm user RemoteUsername string + // Whether this machine should run in a rootful or rootless manner + Rootful bool } type Mount struct { diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 81a6b4935..9beec2173 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -5,14 +5,15 @@ package qemu import ( "bufio" - "encoding/base64" "context" + "encoding/base64" "encoding/json" "fmt" "io/fs" "io/ioutil" "net" "net/http" + "net/url" "os" "os/exec" "path/filepath" @@ -166,14 +167,8 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { key string ) sshDir := filepath.Join(homedir.Get(), ".ssh") - // GetConfDir creates the directory so no need to check for - // its existence - vmConfigDir, err := machine.GetConfDir(vmtype) - if err != nil { - return false, err - } - jsonFile := filepath.Join(vmConfigDir, v.Name) + ".json" v.IdentityPath = filepath.Join(sshDir, v.Name) + v.Rootful = opts.Rootful switch opts.ImagePath { case "testing", "next", "stable", "": @@ -256,29 +251,33 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { // This kind of stinks but no other way around this r/n if len(opts.IgnitionPath) < 1 { uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/user/1000/podman/podman.sock", strconv.Itoa(v.Port), v.RemoteUsername) - if err := machine.AddConnection(&uri, v.Name, filepath.Join(sshDir, v.Name), opts.IsDefault); err != nil { - return false, err + uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root") + identity := filepath.Join(sshDir, v.Name) + + uris := []url.URL{uri, uriRoot} + names := []string{v.Name, v.Name + "-root"} + + // The first connection defined when connections is empty will become the default + // regardless of IsDefault, so order according to rootful + if opts.Rootful { + uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0] } - uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root") - if err := machine.AddConnection(&uriRoot, v.Name+"-root", filepath.Join(sshDir, v.Name), opts.IsDefault); err != nil { - return false, err + for i := 0; i < 2; i++ { + if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil { + return false, err + } } } else { fmt.Println("An ignition path was provided. No SSH connection was added to Podman") } // Write the JSON file - b, err := json.MarshalIndent(v, "", " ") - if err != nil { - return false, err - } - if err := ioutil.WriteFile(jsonFile, b, 0644); err != nil { - return false, err - } + v.writeConfig() // User has provided ignition file so keygen // will be skipped. if len(opts.IgnitionPath) < 1 { + var err error key, err = machine.CreateSSHKeys(v.IdentityPath) if err != nil { return false, err @@ -325,6 +324,30 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { return err == nil, err } +func (v *MachineVM) Set(name string, opts machine.SetOptions) error { + if v.Rootful == opts.Rootful { + return nil + } + + changeCon, err := machine.AnyConnectionDefault(v.Name, v.Name+"-root") + if err != nil { + return err + } + + if changeCon { + newDefault := v.Name + if opts.Rootful { + newDefault += "-root" + } + if err := machine.ChangeDefault(newDefault); err != nil { + return err + } + } + + v.Rootful = opts.Rootful + return v.writeConfig() +} + // Start executes the qemu command line and forks it func (v *MachineVM) Start(name string, _ machine.StartOptions) error { var ( @@ -457,7 +480,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error { } } - printAPIForwardInstructions(forwardState, forwardSock) + waitAPIAndPrintInfo(forwardState, forwardSock, v.Rootful, v.Name) return nil } @@ -929,9 +952,17 @@ func (v *MachineVM) setupAPIForwarding(cmd []string) ([]string, string, apiForwa return cmd, "", noForwarding } + destSock := "/run/user/1000/podman/podman.sock" + forwardUser := "core" + + if v.Rootful { + destSock = "/run/podman/podman.sock" + forwardUser = "root" + } + cmd = append(cmd, []string{"-forward-sock", socket}...) - cmd = append(cmd, []string{"-forward-dest", "/run/podman/podman.sock"}...) - cmd = append(cmd, []string{"-forward-user", "root"}...) + cmd = append(cmd, []string{"-forward-dest", destSock}...) + cmd = append(cmd, []string{"-forward-user", forwardUser}...) cmd = append(cmd, []string{"-forward-identity", v.IdentityPath}...) link := filepath.Join(filepath.Dir(filepath.Dir(socket)), "podman.sock") @@ -1031,19 +1062,32 @@ func waitAndPingAPI(sock string) { } } -func printAPIForwardInstructions(forwardState apiForwardingState, forwardSock string) { +func waitAPIAndPrintInfo(forwardState apiForwardingState, forwardSock string, rootFul bool, name string) { if forwardState != noForwarding { waitAndPingAPI(forwardSock) + if !rootFul { + fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n") + fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n") + fmt.Printf("issues with non-podman clients, you can switch using the following command: \n") + + suffix := "" + if name != machine.DefaultMachineName { + suffix = " " + name + } + fmt.Printf("\n\tpodman machine set --rootful%s\n\n", suffix) + } + fmt.Printf("API forwarding listening on: %s\n", forwardSock) if forwardState == dockerGlobal { - fmt.Printf("\nDocker API clients default to this address. You do not need to set DOCKER_HOST.\n\n") + fmt.Printf("Docker API clients default to this address. You do not need to set DOCKER_HOST.\n\n") } else { stillString := "still " switch forwardState { case notInstalled: - fmt.Printf("\nThe system helper service is not installed; the default Docker API socket address can't be used by podman.\n") + fmt.Printf("\nThe system helper service is not installed; the default Docker API socket\n") + fmt.Printf("address can't be used by podman. ") if helper := findClaimHelper(); len(helper) > 0 { - fmt.Printf("If you would like to install it run the following command:\n") + fmt.Printf("If you would like to install it run the\nfollowing command:\n") fmt.Printf("\n\tsudo %s install\n\n", helper) } case machineLocal: @@ -1053,9 +1097,31 @@ func printAPIForwardInstructions(forwardState apiForwardingState, forwardSock st default: stillString = "" } - fmt.Printf("You can %sconnect Docker API clients by setting DOCKER HOST using the\n", stillString) + + fmt.Printf("You can %sconnect Docker API clients by setting DOCKER_HOST using the\n", stillString) fmt.Printf("following command in your terminal session:\n") fmt.Printf("\n\texport DOCKER_HOST='unix://%s'\n\n", forwardSock) } } } + +func (v *MachineVM) writeConfig() error { + // GetConfDir creates the directory so no need to check for + // its existence + vmConfigDir, err := machine.GetConfDir(vmtype) + if err != nil { + return err + } + + jsonFile := filepath.Join(vmConfigDir, v.Name) + ".json" + // Write the JSON file + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + return err + } + if err := ioutil.WriteFile(jsonFile, b, 0644); err != nil { + return err + } + + return nil +} diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go index 6862e3579..5b0c757f0 100644 --- a/pkg/machine/wsl/machine.go +++ b/pkg/machine/wsl/machine.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package wsl @@ -8,6 +9,7 @@ import ( "fmt" "io" "io/ioutil" + "net/url" "os" "os/exec" "path/filepath" @@ -35,9 +37,6 @@ const ( ErrorSuccessRebootRequired = 3010 ) -// Usermode networking avoids potential nftables compatibility issues between the distro -// and the WSL Kernel. Additionally it avoids fw rule conflicts between distros, since -// all instances run under the same Kernel at runtime const containersConf = `[containers] [engine] @@ -162,6 +161,8 @@ type MachineVM struct { Port int // RemoteUsername of the vm user RemoteUsername string + // Whether this machine should run in a rootful or rootless manner + Rootful bool } type ExitCodeError struct { @@ -227,12 +228,13 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { homeDir := homedir.Get() sshDir := filepath.Join(homeDir, ".ssh") v.IdentityPath = filepath.Join(sshDir, v.Name) + v.Rootful = opts.Rootful if err := downloadDistro(v, opts); err != nil { return false, err } - if err := writeJSON(v); err != nil { + if err := v.writeConfig(); err != nil { return false, err } @@ -282,7 +284,7 @@ func downloadDistro(v *MachineVM, opts machine.InitOptions) error { return machine.DownloadImage(dd) } -func writeJSON(v *MachineVM) error { +func (v *MachineVM) writeConfig() error { vmConfigDir, err := machine.GetConfDir(vmtype) if err != nil { return err @@ -302,14 +304,26 @@ func writeJSON(v *MachineVM) error { } func setupConnections(v *MachineVM, opts machine.InitOptions, sshDir string) error { + uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/user/1000/podman/podman.sock", strconv.Itoa(v.Port), v.RemoteUsername) uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root") - if err := machine.AddConnection(&uriRoot, v.Name+"-root", filepath.Join(sshDir, v.Name), opts.IsDefault); err != nil { - return err + identity := filepath.Join(sshDir, v.Name) + + uris := []url.URL{uri, uriRoot} + names := []string{v.Name, v.Name + "-root"} + + // The first connection defined when connections is empty will become the default + // regardless of IsDefault, so order according to rootful + if opts.Rootful { + uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0] + } + + for i := 0; i < 2; i++ { + if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil { + return err + } } - user := opts.Username - uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", withUser("/run/[USER]/1000/podman/podman.sock", user), strconv.Itoa(v.Port), v.RemoteUsername) - return machine.AddConnection(&uri, v.Name, filepath.Join(sshDir, v.Name), opts.IsDefault) + return nil } func provisionWSLDist(v *MachineVM) (string, error) { @@ -714,6 +728,30 @@ func pipeCmdPassThrough(name string, input string, arg ...string) error { return cmd.Run() } +func (v *MachineVM) Set(name string, opts machine.SetOptions) error { + if v.Rootful == opts.Rootful { + return nil + } + + changeCon, err := machine.AnyConnectionDefault(v.Name, v.Name+"-root") + if err != nil { + return err + } + + if changeCon { + newDefault := v.Name + if opts.Rootful { + newDefault += "-root" + } + if err := machine.ChangeDefault(newDefault); err != nil { + return err + } + } + + v.Rootful = opts.Rootful + return v.writeConfig() +} + func (v *MachineVM) Start(name string, _ machine.StartOptions) error { if v.isRunning() { return errors.Errorf("%q is already running", name) @@ -726,6 +764,18 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error { return errors.Wrap(err, "WSL bootstrap script failed") } + if !v.Rootful { + fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n") + fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n") + fmt.Printf("issues with non-podman clients, you can switch using the following command: \n") + + suffix := "" + if name != machine.DefaultMachineName { + suffix = " " + name + } + fmt.Printf("\n\tpodman machine set --rootful%s\n\n", suffix) + } + globalName, pipeName, err := launchWinProxy(v) if err != nil { fmt.Fprintln(os.Stderr, "API forwarding for Docker API clients is not available due to the following startup failures.") -- cgit v1.2.3-54-g00ecf