diff options
Diffstat (limited to 'cmd/podman')
-rw-r--r-- | cmd/podman/common/specgen.go | 41 | ||||
-rw-r--r-- | cmd/podman/common/types.go | 3 | ||||
-rw-r--r-- | cmd/podman/generate/generate.go | 2 | ||||
-rw-r--r-- | cmd/podman/generate/kube.go | 68 | ||||
-rw-r--r-- | cmd/podman/generate/systemd.go | 2 | ||||
-rw-r--r-- | cmd/podman/images/load.go | 1 | ||||
-rw-r--r-- | cmd/podman/main.go | 1 | ||||
-rw-r--r-- | cmd/podman/manifest/annotate.go | 56 | ||||
-rw-r--r-- | cmd/podman/manifest/manifest.go | 6 | ||||
-rw-r--r-- | cmd/podman/play/kube.go | 101 | ||||
-rw-r--r-- | cmd/podman/play/play.go | 26 | ||||
-rw-r--r-- | cmd/podman/pods/create.go | 3 | ||||
-rw-r--r-- | cmd/podman/system/df.go | 282 | ||||
-rw-r--r-- | cmd/podman/system/migrate.go | 63 | ||||
-rw-r--r-- | cmd/podman/system/renumber.go | 57 | ||||
-rw-r--r-- | cmd/podman/system/reset.go | 82 |
16 files changed, 784 insertions, 10 deletions
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 7467c184a..3e9772576 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -26,6 +26,16 @@ func getCPULimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string) cpu := &specs.LinuxCPU{} hasLimits := false + const cpuPeriod = 100000 + + if c.CPUS > 0 { + quota := int64(c.CPUS * cpuPeriod) + period := uint64(cpuPeriod) + + cpu.Period = &period + cpu.Quota = "a + hasLimits = true + } if c.CPUShares > 0 { cpu.Shares = &c.CPUShares hasLimits = true @@ -142,6 +152,10 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []strin return nil, errors.Wrapf(err, "invalid value for memory") } memory.Limit = &ml + if c.MemorySwap == "" { + limit := 2 * ml + memory.Swap = &(limit) + } hasLimits = true } if m := c.MemoryReservation; len(m) > 0 { @@ -520,10 +534,13 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string case "label": // TODO selinux opts and label opts are the same thing s.ContainerSecurityConfig.SelinuxOpts = append(s.ContainerSecurityConfig.SelinuxOpts, con[1]) + s.Annotations[define.InspectAnnotationLabel] = con[1] case "apparmor": s.ContainerSecurityConfig.ApparmorProfile = con[1] + s.Annotations[define.InspectAnnotationApparmor] = con[1] case "seccomp": s.SeccompProfilePath = con[1] + s.Annotations[define.InspectAnnotationSeccomp] = con[1] default: return fmt.Errorf("invalid --security-opt 2: %q", opt) } @@ -606,7 +623,29 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string s.Name = c.Name s.OOMScoreAdj = &c.OOMScoreAdj - s.RestartPolicy = c.Restart + if c.Restart != "" { + splitRestart := strings.Split(c.Restart, ":") + switch len(splitRestart) { + case 1: + // No retries specified + case 2: + if strings.ToLower(splitRestart[0]) != "on-failure" { + return errors.Errorf("restart policy retries can only be specified with on-failure restart policy") + } + retries, err := strconv.Atoi(splitRestart[1]) + if err != nil { + return errors.Wrapf(err, "error parsing restart policy retry count") + } + if retries < 0 { + return errors.Errorf("must specify restart policy retry count as a number greater than 0") + } + var retriesUint uint = uint(retries) + s.RestartRetries = &retriesUint + default: + return errors.Errorf("invalid restart policy: may specify retries at most once") + } + s.RestartPolicy = splitRestart[0] + } s.Remove = c.Rm s.StopTimeout = &c.StopTimeout diff --git a/cmd/podman/common/types.go b/cmd/podman/common/types.go deleted file mode 100644 index 2427ae975..000000000 --- a/cmd/podman/common/types.go +++ /dev/null @@ -1,3 +0,0 @@ -package common - -var DefaultKernelNamespaces = "cgroup,ipc,net,uts" diff --git a/cmd/podman/generate/generate.go b/cmd/podman/generate/generate.go index b112e666a..7803c0c78 100644 --- a/cmd/podman/generate/generate.go +++ b/cmd/podman/generate/generate.go @@ -22,7 +22,7 @@ var ( func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ - Mode: []entities.EngineMode{entities.ABIMode}, + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: generateCmd, }) } diff --git a/cmd/podman/generate/kube.go b/cmd/podman/generate/kube.go new file mode 100644 index 000000000..86a9cc686 --- /dev/null +++ b/cmd/podman/generate/kube.go @@ -0,0 +1,68 @@ +package pods + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/utils" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + kubeOptions = entities.GenerateKubeOptions{} + kubeFile = "" + kubeDescription = `Command generates Kubernetes pod and service YAML (v1 specification) from a Podman container or pod. + +Whether the input is for a container or pod, Podman will always generate the specification as a pod.` + + kubeCmd = &cobra.Command{ + Use: "kube [flags] CONTAINER | POD", + Short: "Generate Kubernetes YAML from a container or pod.", + Long: kubeDescription, + RunE: kube, + Args: cobra.ExactArgs(1), + Example: `podman generate kube ctrID + podman generate kube podID + podman generate kube --service podID`, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: kubeCmd, + Parent: generateCmd, + }) + flags := kubeCmd.Flags() + flags.BoolVarP(&kubeOptions.Service, "service", "s", false, "Generate YAML for a Kubernetes service object") + flags.StringVarP(&kubeFile, "filename", "f", "", "Write output to the specified path") + flags.SetNormalizeFunc(utils.AliasFlags) +} + +func kube(cmd *cobra.Command, args []string) error { + report, err := registry.ContainerEngine().GenerateKube(registry.GetContext(), args[0], kubeOptions) + if err != nil { + return err + } + + content, err := ioutil.ReadAll(report.Reader) + if err != nil { + return err + } + if cmd.Flags().Changed("filename") { + if _, err := os.Stat(kubeFile); err == nil { + return errors.Errorf("cannot write to %q", kubeFile) + } + if err := ioutil.WriteFile(kubeFile, content, 0644); err != nil { + return errors.Wrapf(err, "cannot write to %q", kubeFile) + } + return nil + } + + fmt.Println(string(content)) + return nil +} diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go index 55d770249..20d9748d4 100644 --- a/cmd/podman/generate/systemd.go +++ b/cmd/podman/generate/systemd.go @@ -29,7 +29,7 @@ var ( func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ - Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Mode: []entities.EngineMode{entities.ABIMode}, Command: systemdCmd, Parent: generateCmd, }) diff --git a/cmd/podman/images/load.go b/cmd/podman/images/load.go index d34c794c6..4bbffd432 100644 --- a/cmd/podman/images/load.go +++ b/cmd/podman/images/load.go @@ -78,7 +78,6 @@ func load(cmd *cobra.Command, args []string) error { loadOpts.Tag = "latest" } if r, ok := ref.(reference.Named); ok { - fmt.Println(r.Name()) loadOpts.Name = r.Name() } } diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 422dee90b..76ec7bc8e 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -10,6 +10,7 @@ import ( _ "github.com/containers/libpod/cmd/podman/images" _ "github.com/containers/libpod/cmd/podman/manifest" _ "github.com/containers/libpod/cmd/podman/networks" + _ "github.com/containers/libpod/cmd/podman/play" _ "github.com/containers/libpod/cmd/podman/pods" "github.com/containers/libpod/cmd/podman/registry" _ "github.com/containers/libpod/cmd/podman/system" diff --git a/cmd/podman/manifest/annotate.go b/cmd/podman/manifest/annotate.go new file mode 100644 index 000000000..21d4fb747 --- /dev/null +++ b/cmd/podman/manifest/annotate.go @@ -0,0 +1,56 @@ +package manifest + +import ( + "context" + "fmt" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + manifestAnnotateOpts = entities.ManifestAnnotateOptions{} + annotateCmd = &cobra.Command{ + Use: "annotate [flags] LIST IMAGE", + Short: "Add or update information about an entry in a manifest list or image index", + Long: "Adds or updates information about an entry in a manifest list or image index.", + RunE: annotate, + Example: `podman manifest annotate --annotation left=right mylist:v1.11 image:v1.11-amd64`, + Args: cobra.ExactArgs(2), + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: annotateCmd, + Parent: manifestCmd, + }) + flags := annotateCmd.Flags() + flags.StringSliceVar(&manifestAnnotateOpts.Annotation, "annotation", nil, "set an `annotation` for the specified image") + flags.StringVar(&manifestAnnotateOpts.Arch, "arch", "", "override the `architecture` of the specified image") + flags.StringSliceVar(&manifestAnnotateOpts.Features, "features", nil, "override the `features` of the specified image") + flags.StringVar(&manifestAnnotateOpts.OS, "os", "", "override the `OS` of the specified image") + flags.StringSliceVar(&manifestAnnotateOpts.OSFeatures, "os-features", nil, "override the OS `features` of the specified image") + flags.StringVar(&manifestAnnotateOpts.OSVersion, "os-version", "", "override the OS `version` of the specified image") + flags.StringVar(&manifestAnnotateOpts.Variant, "variant", "", "override the `variant` of the specified image") +} + +func annotate(cmd *cobra.Command, args []string) error { + listImageSpec := args[0] + instanceSpec := args[1] + if listImageSpec == "" { + return errors.Errorf(`invalid image name "%s"`, listImageSpec) + } + if instanceSpec == "" { + return errors.Errorf(`invalid image digest "%s"`, instanceSpec) + } + updatedListID, err := registry.ImageEngine().ManifestAnnotate(context.Background(), args, manifestAnnotateOpts) + if err != nil { + return errors.Wrapf(err, "error removing from manifest list %s", listImageSpec) + } + fmt.Printf("%s\n", updatedListID) + return nil +} diff --git a/cmd/podman/manifest/manifest.go b/cmd/podman/manifest/manifest.go index b78879b34..88d264c1f 100644 --- a/cmd/podman/manifest/manifest.go +++ b/cmd/podman/manifest/manifest.go @@ -15,8 +15,10 @@ var ( Long: manifestDescription, TraverseChildren: true, RunE: validate.SubCommandExists, - Example: `podman manifest create localhost/list - podman manifest inspect localhost/list`, + Example: `podman manifest add mylist:v1.11 image:v1.11-amd64 + podman manifest create localhost/list + podman manifest inspect localhost/list + podman manifest annotate --annotation left=right mylist:v1.11 image:v1.11-amd64`, } ) diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go new file mode 100644 index 000000000..2499b54b9 --- /dev/null +++ b/cmd/podman/play/kube.go @@ -0,0 +1,101 @@ +package pods + +import ( + "fmt" + "os" + + "github.com/containers/common/pkg/auth" + "github.com/containers/image/v5/types" + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/utils" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +// playKubeOptionsWrapper allows for separating CLI-only fields from API-only +// fields. +type playKubeOptionsWrapper struct { + entities.PlayKubeOptions + + TLSVerifyCLI bool +} + +var ( + // https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/ + defaultSeccompRoot = "/var/lib/kubelet/seccomp" + kubeOptions = playKubeOptionsWrapper{} + kubeDescription = `Command reads in a structured file of Kubernetes YAML. + + It creates the pod and containers described in the YAML. The containers within the pod are then started and the ID of the new Pod is output.` + + kubeCmd = &cobra.Command{ + Use: "kube [flags] KUBEFILE", + Short: "Play a pod based on Kubernetes YAML.", + Long: kubeDescription, + RunE: kube, + Args: cobra.ExactArgs(1), + Example: `podman play kube nginx.yml + podman play kube --creds user:password --seccomp-profile-root /custom/path apache.yml`, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: kubeCmd, + Parent: playCmd, + }) + + flags := kubeCmd.Flags() + flags.SetNormalizeFunc(utils.AliasFlags) + flags.StringVar(&kubeOptions.Credentials, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") + flags.StringVar(&kubeOptions.Network, "network", "", "Connect pod to CNI network(s)") + flags.BoolVarP(&kubeOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images") + if !registry.IsRemote() { + flags.StringVar(&kubeOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") + flags.StringVar(&kubeOptions.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys") + flags.BoolVar(&kubeOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") + flags.StringVar(&kubeOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") + flags.StringVar(&kubeOptions.SeccompProfileRoot, "seccomp-profile-root", defaultSeccompRoot, "Directory path for seccomp profiles") + } +} + +func kube(cmd *cobra.Command, args []string) error { + // TLS verification in c/image is controlled via a `types.OptionalBool` + // which allows for distinguishing among set-true, set-false, unspecified + // which is important to implement a sane way of dealing with defaults of + // boolean CLI flags. + if cmd.Flags().Changed("tls-verify") { + kubeOptions.SkipTLSVerify = types.NewOptionalBool(!kubeOptions.TLSVerifyCLI) + } + if kubeOptions.Authfile != "" { + if _, err := os.Stat(kubeOptions.Authfile); err != nil { + return errors.Wrapf(err, "error getting authfile %s", kubeOptions.Authfile) + } + } + + report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), args[0], kubeOptions.PlayKubeOptions) + if err != nil { + return err + } + + for _, l := range report.Logs { + fmt.Fprintf(os.Stderr, l) + } + + fmt.Printf("Pod:\n%s\n", report.Pod) + switch len(report.Containers) { + case 0: + return nil + case 1: + fmt.Printf("Container:\n") + default: + fmt.Printf("Containers:\n") + } + for _, ctr := range report.Containers { + fmt.Println(ctr) + } + + return nil +} diff --git a/cmd/podman/play/play.go b/cmd/podman/play/play.go new file mode 100644 index 000000000..b151e5f5d --- /dev/null +++ b/cmd/podman/play/play.go @@ -0,0 +1,26 @@ +package pods + +import ( + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/spf13/cobra" +) + +var ( + // Command: podman _play_ + playCmd = &cobra.Command{ + Use: "play", + Short: "Play a pod and its containers from a structured file.", + Long: "Play structured data (e.g., Kubernetes pod or service yaml) based on containers and pods.", + TraverseChildren: true, + RunE: validate.SubCommandExists, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: playCmd, + }) +} diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go index 85b96d37b..0a2016496 100644 --- a/cmd/podman/pods/create.go +++ b/cmd/podman/pods/create.go @@ -12,6 +12,7 @@ import ( "github.com/containers/libpod/cmd/podman/validate" "github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/errorhandling" + createconfig "github.com/containers/libpod/pkg/spec" "github.com/containers/libpod/pkg/specgen" "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" @@ -57,7 +58,7 @@ func init() { flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod") flags.StringVarP(&createOptions.Hostname, "hostname", "", "", "Set a hostname to the pod") flags.StringVar(&podIDFile, "pod-id-file", "", "Write the pod ID to the file") - flags.StringVar(&share, "share", common.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share") + flags.StringVar(&share, "share", createconfig.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share") } func create(cmd *cobra.Command, args []string) error { diff --git a/cmd/podman/system/df.go b/cmd/podman/system/df.go new file mode 100644 index 000000000..7caa8e39a --- /dev/null +++ b/cmd/podman/system/df.go @@ -0,0 +1,282 @@ +package system + +import ( + "fmt" + "html/template" + "io" + "os" + "strings" + "text/tabwriter" + "time" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/docker/go-units" + "github.com/spf13/cobra" +) + +var ( + dfSystemDescription = ` + podman system df + + Show podman disk usage + ` + dfSystemCommand = &cobra.Command{ + Use: "df", + Args: validate.NoArgs, + Short: "Show podman disk usage", + Long: dfSystemDescription, + RunE: df, + } +) + +var ( + dfOptions entities.SystemDfOptions +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: dfSystemCommand, + Parent: systemCmd, + }) + flags := dfSystemCommand.Flags() + flags.BoolVarP(&dfOptions.Verbose, "verbose", "v", false, "Show detailed information on disk usage") + flags.StringVar(&dfOptions.Format, "format", "", "Pretty-print images using a Go template") +} + +func df(cmd *cobra.Command, args []string) error { + reports, err := registry.ContainerEngine().SystemDf(registry.Context(), dfOptions) + if err != nil { + return err + } + if dfOptions.Verbose { + return printVerbose(reports) + } + return printSummary(reports, dfOptions.Format) +} + +func printSummary(reports *entities.SystemDfReport, userFormat string) error { + + var ( + dfSummaries []*dfSummary + active int + size, reclaimable int64 + format string = "{{.Type}}\t{{.Total}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}\n" + w io.Writer = os.Stdout + ) + + // Images + if len(userFormat) > 0 { + format = userFormat + } + + for _, i := range reports.Images { + if i.Containers > 0 { + active += 1 + } + size += i.Size + if i.Containers < 1 { + reclaimable += i.Size + } + } + + imageSummary := dfSummary{ + Type: "Images", + Total: len(reports.Images), + Active: active, + size: size, + reclaimable: reclaimable, + } + dfSummaries = append(dfSummaries, &imageSummary) + + // Containers + + var ( + conActive int + conSize, conReclaimable int64 + ) + for _, c := range reports.Containers { + if c.Status == "running" { + conActive += 1 + } else { + conReclaimable += c.RWSize + } + conSize += c.RWSize + } + + containerSummary := dfSummary{ + Type: "Containers", + Total: len(reports.Containers), + Active: conActive, + size: conSize, + reclaimable: conReclaimable, + } + + dfSummaries = append(dfSummaries, &containerSummary) + + // Volumes + var ( + activeVolumes int + volumesSize, volumesReclaimable int64 + ) + + for _, v := range reports.Volumes { + activeVolumes += v.Links + volumesSize += v.Size + volumesReclaimable += v.Size + } + volumeSummary := dfSummary{ + Type: "Local Volumes", + Total: len(reports.Volumes), + Active: activeVolumes, + size: volumesSize, + reclaimable: volumesReclaimable, + } + + dfSummaries = append(dfSummaries, &volumeSummary) + + headers := "TYPE\tTOTAL\tACTIVE\tSIZE\tRECLAIMABLE\n" + format = "{{range . }}" + format + "{{end}}" + if len(userFormat) == 0 { + format = headers + format + } + return writeTemplate(w, format, dfSummaries) +} + +func printVerbose(reports *entities.SystemDfReport) error { + var ( + dfImages []*dfImage + dfContainers []*dfContainer + dfVolumes []*dfVolume + w io.Writer = os.Stdout + ) + + // Images + fmt.Print("\nImages space usage:\n\n") + // convert to dfImage for output + for _, d := range reports.Images { + dfImages = append(dfImages, &dfImage{SystemDfImageReport: d}) + } + imageHeaders := "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tSIZE\tSHARED SIZE\tUNIQUE SIZE\tCONTAINERS\n" + imageRow := "{{.Repository}}\t{{.Tag}}\t{{.ImageID}}\t{{.Created}}\t{{.Size}}\t{{.SharedSize}}\t{{.UniqueSize}}\t{{.Containers}}\n" + format := imageHeaders + "{{range . }}" + imageRow + "{{end}}" + if err := writeTemplate(w, format, dfImages); err != nil { + return nil + } + + // Containers + fmt.Print("\nContainers space usage:\n\n") + + // convert to dfContainers for output + for _, d := range reports.Containers { + dfContainers = append(dfContainers, &dfContainer{SystemDfContainerReport: d}) + } + containerHeaders := "CONTAINER ID\tIMAGE\tCOMMAND\tLOCAL VOLUMES\tSIZE\tCREATED\tSTATUS\tNAMES\n" + containerRow := "{{.ContainerID}}\t{{.Image}}\t{{.Command}}\t{{.LocalVolumes}}\t{{.Size}}\t{{.Created}}\t{{.Status}}\t{{.Names}}\n" + format = containerHeaders + "{{range . }}" + containerRow + "{{end}}" + if err := writeTemplate(w, format, dfContainers); err != nil { + return nil + } + + // Volumes + fmt.Print("\nLocal Volumes space usage:\n\n") + + // convert to dfVolume for output + for _, d := range reports.Volumes { + dfVolumes = append(dfVolumes, &dfVolume{SystemDfVolumeReport: d}) + } + volumeHeaders := "VOLUME NAME\tLINKS\tSIZE\n" + volumeRow := "{{.VolumeName}}\t{{.Links}}\t{{.Size}}\n" + format = volumeHeaders + "{{range . }}" + volumeRow + "{{end}}" + return writeTemplate(w, format, dfVolumes) +} + +func writeTemplate(w io.Writer, format string, output interface{}) error { + tmpl, err := template.New("dfout").Parse(format) + if err != nil { + return err + } + w = tabwriter.NewWriter(w, 8, 2, 2, ' ', 0) //nolint + if err := tmpl.Execute(w, output); err != nil { + return err + } + if flusher, ok := w.(interface{ Flush() error }); ok { + return flusher.Flush() + } + return nil +} + +type dfImage struct { + *entities.SystemDfImageReport +} + +func (d *dfImage) ImageID() string { + return d.SystemDfImageReport.ImageID[0:12] +} + +func (d *dfImage) Created() string { + return units.HumanDuration(time.Since(d.SystemDfImageReport.Created)) +} + +func (d *dfImage) Size() string { + return units.HumanSize(float64(d.SystemDfImageReport.Size)) +} + +func (d *dfImage) SharedSize() string { + return units.HumanSize(float64(d.SystemDfImageReport.SharedSize)) +} + +func (d *dfImage) UniqueSize() string { + return units.HumanSize(float64(d.SystemDfImageReport.UniqueSize)) +} + +type dfContainer struct { + *entities.SystemDfContainerReport +} + +func (d *dfContainer) ContainerID() string { + return d.SystemDfContainerReport.ContainerID[0:12] +} + +func (d *dfContainer) Image() string { + return d.SystemDfContainerReport.Image[0:12] +} + +func (d *dfContainer) Command() string { + return strings.Join(d.SystemDfContainerReport.Command, " ") +} + +func (d *dfContainer) Size() string { + return units.HumanSize(float64(d.SystemDfContainerReport.Size)) +} + +func (d *dfContainer) Created() string { + return units.HumanDuration(time.Since(d.SystemDfContainerReport.Created)) +} + +type dfVolume struct { + *entities.SystemDfVolumeReport +} + +func (d *dfVolume) Size() string { + return units.HumanSize(float64(d.SystemDfVolumeReport.Size)) +} + +type dfSummary struct { + Type string + Total int + Active int + size int64 + reclaimable int64 +} + +func (d *dfSummary) Size() string { + return units.HumanSize(float64(d.size)) +} + +func (d *dfSummary) Reclaimable() string { + percent := int(float64(d.reclaimable)/float64(d.size)) * 100 + return fmt.Sprintf("%s (%d%%)", units.HumanSize(float64(d.reclaimable)), percent) +} diff --git a/cmd/podman/system/migrate.go b/cmd/podman/system/migrate.go new file mode 100644 index 000000000..13aa162c7 --- /dev/null +++ b/cmd/podman/system/migrate.go @@ -0,0 +1,63 @@ +package system + +import ( + "fmt" + "os" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/domain/infra" + "github.com/spf13/cobra" +) + +var ( + migrateDescription = ` + podman system migrate + + Migrate existing containers to a new version of Podman. +` + + migrateCommand = &cobra.Command{ + Use: "migrate", + Args: validate.NoArgs, + Short: "Migrate containers", + Long: migrateDescription, + Run: migrate, + } +) + +var ( + migrateOptions entities.SystemMigrateOptions +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: migrateCommand, + Parent: systemCmd, + }) + + flags := migrateCommand.Flags() + flags.StringVar(&migrateOptions.NewRuntime, "new-runtime", "", "Specify a new runtime for all containers") +} + +func migrate(cmd *cobra.Command, args []string) { + // Shutdown all running engines, `renumber` will hijack repository + registry.ContainerEngine().Shutdown(registry.Context()) + registry.ImageEngine().Shutdown(registry.Context()) + + engine, err := infra.NewSystemEngine(entities.MigrateMode, registry.PodmanConfig()) + if err != nil { + fmt.Println(err) + os.Exit(125) + } + defer engine.Shutdown(registry.Context()) + + err = engine.Migrate(registry.Context(), cmd.Flags(), registry.PodmanConfig(), migrateOptions) + if err != nil { + fmt.Println(err) + os.Exit(125) + } + os.Exit(0) +} diff --git a/cmd/podman/system/renumber.go b/cmd/podman/system/renumber.go new file mode 100644 index 000000000..5ee6b3be6 --- /dev/null +++ b/cmd/podman/system/renumber.go @@ -0,0 +1,57 @@ +package system + +import ( + "fmt" + "os" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/domain/infra" + "github.com/spf13/cobra" +) + +var ( + renumberDescription = ` + podman system renumber + + Migrate lock numbers to handle a change in maximum number of locks. + Mandatory after the number of locks in libpod.conf is changed. +` + + renumberCommand = &cobra.Command{ + Use: "renumber", + Args: validate.NoArgs, + Short: "Migrate lock numbers", + Long: renumberDescription, + Run: renumber, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: renumberCommand, + Parent: systemCmd, + }) + +} +func renumber(cmd *cobra.Command, args []string) { + // Shutdown all running engines, `renumber` will hijack all methods + registry.ContainerEngine().Shutdown(registry.Context()) + registry.ImageEngine().Shutdown(registry.Context()) + + engine, err := infra.NewSystemEngine(entities.RenumberMode, registry.PodmanConfig()) + if err != nil { + fmt.Println(err) + os.Exit(125) + } + defer engine.Shutdown(registry.Context()) + + err = engine.Renumber(registry.Context(), cmd.Flags(), registry.PodmanConfig()) + if err != nil { + fmt.Println(err) + os.Exit(125) + } + os.Exit(0) +} diff --git a/cmd/podman/system/reset.go b/cmd/podman/system/reset.go new file mode 100644 index 000000000..22ddc7529 --- /dev/null +++ b/cmd/podman/system/reset.go @@ -0,0 +1,82 @@ +package system + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/domain/infra" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + systemResetDescription = `Reset podman storage back to default state" + + All containers will be stopped and removed, and all images, volumes and container content will be removed. +` + systemResetCommand = &cobra.Command{ + Use: "reset", + Args: validate.NoArgs, + Short: "Reset podman storage", + Long: systemResetDescription, + Run: reset, + } +) + +var ( + systemResetOptions entities.SystemResetOptions +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: systemResetCommand, + Parent: systemCmd, + }) + flags := systemResetCommand.Flags() + flags.BoolVarP(&systemResetOptions.Force, "force", "f", false, "Do not prompt for confirmation") +} + +func reset(cmd *cobra.Command, args []string) { + // Prompt for confirmation if --force is not set + if !systemResetOptions.Force { + reader := bufio.NewReader(os.Stdin) + fmt.Print(` +WARNING! This will remove: + - all containers + - all pods + - all images + - all build cache +Are you sure you want to continue? [y/N] `) + answer, err := reader.ReadString('\n') + if err != nil { + fmt.Println(errors.Wrapf(err, "error reading input")) + os.Exit(1) + } + if strings.ToLower(answer)[0] != 'y' { + os.Exit(0) + } + } + + // Shutdown all running engines, `reset` will hijack repository + registry.ContainerEngine().Shutdown(registry.Context()) + registry.ImageEngine().Shutdown(registry.Context()) + + engine, err := infra.NewSystemEngine(entities.ResetMode, registry.PodmanConfig()) + if err != nil { + fmt.Println(err) + os.Exit(125) + } + defer engine.Shutdown(registry.Context()) + + if err := engine.Reset(registry.Context(), systemResetOptions); err != nil { + fmt.Println(err) + os.Exit(125) + } + os.Exit(0) +} |