aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman-msihooks/main.go46
-rw-r--r--cmd/podman-wslkerninst/event-hook.go73
-rw-r--r--cmd/podman-wslkerninst/main.go103
-rw-r--r--cmd/podman/common/inspect.go4
-rw-r--r--cmd/podman/inspect/inspect.go72
-rw-r--r--cmd/podman/pods/inspect.go54
-rw-r--r--cmd/podman/root.go4
-rw-r--r--cmd/podman/system/reset.go3
8 files changed, 264 insertions, 95 deletions
diff --git a/cmd/podman-msihooks/main.go b/cmd/podman-msihooks/main.go
new file mode 100644
index 000000000..903c91abb
--- /dev/null
+++ b/cmd/podman-msihooks/main.go
@@ -0,0 +1,46 @@
+//go:build windows
+// +build windows
+
+package main
+
+import (
+ "C"
+ "syscall"
+ "unsafe"
+
+ "github.com/containers/podman/v4/pkg/machine/wsl"
+)
+
+const KernelWarning = "WSL Kernel installation did not complete successfully. " +
+ "Podman machine will attempt to install this at a later time. " +
+ "You can also manually complete the installation using the " +
+ "\"wsl --update\" command."
+
+//export CheckWSL
+func CheckWSL(hInstall uint32) uint32 {
+ installed := wsl.IsWSLInstalled()
+ feature := wsl.IsWSLFeatureEnabled()
+ setMsiProperty(hInstall, "HAS_WSL", strBool(installed))
+ setMsiProperty(hInstall, "HAS_WSLFEATURE", strBool(feature))
+
+ return 0
+}
+
+func setMsiProperty(hInstall uint32, name string, value string) {
+ nameW, _ := syscall.UTF16PtrFromString(name)
+ valueW, _ := syscall.UTF16PtrFromString(value)
+
+ msi := syscall.NewLazyDLL("msi")
+ proc := msi.NewProc("MsiSetPropertyW")
+ _, _, _ = proc.Call(uintptr(hInstall), uintptr(unsafe.Pointer(nameW)), uintptr(unsafe.Pointer(valueW)))
+
+}
+func strBool(val bool) string {
+ if val {
+ return "1"
+ }
+
+ return "0"
+}
+
+func main() {}
diff --git a/cmd/podman-wslkerninst/event-hook.go b/cmd/podman-wslkerninst/event-hook.go
new file mode 100644
index 000000000..a5c23e4cf
--- /dev/null
+++ b/cmd/podman-wslkerninst/event-hook.go
@@ -0,0 +1,73 @@
+//go:build windows
+// +build windows
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sys/windows/svc/eventlog"
+)
+
+// Logrus hook that delegates to windows event log
+type EventLogHook struct {
+ events *eventlog.Log
+}
+
+type LogFormat struct {
+ name string
+}
+
+func (f *LogFormat) Format(entry *logrus.Entry) ([]byte, error) {
+ var b *bytes.Buffer
+
+ if entry.Buffer != nil {
+ b = entry.Buffer
+ } else {
+ b = &bytes.Buffer{}
+ }
+
+ fmt.Fprintf(b, "[%-5s] %s: %s", entry.Level.String(), f.name, entry.Message)
+
+ for key, value := range entry.Data {
+ fmt.Fprintf(b, " {%s = %s}", key, value)
+ }
+
+ b.WriteByte('\n')
+ return b.Bytes(), nil
+}
+
+func NewEventHook(events *eventlog.Log, name string) *EventLogHook {
+ logrus.SetFormatter(&LogFormat{name})
+ return &EventLogHook{events}
+}
+
+func (hook *EventLogHook) Fire(entry *logrus.Entry) error {
+ line, err := entry.String()
+ if err != nil {
+ return err
+ }
+
+ switch entry.Level {
+ case logrus.PanicLevel:
+ return hook.events.Error(1002, line)
+ case logrus.FatalLevel:
+ return hook.events.Error(1001, line)
+ case logrus.ErrorLevel:
+ return hook.events.Error(1000, line)
+ case logrus.WarnLevel:
+ return hook.events.Warning(1000, line)
+ case logrus.InfoLevel:
+ return hook.events.Info(1000, line)
+ case logrus.DebugLevel, logrus.TraceLevel:
+ return hook.events.Info(1001, line)
+ default:
+ return nil
+ }
+}
+
+func (hook *EventLogHook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
diff --git a/cmd/podman-wslkerninst/main.go b/cmd/podman-wslkerninst/main.go
new file mode 100644
index 000000000..0485db13c
--- /dev/null
+++ b/cmd/podman-wslkerninst/main.go
@@ -0,0 +1,103 @@
+//go:build windows
+// +build windows
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "path"
+ "syscall"
+ "time"
+ "unsafe"
+
+ "github.com/containers/podman/v4/pkg/machine/wsl"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sys/windows/svc/eventlog"
+)
+
+const (
+ MB_ICONWARNING = 0x00000030
+ MB_OK = 0x00000000
+ MB_DEFBUTTON1 = 0x00000000
+)
+
+const KernelWarning = "WSL Kernel installation did not complete successfully. " +
+ "Podman machine will attempt to install this at a later time. " +
+ "You can also manually complete the installation using the " +
+ "\"wsl --update\" command."
+
+func setupLogging(name string) (*eventlog.Log, error) {
+ // Reuse the Built-in .NET Runtime Source so that we do not
+ // have to provide a messaage table and modify the system
+ // event configuration
+ log, err := eventlog.Open(".NET Runtime")
+ if err != nil {
+ return nil, err
+ }
+
+ logrus.AddHook(NewEventHook(log, name))
+ logrus.SetLevel(logrus.InfoLevel)
+
+ return log, nil
+}
+
+func installWslKernel() error {
+ logrus.Info("Installing WSL Kernel update")
+ var (
+ err error
+ )
+ backoff := 500 * time.Millisecond
+ for i := 1; i < 6; i++ {
+ err = wsl.SilentExec("wsl", "--update")
+ if err == nil {
+ break
+ }
+
+ // In case of unusual circumstances (e.g. race with installer actions)
+ // retry a few times
+ logrus.Warn("An error occurred attempting the WSL Kernel update, retrying...")
+ time.Sleep(backoff)
+ backoff *= 2
+ }
+
+ if err != nil {
+ err = fmt.Errorf("could not install WSL Kernel: %w", err)
+ }
+
+ return err
+}
+
+// Creates an "warn" style pop-up window
+func warn(title string, caption string) int {
+ format := MB_ICONWARNING | MB_OK | MB_DEFBUTTON1
+
+ user32 := syscall.NewLazyDLL("user32.dll")
+ captionPtr, _ := syscall.UTF16PtrFromString(caption)
+ titlePtr, _ := syscall.UTF16PtrFromString(title)
+ ret, _, _ := user32.NewProc("MessageBoxW").Call(
+ uintptr(0),
+ uintptr(unsafe.Pointer(captionPtr)),
+ uintptr(unsafe.Pointer(titlePtr)),
+ uintptr(format))
+
+ return int(ret)
+}
+
+func main() {
+ args := os.Args
+ setupLogging(path.Base(args[0]))
+ if wsl.IsWSLInstalled() {
+ // nothing to do
+ logrus.Info("WSL Kernel already installed")
+ return
+ }
+
+ result := installWslKernel()
+ if result != nil {
+ logrus.Error(result.Error())
+ _ = warn("Podman Setup", KernelWarning)
+ }
+
+ logrus.Info("WSL Kernel update successful")
+}
diff --git a/cmd/podman/common/inspect.go b/cmd/podman/common/inspect.go
index 12a5af5a9..f82161d31 100644
--- a/cmd/podman/common/inspect.go
+++ b/cmd/podman/common/inspect.go
@@ -11,6 +11,10 @@ const (
NetworkType = "network"
// PodType is the pod type.
PodType = "pod"
+ // PodLegacyType is the pod type for backwards compatibility with the old pod inspect code.
+ // This allows us to use the shared inspect code but still provide the correct output format
+ // when podman pod inspect was called.
+ PodLegacyType = "pod-legacy"
// VolumeType is the volume type
VolumeType = "volume"
)
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go
index d519bc7d9..ccabd7614 100644
--- a/cmd/podman/inspect/inspect.go
+++ b/cmd/podman/inspect/inspect.go
@@ -15,7 +15,6 @@ import (
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
- "github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -55,18 +54,10 @@ type inspector struct {
containerEngine entities.ContainerEngine
imageEngine entities.ImageEngine
options entities.InspectOptions
- podOptions entities.PodInspectOptions
}
// newInspector creates a new inspector based on the specified options.
func newInspector(options entities.InspectOptions) (*inspector, error) {
- switch options.Type {
- case common.ImageType, common.ContainerType, common.AllType, common.PodType, common.NetworkType, common.VolumeType:
- // Valid types.
- default:
- return nil, fmt.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, or %q", options.Type,
- common.ImageType, common.ContainerType, common.PodType, common.NetworkType, common.VolumeType, common.AllType)
- }
if options.Type == common.ImageType {
if options.Latest {
return nil, fmt.Errorf("latest is not supported for type %q", common.ImageType)
@@ -78,15 +69,10 @@ func newInspector(options entities.InspectOptions) (*inspector, error) {
if options.Type == common.PodType && options.Size {
return nil, fmt.Errorf("size is not supported for type %q", common.PodType)
}
- podOpts := entities.PodInspectOptions{
- Latest: options.Latest,
- Format: options.Format,
- }
return &inspector{
containerEngine: registry.ContainerEngine(),
imageEngine: registry.ImageEngine(),
options: options,
- podOptions: podOpts,
}, nil
}
@@ -140,34 +126,16 @@ func (i *inspector) inspect(namesOrIDs []string) error {
for i := range ctrData {
data = append(data, ctrData[i])
}
- case common.PodType:
- for _, pod := range namesOrIDs {
- i.podOptions.NameOrID = pod
- podData, err := i.containerEngine.PodInspect(ctx, i.podOptions)
- if err != nil {
- if !strings.Contains(err.Error(), define.ErrNoSuchPod.Error()) {
- errs = []error{err}
- } else {
- return err
- }
- } else {
- errs = nil
- data = append(data, podData)
- }
+ case common.PodType, common.PodLegacyType:
+ podData, allErrs, err := i.containerEngine.PodInspect(ctx, namesOrIDs, i.options)
+ if err != nil {
+ return err
}
- if i.podOptions.Latest { // latest means there are no names in the namesOrID array
- podData, err := i.containerEngine.PodInspect(ctx, i.podOptions)
- if err != nil {
- if !strings.Contains(err.Error(), define.ErrNoSuchPod.Error()) {
- errs = []error{err}
- } else {
- return err
- }
- } else {
- errs = nil
- data = append(data, podData)
- }
+ errs = allErrs
+ for i := range podData {
+ data = append(data, podData[i])
}
+
case common.NetworkType:
networkData, allErrs, err := registry.ContainerEngine().NetworkInspect(ctx, namesOrIDs, i.options)
if err != nil {
@@ -198,7 +166,14 @@ func (i *inspector) inspect(namesOrIDs []string) error {
var err error
switch {
case report.IsJSON(i.options.Format) || i.options.Format == "":
- err = printJSON(data)
+ if i.options.Type == common.PodLegacyType && len(data) == 1 {
+ // We need backwards compat with the old podman pod inspect behavior.
+ // https://github.com/containers/podman/pull/15675
+ // TODO (5.0): consider removing this to better match other commands.
+ err = printJSON(data[0])
+ } else {
+ err = printJSON(data)
+ }
default:
// Landing here implies user has given a custom --format
row := inspectNormalize(i.options.Format, tmpType)
@@ -221,7 +196,7 @@ func (i *inspector) inspect(namesOrIDs []string) error {
return nil
}
-func printJSON(data []interface{}) error {
+func printJSON(data interface{}) error {
enc := json.NewEncoder(os.Stdout)
// by default, json marshallers will force utf=8 from
// a string. this breaks healthchecks that use <,>, &&.
@@ -282,14 +257,13 @@ func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]inte
data = append(data, networkData[0])
continue
}
- i.podOptions.NameOrID = name
- podData, err := i.containerEngine.PodInspect(ctx, i.podOptions)
+
+ podData, errs, err := i.containerEngine.PodInspect(ctx, []string{name}, i.options)
if err != nil {
- if !strings.Contains(err.Error(), define.ErrNoSuchPod.Error()) {
- return nil, nil, err
- }
- } else {
- data = append(data, podData)
+ return nil, nil, err
+ }
+ if len(errs) == 0 {
+ data = append(data, podData[0])
continue
}
if len(errs) > 0 {
diff --git a/cmd/podman/pods/inspect.go b/cmd/podman/pods/inspect.go
index 082e8d9a1..22e781cdf 100644
--- a/cmd/podman/pods/inspect.go
+++ b/cmd/podman/pods/inspect.go
@@ -1,13 +1,8 @@
package pods
import (
- "context"
- "errors"
- "os"
- "text/template"
-
- "github.com/containers/common/pkg/report"
"github.com/containers/podman/v4/cmd/podman/common"
+ "github.com/containers/podman/v4/cmd/podman/inspect"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/validate"
"github.com/containers/podman/v4/pkg/domain/entities"
@@ -15,10 +10,6 @@ import (
)
var (
- inspectOptions = entities.PodInspectOptions{}
-)
-
-var (
inspectDescription = `Display the configuration for a pod by name or id
By default, this will render all results in a JSON array.`
@@ -27,10 +18,12 @@ var (
Use: "inspect [options] POD [POD...]",
Short: "Displays a pod configuration",
Long: inspectDescription,
- RunE: inspect,
+ RunE: inspectExec,
ValidArgsFunction: common.AutocompletePods,
Example: `podman pod inspect podID`,
}
+
+ inspectOpts = &entities.InspectOptions{}
)
func init() {
@@ -41,40 +34,15 @@ func init() {
flags := inspectCmd.Flags()
formatFlagName := "format"
- flags.StringVarP(&inspectOptions.Format, formatFlagName, "f", "json", "Format the output to a Go template or json")
+ flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "json", "Format the output to a Go template or json")
_ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.PodInspectReport{}))
- validate.AddLatestFlag(inspectCmd, &inspectOptions.Latest)
+ validate.AddLatestFlag(inspectCmd, &inspectOpts.Latest)
}
-func inspect(cmd *cobra.Command, args []string) error {
- if len(args) < 1 && !inspectOptions.Latest {
- return errors.New("you must provide the name or id of a running pod")
- }
- if len(args) > 0 && inspectOptions.Latest {
- return errors.New("--latest and containers cannot be used together")
- }
-
- if !inspectOptions.Latest {
- inspectOptions.NameOrID = args[0]
- }
- responses, err := registry.ContainerEngine().PodInspect(context.Background(), inspectOptions)
- if err != nil {
- return err
- }
-
- if report.IsJSON(inspectOptions.Format) {
- enc := json.NewEncoder(os.Stdout)
- enc.SetIndent("", " ")
- return enc.Encode(responses)
- }
-
- // Cannot use report.New() as it enforces {{range .}} for OriginUser templates
- tmpl := template.New(cmd.Name()).Funcs(template.FuncMap(report.DefaultFuncs))
- format := report.NormalizeFormat(inspectOptions.Format)
- tmpl, err = tmpl.Parse(format)
- if err != nil {
- return err
- }
- return tmpl.Execute(os.Stdout, *responses)
+func inspectExec(cmd *cobra.Command, args []string) error {
+ // We need backwards compat with the old podman pod inspect behavior.
+ // https://github.com/containers/podman/pull/15675
+ inspectOpts.Type = common.PodLegacyType
+ return inspect.Inspect(args, *inspectOpts)
}
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index f45dc94b2..0261cd670 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -475,8 +475,8 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
pFlags.StringVar(&logLevel, logLevelFlagName, logLevel, fmt.Sprintf("Log messages above specified level (%s)", strings.Join(common.LogLevels, ", ")))
_ = rootCmd.RegisterFlagCompletionFunc(logLevelFlagName, common.AutocompleteLogLevel)
- pFlags.BoolVar(&debug, "debug", false, "Docker compatibility, force setting of log-level")
- _ = pFlags.MarkHidden("debug")
+ lFlags.BoolVarP(&debug, "debug", "D", false, "Docker compatibility, force setting of log-level")
+ _ = lFlags.MarkHidden("debug")
// Only create these flags for ABI connections
if !registry.IsRemote() {
diff --git a/cmd/podman/system/reset.go b/cmd/podman/system/reset.go
index 20f15a34f..02c4a7b46 100644
--- a/cmd/podman/system/reset.go
+++ b/cmd/podman/system/reset.go
@@ -62,7 +62,8 @@ func reset(cmd *cobra.Command, args []string) {
- all images
- all networks
- all build cache
- - all machines`)
+ - all machines
+ - all volumes`)
if len(listCtn) > 0 {
fmt.Println(`WARNING! The following external containers will be purged:`)