diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/podman-msihooks/main.go | 46 | ||||
-rw-r--r-- | cmd/podman-wslkerninst/event-hook.go | 73 | ||||
-rw-r--r-- | cmd/podman-wslkerninst/main.go | 103 | ||||
-rw-r--r-- | cmd/podman/common/inspect.go | 4 | ||||
-rw-r--r-- | cmd/podman/inspect/inspect.go | 72 | ||||
-rw-r--r-- | cmd/podman/pods/inspect.go | 54 | ||||
-rw-r--r-- | cmd/podman/root.go | 4 | ||||
-rw-r--r-- | cmd/podman/system/reset.go | 3 |
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:`) |