summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/common/completion.go5
-rw-r--r--cmd/podman/common/create.go2
-rw-r--r--cmd/podman/common/create_opts.go2
-rw-r--r--cmd/podman/machine/init.go6
-rw-r--r--cmd/podman/machine/inspect.go34
-rw-r--r--cmd/podman/machine/list.go3
-rw-r--r--cmd/podman/machine/machine.go110
-rw-r--r--cmd/podman/machine/platform.go2
-rw-r--r--cmd/podman/machine/platform_windows.go2
-rw-r--r--cmd/podman/machine/rm.go12
-rw-r--r--cmd/podman/machine/set.go2
-rw-r--r--cmd/podman/machine/ssh.go2
-rw-r--r--cmd/podman/machine/start.go6
-rw-r--r--cmd/podman/machine/stop.go4
-rw-r--r--cmd/podman/main.go9
-rw-r--r--cmd/podman/play/kube.go2
-rw-r--r--cmd/podman/pods/create.go6
-rw-r--r--cmd/podman/root.go4
-rw-r--r--cmd/podman/secrets/inspect.go4
-rw-r--r--cmd/podman/system/connection.go15
-rw-r--r--cmd/podman/system/reset.go15
-rw-r--r--cmd/podman/system/reset_machine.go13
-rw-r--r--cmd/podman/system/reset_machine_unsupported.go8
-rw-r--r--cmd/podman/system/service_abi.go37
-rw-r--r--cmd/podman/validate/noop.go9
-rw-r--r--cmd/rootlessport/main.go24
-rw-r--r--cmd/rootlessport/wsl.go37
-rw-r--r--cmd/rootlessport/wsl_test.go89
28 files changed, 397 insertions, 67 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index ddf922b2a..6149a4465 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -492,6 +492,11 @@ func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([
return getImages(cmd, toComplete)
}
+// AutocompletePodExitPolicy - Autocomplete pod exit policy.
+func AutocompletePodExitPolicy(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ return config.PodExitPolicies, cobra.ShellCompDirectiveNoFileComp
+}
+
// AutocompleteCreateRun - Autocomplete only the fist argument as image and then do file completion.
func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if !validCurrentCmdLine(cmd, args, toComplete) {
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 1c1a7c3e3..d28becc8a 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -299,7 +299,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
logDriverFlagName := "log-driver"
createFlags.StringVar(
&cf.LogDriver,
- logDriverFlagName, logDriver(),
+ logDriverFlagName, LogDriver(),
"Logging driver for the container",
)
_ = cmd.RegisterFlagCompletionFunc(logDriverFlagName, AutocompleteLogDriver)
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 16f193b03..c40d1ea51 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -530,7 +530,7 @@ func volumes() []string {
return nil
}
-func logDriver() string {
+func LogDriver() string {
if !registry.IsRemote() {
return containerConfig.Containers.LogDriver
}
diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go
index 4991c6aa3..6c31f3531 100644
--- a/cmd/podman/machine/init.go
+++ b/cmd/podman/machine/init.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/machine"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -117,7 +118,7 @@ func initMachine(cmd *cobra.Command, args []string) error {
vm machine.VM
)
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
initOpts.Name = defaultMachineName
if len(args) > 0 {
if len(args[0]) > maxMachineNameSize {
@@ -145,11 +146,14 @@ func initMachine(cmd *cobra.Command, args []string) error {
// Finished = *, err != nil - Exit with an error message
return err
}
+ newMachineEvent(events.Init, events.Event{Name: initOpts.Name})
fmt.Println("Machine init complete")
+
if now {
err = vm.Start(initOpts.Name, machine.StartOptions{})
if err == nil {
fmt.Printf("Machine %q started successfully\n", initOpts.Name)
+ newMachineEvent(events.Start, events.Event{Name: initOpts.Name})
}
} else {
extra := ""
diff --git a/cmd/podman/machine/inspect.go b/cmd/podman/machine/inspect.go
index 21e5074b7..4600a2b6d 100644
--- a/cmd/podman/machine/inspect.go
+++ b/cmd/podman/machine/inspect.go
@@ -4,13 +4,12 @@
package machine
import (
- "encoding/json"
"os"
+ "github.com/containers/common/pkg/report"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/utils"
- "github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/machine"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -52,7 +51,7 @@ func inspect(cmd *cobra.Command, args []string) error {
args = append(args, defaultMachineName)
}
vms := make([]machine.InspectInfo, 0, len(args))
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
for _, vmName := range args {
vm, err := provider.LoadVMByName(vmName)
if err != nil {
@@ -66,12 +65,29 @@ func inspect(cmd *cobra.Command, args []string) error {
}
vms = append(vms, *ii)
}
- if len(inspectFlag.format) > 0 {
- // need jhonce to work his template magic
- return define.ErrNotImplemented
- }
- if err := printJSON(vms); err != nil {
- logrus.Error(err)
+ switch {
+ case cmd.Flag("format").Changed:
+ row := report.NormalizeFormat(inspectFlag.format)
+ row = report.EnforceRange(row)
+
+ tmpl, err := report.NewTemplate("Machine inspect").Parse(row)
+ if err != nil {
+ return err
+ }
+
+ w, err := report.NewWriterDefault(os.Stdout)
+ if err != nil {
+ return err
+ }
+
+ if err := tmpl.Execute(w, vms); err != nil {
+ logrus.Error(err)
+ }
+ w.Flush()
+ default:
+ if err := printJSON(vms); err != nil {
+ logrus.Error(err)
+ }
}
return errs.PrintErrors()
}
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go
index c987bf71a..ef26b7886 100644
--- a/cmd/podman/machine/list.go
+++ b/cmd/podman/machine/list.go
@@ -4,7 +4,6 @@
package machine
import (
- "encoding/json"
"os"
"sort"
"strconv"
@@ -85,7 +84,7 @@ func list(cmd *cobra.Command, args []string) error {
listFlag.format = "{{.Name}}\n"
}
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
listResponse, err = provider.List(opts)
if err != nil {
return errors.Wrap(err, "error listing vms")
diff --git a/cmd/podman/machine/machine.go b/cmd/podman/machine/machine.go
index d3775f022..553f1ef7a 100644
--- a/cmd/podman/machine/machine.go
+++ b/cmd/podman/machine/machine.go
@@ -4,25 +4,38 @@
package machine
import (
+ "errors"
+ "net"
+ "os"
+ "path/filepath"
+ "regexp"
"strings"
+ "sync"
+ "time"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
+ "github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/machine"
+ "github.com/containers/podman/v4/pkg/util"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var (
- noOp = func(cmd *cobra.Command, args []string) error {
- return nil
- }
+ // Pull in configured json library
+ json = registry.JSONLibrary()
+
+ openEventSock sync.Once // Singleton support for opening sockets as needed
+ sockets []net.Conn // Opened sockets, if any
+
// Command: podman _machine_
machineCmd = &cobra.Command{
Use: "machine",
Short: "Manage a virtual machine",
Long: "Manage a virtual machine. Virtual machines are used to run Podman.",
- PersistentPreRunE: noOp,
- PersistentPostRunE: noOp,
+ PersistentPreRunE: validate.NoOp,
+ PersistentPostRunE: closeMachineEvents,
RunE: validate.SubCommandExists,
}
)
@@ -51,7 +64,7 @@ func autocompleteMachine(cmd *cobra.Command, args []string, toComplete string) (
func getMachines(toComplete string) ([]string, cobra.ShellCompDirective) {
suggestions := []string{}
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
machines, err := provider.List(machine.ListOptions{})
if err != nil {
cobra.CompErrorln(err.Error())
@@ -64,3 +77,88 @@ func getMachines(toComplete string) ([]string, cobra.ShellCompDirective) {
}
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
+
+func initMachineEvents() {
+ sockPaths, err := resolveEventSock()
+ if err != nil {
+ logrus.Warnf("Failed to resolve machine event sockets, machine events will not be published: %v", err)
+ }
+
+ for _, path := range sockPaths {
+ conn, err := (&net.Dialer{}).DialContext(registry.Context(), "unix", path)
+ if err != nil {
+ logrus.Warnf("Failed to open event socket %q: %v", path, err)
+ continue
+ }
+ logrus.Debugf("Machine event socket %q found", path)
+ sockets = append(sockets, conn)
+ }
+}
+
+func resolveEventSock() ([]string, error) {
+ // Used mostly for testing
+ if sock, found := os.LookupEnv("PODMAN_MACHINE_EVENTS_SOCK"); found {
+ return []string{sock}, nil
+ }
+
+ xdg, err := util.GetRuntimeDir()
+ if err != nil {
+ logrus.Warnf("Failed to get runtime dir, machine events will not be published: %s", err)
+ return nil, nil
+ }
+
+ re := regexp.MustCompile(`machine_events.*\.sock`)
+ sockPaths := make([]string, 0)
+ fn := func(path string, info os.DirEntry, err error) error {
+ switch {
+ case err != nil:
+ return err
+ case info.IsDir():
+ return nil
+ case info.Type() != os.ModeSocket:
+ return nil
+ case !re.MatchString(info.Name()):
+ return nil
+ }
+
+ logrus.Debugf("Machine events will be published on: %q", path)
+ sockPaths = append(sockPaths, path)
+ return nil
+ }
+
+ if err := filepath.WalkDir(filepath.Join(xdg, "podman"), fn); err != nil {
+ if errors.Is(err, os.ErrNotExist) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return sockPaths, nil
+}
+
+func newMachineEvent(status events.Status, event events.Event) {
+ openEventSock.Do(initMachineEvents)
+
+ event.Status = status
+ event.Time = time.Now()
+ event.Type = events.Machine
+
+ payload, err := json.Marshal(event)
+ if err != nil {
+ logrus.Errorf("Unable to format machine event: %q", err)
+ return
+ }
+
+ for _, sock := range sockets {
+ if _, err := sock.Write(payload); err != nil {
+ logrus.Errorf("Unable to write machine event: %q", err)
+ }
+ }
+}
+
+func closeMachineEvents(cmd *cobra.Command, _ []string) error {
+ logrus.Debugf("Called machine %s.PersistentPostRunE(%s)", cmd.Name(), strings.Join(os.Args, " "))
+ for _, sock := range sockets {
+ _ = sock.Close()
+ }
+ return nil
+}
diff --git a/cmd/podman/machine/platform.go b/cmd/podman/machine/platform.go
index 77fec083e..5ba649a48 100644
--- a/cmd/podman/machine/platform.go
+++ b/cmd/podman/machine/platform.go
@@ -8,6 +8,6 @@ import (
"github.com/containers/podman/v4/pkg/machine/qemu"
)
-func getSystemDefaultProvider() machine.Provider {
+func GetSystemDefaultProvider() machine.Provider {
return qemu.GetQemuProvider()
}
diff --git a/cmd/podman/machine/platform_windows.go b/cmd/podman/machine/platform_windows.go
index 03978eda1..cdbc52459 100644
--- a/cmd/podman/machine/platform_windows.go
+++ b/cmd/podman/machine/platform_windows.go
@@ -5,6 +5,6 @@ import (
"github.com/containers/podman/v4/pkg/machine/wsl"
)
-func getSystemDefaultProvider() machine.Provider {
+func GetSystemDefaultProvider() machine.Provider {
return wsl.GetWSLProvider()
}
diff --git a/cmd/podman/machine/rm.go b/cmd/podman/machine/rm.go
index 617a70a76..a6e66265c 100644
--- a/cmd/podman/machine/rm.go
+++ b/cmd/podman/machine/rm.go
@@ -10,6 +10,7 @@ import (
"strings"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/machine"
"github.com/spf13/cobra"
)
@@ -50,7 +51,7 @@ func init() {
flags.BoolVar(&destroyOptions.SaveImage, imageFlagName, false, "Do not delete the image file")
}
-func rm(cmd *cobra.Command, args []string) error {
+func rm(_ *cobra.Command, args []string) error {
var (
err error
vm machine.VM
@@ -60,7 +61,7 @@ func rm(cmd *cobra.Command, args []string) error {
vmName = args[0]
}
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
vm, err = provider.LoadVMByName(vmName)
if err != nil {
return err
@@ -83,5 +84,10 @@ func rm(cmd *cobra.Command, args []string) error {
return nil
}
}
- return remove()
+ err = remove()
+ if err != nil {
+ return err
+ }
+ newMachineEvent(events.Remove, events.Event{Name: vmName})
+ return nil
}
diff --git a/cmd/podman/machine/set.go b/cmd/podman/machine/set.go
index a994c981b..5777882da 100644
--- a/cmd/podman/machine/set.go
+++ b/cmd/podman/machine/set.go
@@ -83,7 +83,7 @@ func setMachine(cmd *cobra.Command, args []string) error {
if len(args) > 0 && len(args[0]) > 0 {
vmName = args[0]
}
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
vm, err = provider.LoadVMByName(vmName)
if err != nil {
return err
diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go
index e1175d632..4a86da67a 100644
--- a/cmd/podman/machine/ssh.go
+++ b/cmd/podman/machine/ssh.go
@@ -51,7 +51,7 @@ func ssh(cmd *cobra.Command, args []string) error {
// Set the VM to default
vmName := defaultMachineName
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
// If len is greater than 0, it means we may have been
// provided the VM name. If so, we check. The VM name,
diff --git a/cmd/podman/machine/start.go b/cmd/podman/machine/start.go
index 56acb09cb..c9b99e63b 100644
--- a/cmd/podman/machine/start.go
+++ b/cmd/podman/machine/start.go
@@ -7,6 +7,7 @@ import (
"fmt"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/machine"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -31,7 +32,7 @@ func init() {
})
}
-func start(cmd *cobra.Command, args []string) error {
+func start(_ *cobra.Command, args []string) error {
var (
err error
vm machine.VM
@@ -41,7 +42,7 @@ func start(cmd *cobra.Command, args []string) error {
vmName = args[0]
}
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
vm, err = provider.LoadVMByName(vmName)
if err != nil {
return err
@@ -62,5 +63,6 @@ func start(cmd *cobra.Command, args []string) error {
return err
}
fmt.Printf("Machine %q started successfully\n", vmName)
+ newMachineEvent(events.Start, events.Event{Name: vmName})
return nil
}
diff --git a/cmd/podman/machine/stop.go b/cmd/podman/machine/stop.go
index e6bf3cf2b..993662792 100644
--- a/cmd/podman/machine/stop.go
+++ b/cmd/podman/machine/stop.go
@@ -7,6 +7,7 @@ import (
"fmt"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/machine"
"github.com/spf13/cobra"
)
@@ -40,7 +41,7 @@ func stop(cmd *cobra.Command, args []string) error {
if len(args) > 0 && len(args[0]) > 0 {
vmName = args[0]
}
- provider := getSystemDefaultProvider()
+ provider := GetSystemDefaultProvider()
vm, err = provider.LoadVMByName(vmName)
if err != nil {
return err
@@ -49,5 +50,6 @@ func stop(cmd *cobra.Command, args []string) error {
return err
}
fmt.Printf("Machine %q stopped successfully\n", vmName)
+ newMachineEvent(events.Stop, events.Event{Name: vmName})
return nil
}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 8f580601e..929c8a757 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -18,6 +18,7 @@ import (
_ "github.com/containers/podman/v4/cmd/podman/secrets"
_ "github.com/containers/podman/v4/cmd/podman/system"
_ "github.com/containers/podman/v4/cmd/podman/system/connection"
+ "github.com/containers/podman/v4/cmd/podman/validate"
_ "github.com/containers/podman/v4/cmd/podman/volumes"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/rootless"
@@ -64,8 +65,8 @@ func parseCommands() *cobra.Command {
c.Command.Hidden = true
// overwrite persistent pre/post function to skip setup
- c.Command.PersistentPostRunE = noop
- c.Command.PersistentPreRunE = noop
+ c.Command.PersistentPostRunE = validate.NoOp
+ c.Command.PersistentPreRunE = validate.NoOp
addCommand(c)
continue
}
@@ -120,7 +121,3 @@ func addCommand(c registry.CliCommand) {
c.Command.SetUsageTemplate(usageTemplate)
c.Command.DisableFlagsInUseLine = true
}
-
-func noop(cmd *cobra.Command, args []string) error {
- return nil
-}
diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go
index 40d14a609..3be7396ce 100644
--- a/cmd/podman/play/kube.go
+++ b/cmd/podman/play/kube.go
@@ -87,7 +87,7 @@ func init() {
_ = kubeCmd.RegisterFlagCompletionFunc(staticIPFlagName, completion.AutocompleteNone)
logDriverFlagName := "log-driver"
- flags.StringVar(&kubeOptions.LogDriver, logDriverFlagName, "", "Logging driver for the container")
+ flags.StringVar(&kubeOptions.LogDriver, logDriverFlagName, common.LogDriver(), "Logging driver for the container")
_ = kubeCmd.RegisterFlagCompletionFunc(logDriverFlagName, common.AutocompleteLogDriver)
logOptFlagName := "log-opt"
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 891ff2e3c..62f820790 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -72,6 +72,10 @@ func init() {
flags.StringVarP(&createOptions.Name, nameFlagName, "n", "", "Assign a name to the pod")
_ = createCommand.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone)
+ policyFlag := "exit-policy"
+ flags.StringVarP(&createOptions.ExitPolicy, policyFlag, "", string(containerConfig.Engine.PodExitPolicy), "Behaviour when the last container exits")
+ _ = createCommand.RegisterFlagCompletionFunc(policyFlag, common.AutocompletePodExitPolicy)
+
infraImageFlagName := "infra-image"
var defInfraImage string
if !registry.IsRemote() {
@@ -214,7 +218,7 @@ func create(cmd *cobra.Command, args []string) error {
ret, err := parsers.ParseUintList(copy)
copy = ""
if err != nil {
- errors.Wrapf(err, "could not parse list")
+ return errors.Wrapf(err, "could not parse list")
}
var vals []int
for ind, val := range ret {
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 9b1aa778b..2bd4fa723 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -153,7 +153,9 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
*runtime,
)
}
- runtimeFlag.Value.Set(*runtime)
+ if err := runtimeFlag.Value.Set(*runtime); err != nil {
+ return err
+ }
runtimeFlag.Changed = true
logrus.Debugf("Checkpoint was created using '%s'. Restore will use the same runtime", *runtime)
} else if cfg.RuntimePath != *runtime {
diff --git a/cmd/podman/secrets/inspect.go b/cmd/podman/secrets/inspect.go
index e8947e441..473d5620c 100644
--- a/cmd/podman/secrets/inspect.go
+++ b/cmd/podman/secrets/inspect.go
@@ -61,7 +61,9 @@ func inspect(cmd *cobra.Command, args []string) error {
return err
}
defer w.Flush()
- tmpl.Execute(w, inspected)
+ if err := tmpl.Execute(w, inspected); err != nil {
+ return err
+ }
} else {
buf, err := json.MarshalIndent(inspected, "", " ")
if err != nil {
diff --git a/cmd/podman/system/connection.go b/cmd/podman/system/connection.go
index 5164de78c..5dbe50fc9 100644
--- a/cmd/podman/system/connection.go
+++ b/cmd/podman/system/connection.go
@@ -7,18 +7,15 @@ import (
)
var (
- // Skip creating engines since this command will obtain connection information to said engines
- noOp = func(cmd *cobra.Command, args []string) error {
- return nil
- }
-
+ // ConnectionCmd skips creating engines (PersistentPreRunE/PersistentPostRunE are No-Op's) since
+ // sub-commands will obtain connection information to said engines
ConnectionCmd = &cobra.Command{
Use: "connection",
- Short: "Manage remote ssh destinations",
- Long: `Manage ssh destination information in podman configuration`,
- PersistentPreRunE: noOp,
+ Short: "Manage remote API service destinations",
+ Long: `Manage remote API service destination information in podman configuration`,
+ PersistentPreRunE: validate.NoOp,
RunE: validate.SubCommandExists,
- PersistentPostRunE: noOp,
+ PersistentPostRunE: validate.NoOp,
TraverseChildren: false,
}
)
diff --git a/cmd/podman/system/reset.go b/cmd/podman/system/reset.go
index 03783170f..176573bf6 100644
--- a/cmd/podman/system/reset.go
+++ b/cmd/podman/system/reset.go
@@ -61,7 +61,9 @@ func reset(cmd *cobra.Command, args []string) {
- all pods
- all images
- all networks
- - all build cache`)
+ - all build cache
+ - all machines`)
+
if len(listCtn) > 0 {
fmt.Println(`WARNING! The following external containers will be purged:`)
// print first 12 characters of ID and first configured name alias
@@ -81,7 +83,10 @@ func reset(cmd *cobra.Command, args []string) {
}
// Purge all the external containers with storage
- registry.ContainerEngine().ContainerRm(registry.Context(), listCtnIds, entities.RmOptions{Force: true, All: true, Ignore: true, Volumes: true})
+ _, err := registry.ContainerEngine().ContainerRm(registry.Context(), listCtnIds, entities.RmOptions{Force: true, All: true, Ignore: true, Volumes: true})
+ if err != nil {
+ logrus.Error(err)
+ }
// Shutdown all running engines, `reset` will hijack repository
registry.ContainerEngine().Shutdown(registry.Context())
registry.ImageEngine().Shutdown(registry.Context())
@@ -100,5 +105,11 @@ func reset(cmd *cobra.Command, args []string) {
//nolint:gocritic
os.Exit(define.ExecErrorCodeGeneric)
}
+
+ // Shutdown podman-machine and delete all machine files
+ if err := resetMachine(); err != nil {
+ logrus.Error(err)
+ }
+
os.Exit(0)
}
diff --git a/cmd/podman/system/reset_machine.go b/cmd/podman/system/reset_machine.go
new file mode 100644
index 000000000..a07b4fb83
--- /dev/null
+++ b/cmd/podman/system/reset_machine.go
@@ -0,0 +1,13 @@
+//go:build (amd64 && !remote) || (arm64 && !remote)
+// +build amd64,!remote arm64,!remote
+
+package system
+
+import (
+ cmdMach "github.com/containers/podman/v4/cmd/podman/machine"
+)
+
+func resetMachine() error {
+ provider := cmdMach.GetSystemDefaultProvider()
+ return provider.RemoveAndCleanMachines()
+}
diff --git a/cmd/podman/system/reset_machine_unsupported.go b/cmd/podman/system/reset_machine_unsupported.go
new file mode 100644
index 000000000..e063cd089
--- /dev/null
+++ b/cmd/podman/system/reset_machine_unsupported.go
@@ -0,0 +1,8 @@
+//go:build !amd64 && !arm64
+// +build !amd64,!arm64
+
+package system
+
+func resetMachine() error {
+ return nil
+}
diff --git a/cmd/podman/system/service_abi.go b/cmd/podman/system/service_abi.go
index f8abea3aa..9dc9de1c8 100644
--- a/cmd/podman/system/service_abi.go
+++ b/cmd/podman/system/service_abi.go
@@ -4,17 +4,18 @@
package system
import (
- "context"
+ "fmt"
"net"
"net/url"
"os"
"path/filepath"
+ "github.com/containers/podman/v4/cmd/podman/registry"
api "github.com/containers/podman/v4/pkg/api/server"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/domain/infra"
"github.com/containers/podman/v4/pkg/servicereaper"
- "github.com/containers/podman/v4/pkg/util"
+ "github.com/coreos/go-systemd/v22/activation"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
@@ -27,7 +28,26 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
err error
)
- if opts.URI != "" {
+ libpodRuntime, err := infra.GetRuntime(registry.Context(), flags, cfg)
+ if err != nil {
+ return err
+ }
+
+ if opts.URI == "" {
+ if _, found := os.LookupEnv("LISTEN_PID"); !found {
+ return errors.New("no service URI provided and socket activation protocol is not active")
+ }
+
+ listeners, err := activation.Listeners()
+ if err != nil {
+ return fmt.Errorf("cannot retrieve file descriptors from systemd: %w", err)
+ }
+ if len(listeners) != 1 {
+ return fmt.Errorf("wrong number of file descriptors for socket activation protocol (%d != 1)", len(listeners))
+ }
+ listener = listeners[0]
+ libpodRuntime.SetRemoteURI(listeners[0].Addr().String())
+ } else {
uri, err := url.Parse(opts.URI)
if err != nil {
return errors.Errorf("%s is an invalid socket destination", opts.URI)
@@ -39,7 +59,6 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
if err != nil {
return err
}
- util.SetSocketPath(path)
if os.Getenv("LISTEN_FDS") != "" {
// If it is activated by systemd, use the first LISTEN_FD (3)
// instead of opening the socket file.
@@ -67,6 +86,7 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
default:
logrus.Debugf("Attempting API Service endpoint scheme %q", uri.Scheme)
}
+ libpodRuntime.SetRemoteURI(uri.String())
}
// Close stdin, so shortnames will not prompt
@@ -78,15 +98,10 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
if err := unix.Dup2(int(devNullfile.Fd()), int(os.Stdin.Fd())); err != nil {
return err
}
- rt, err := infra.GetRuntime(context.Background(), flags, cfg)
- if err != nil {
- return err
- }
servicereaper.Start()
-
- infra.StartWatcher(rt)
- server, err := api.NewServerWithSettings(rt, listener, opts)
+ infra.StartWatcher(libpodRuntime)
+ server, err := api.NewServerWithSettings(libpodRuntime, listener, opts)
if err != nil {
return err
}
diff --git a/cmd/podman/validate/noop.go b/cmd/podman/validate/noop.go
new file mode 100644
index 000000000..2243ef5c4
--- /dev/null
+++ b/cmd/podman/validate/noop.go
@@ -0,0 +1,9 @@
+package validate
+
+import (
+ "github.com/spf13/cobra"
+)
+
+func NoOp(_ *cobra.Command, _ []string) error {
+ return nil
+}
diff --git a/cmd/rootlessport/main.go b/cmd/rootlessport/main.go
index e9ab8b076..5bd35a985 100644
--- a/cmd/rootlessport/main.go
+++ b/cmd/rootlessport/main.go
@@ -1,3 +1,6 @@
+//go:build linux
+// +build linux
+
package main
import (
@@ -307,11 +310,11 @@ func exposePorts(pm rkport.Manager, portMappings []types.PortMapping, childIP st
ChildPort: int(port.ContainerPort + i),
ChildIP: childIP,
}
- if err := rkportutil.ValidatePortSpec(spec, nil); err != nil {
- return err
- }
- if _, err := pm.AddPort(ctx, spec); err != nil {
- return err
+
+ for _, spec = range splitDualStackSpecIfWsl(spec) {
+ if err := validateAndAddPort(ctx, pm, spec); err != nil {
+ return err
+ }
}
}
}
@@ -319,6 +322,17 @@ func exposePorts(pm rkport.Manager, portMappings []types.PortMapping, childIP st
return nil
}
+func validateAndAddPort(ctx context.Context, pm rkport.Manager, spec rkport.Spec) error {
+ if err := rkportutil.ValidatePortSpec(spec, nil); err != nil {
+ return err
+ }
+ if _, err := pm.AddPort(ctx, spec); err != nil {
+ return err
+ }
+
+ return nil
+}
+
func child() error {
// load the config from the parent
var opaque map[string]string
diff --git a/cmd/rootlessport/wsl.go b/cmd/rootlessport/wsl.go
new file mode 100644
index 000000000..c1e67ba87
--- /dev/null
+++ b/cmd/rootlessport/wsl.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "net"
+ "strings"
+
+ "github.com/containers/common/pkg/machine"
+ rkport "github.com/rootless-containers/rootlesskit/pkg/port"
+)
+
+// WSL machines do not relay ipv4 traffic to dual-stack ports, simulate instead
+func splitDualStackSpecIfWsl(spec rkport.Spec) []rkport.Spec {
+ specs := []rkport.Spec{spec}
+ protocol := spec.Proto
+ if machine.MachineHostType() != machine.Wsl || strings.HasSuffix(protocol, "4") || strings.HasSuffix(protocol, "6") {
+ return specs
+ }
+
+ ip := net.ParseIP(spec.ParentIP)
+ splitLoopback := ip.IsLoopback() && ip.To4() == nil
+ // Map ::1 and 0.0.0.0/:: to ipv4 + ipv6 to simulate dual-stack
+ if ip.IsUnspecified() || splitLoopback {
+ specs = append(specs, spec)
+ specs[0].Proto = protocol + "4"
+ specs[1].Proto = protocol + "6"
+ if splitLoopback {
+ // Hacky, but we will only have one ipv4 loopback with WSL config
+ specs[0].ParentIP = "127.0.0.1"
+ }
+ if ip.IsUnspecified() {
+ specs[0].ParentIP = "0.0.0.0"
+ specs[1].ParentIP = "::"
+ }
+ }
+
+ return specs
+}
diff --git a/cmd/rootlessport/wsl_test.go b/cmd/rootlessport/wsl_test.go
new file mode 100644
index 000000000..83d7e3717
--- /dev/null
+++ b/cmd/rootlessport/wsl_test.go
@@ -0,0 +1,89 @@
+package main
+
+import (
+ "testing"
+
+ "github.com/containers/common/pkg/machine"
+ "github.com/rootless-containers/rootlesskit/pkg/port"
+ "github.com/stretchr/testify/assert"
+)
+
+type SpecData struct {
+ mach string
+ sourceProto string
+ sourceIP string
+ expectCount int
+ expectProto string
+ expectIP string
+ secondProto string
+ secondIP string
+}
+
+func TestDualStackSplit(t *testing.T) {
+ //nolint
+ const (
+ IP4_ALL = "0.0.0.0"
+ IP4__LO = "127.0.0.1"
+ IP6_ALL = "::"
+ IP6__LO = "::1"
+ TCP_ = "tcp"
+ TCP4 = "tcp4"
+ TCP6 = "tcp6"
+ WSL = "wsl"
+ ___ = ""
+ IP6_REG = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
+ IP4_REG = "10.0.0.1"
+ )
+
+ tests := []SpecData{
+ // Split cases
+ {WSL, TCP_, IP4_ALL, 2, TCP4, IP4_ALL, TCP6, IP6_ALL},
+ {WSL, TCP_, IP6_ALL, 2, TCP4, IP4_ALL, TCP6, IP6_ALL},
+ {WSL, TCP_, IP6__LO, 2, TCP4, IP4__LO, TCP6, IP6__LO},
+
+ // Non-Split
+ {WSL, TCP_, IP4__LO, 1, TCP_, IP4__LO, "", ""},
+ {WSL, TCP4, IP4_ALL, 1, TCP4, IP4_ALL, "", ""},
+ {WSL, TCP6, IP6__LO, 1, TCP6, IP6__LO, "", ""},
+ {WSL, TCP_, IP4_REG, 1, TCP_, IP4_REG, "", ""},
+ {WSL, TCP_, IP6_REG, 1, TCP_, IP6_REG, "", ""},
+ {___, TCP_, IP4_ALL, 1, TCP_, IP4_ALL, "", ""},
+ {___, TCP_, IP6_ALL, 1, TCP_, IP6_ALL, "", ""},
+ {___, TCP_, IP4__LO, 1, TCP_, IP4__LO, "", ""},
+ {___, TCP_, IP6__LO, 1, TCP_, IP6__LO, "", ""},
+ }
+
+ for _, data := range tests {
+ verifySplit(t, data)
+ }
+}
+
+func verifySplit(t *testing.T, data SpecData) {
+ machine := machine.GetMachineMarker()
+ oldEnable, oldType := machine.Enabled, machine.Type
+ machine.Enabled, machine.Type = len(data.mach) > 0, data.mach
+
+ source := port.Spec{
+ Proto: data.sourceProto,
+ ParentIP: data.sourceIP,
+ ParentPort: 100,
+ ChildIP: "1.1.1.1",
+ ChildPort: 200,
+ }
+ expect, second := source, source
+ specs := splitDualStackSpecIfWsl(source)
+
+ assert.Equal(t, data.expectCount, len(specs))
+
+ expect.Proto = data.expectProto
+ expect.ParentIP = data.expectIP
+ assert.Equal(t, expect, specs[0])
+
+ if data.expectCount > 1 {
+ second.Proto = data.secondProto
+ second.ParentIP = data.secondIP
+ assert.Equal(t, second, specs[1])
+ }
+
+ machine.Enabled, machine.Type = oldEnable, oldType
+}