mirror of https://github.com/containers/podman.git
V2 podman command
Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
parent
bd9386ddac
commit
fbe743501e
|
@ -0,0 +1,33 @@
|
|||
package containers
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command: podman _container_
|
||||
containerCmd = &cobra.Command{
|
||||
Use: "container",
|
||||
Short: "Manage containers",
|
||||
Long: "Manage containers",
|
||||
TraverseChildren: true,
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: registry.SubCommandExists,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: containerCmd,
|
||||
})
|
||||
containerCmd.SetHelpTemplate(registry.HelpTemplate())
|
||||
containerCmd.SetUsageTemplate(registry.UsageTemplate())
|
||||
}
|
||||
|
||||
func preRunE(cmd *cobra.Command, args []string) error {
|
||||
_, err := registry.NewContainerEngine(cmd, args)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package containers
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// podman container _inspect_
|
||||
inspectCmd = &cobra.Command{
|
||||
Use: "inspect [flags] CONTAINER",
|
||||
Short: "Display the configuration of a container",
|
||||
Long: `Displays the low-level information on a container identified by name or ID.`,
|
||||
PreRunE: inspectPreRunE,
|
||||
RunE: inspect,
|
||||
Example: `podman container inspect myCtr
|
||||
podman container inspect -l --format '{{.Id}} {{.Config.Labels}}'`,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: inspectCmd,
|
||||
Parent: containerCmd,
|
||||
})
|
||||
}
|
||||
|
||||
func inspectPreRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
err = preRunE(cmd, args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = registry.NewImageEngine(cmd, args)
|
||||
return err
|
||||
}
|
||||
|
||||
func inspect(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package containers
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// podman container _list_
|
||||
listCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Args: cobra.NoArgs,
|
||||
Short: "List containers",
|
||||
Long: "Prints out information about the containers",
|
||||
RunE: containers,
|
||||
Example: `podman container list -a
|
||||
podman container list -a --format "{{.ID}} {{.Image}} {{.Labels}} {{.Mounts}}"
|
||||
podman container list --size --sort names`,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: listCmd,
|
||||
Parent: containerCmd,
|
||||
})
|
||||
}
|
||||
|
||||
func containers(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package containers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// podman _ps_
|
||||
psCmd = &cobra.Command{
|
||||
Use: "ps",
|
||||
Args: cobra.NoArgs,
|
||||
Short: listCmd.Short,
|
||||
Long: listCmd.Long,
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: containers,
|
||||
Example: strings.Replace(listCmd.Example, "container list", "ps", -1),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: psCmd,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/cmd/podmanV2/report"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
long = `Displays the history of an image.
|
||||
|
||||
The information can be printed out in an easy to read, or user specified format, and can be truncated.`
|
||||
|
||||
// podman _history_
|
||||
historyCmd = &cobra.Command{
|
||||
Use: "history [flags] IMAGE",
|
||||
Short: "Show history of a specified image",
|
||||
Long: long,
|
||||
Example: "podman history quay.io/fedora/fedora",
|
||||
Args: cobra.ExactArgs(1),
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: history,
|
||||
}
|
||||
)
|
||||
|
||||
var cmdFlags = struct {
|
||||
Human bool
|
||||
NoTrunc bool
|
||||
Quiet bool
|
||||
Format string
|
||||
}{}
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: historyCmd,
|
||||
})
|
||||
|
||||
historyCmd.SetHelpTemplate(registry.HelpTemplate())
|
||||
historyCmd.SetUsageTemplate(registry.UsageTemplate())
|
||||
flags := historyCmd.Flags()
|
||||
flags.StringVar(&cmdFlags.Format, "format", "", "Change the output to JSON or a Go template")
|
||||
flags.BoolVarP(&cmdFlags.Human, "human", "H", true, "Display sizes and dates in human readable format")
|
||||
flags.BoolVar(&cmdFlags.NoTrunc, "no-trunc", false, "Do not truncate the output")
|
||||
flags.BoolVar(&cmdFlags.NoTrunc, "notruncate", false, "Do not truncate the output")
|
||||
flags.BoolVarP(&cmdFlags.Quiet, "quiet", "q", false, "Display the numeric IDs only")
|
||||
}
|
||||
|
||||
func history(cmd *cobra.Command, args []string) error {
|
||||
results, err := registry.ImageEngine().History(context.Background(), args[0], entities.ImageHistoryOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
row := "{{slice $x.ID 0 12}}\t{{toRFC3339 $x.Created}}\t{{ellipsis $x.CreatedBy 45}}\t{{$x.Size}}\t{{$x.Comment}}\n"
|
||||
if cmdFlags.Human {
|
||||
row = "{{slice $x.ID 0 12}}\t{{toHumanDuration $x.Created}}\t{{ellipsis $x.CreatedBy 45}}\t{{toHumanSize $x.Size}}\t{{$x.Comment}}\n"
|
||||
}
|
||||
format := "{{range $y, $x := . }}" + row + "{{end}}"
|
||||
|
||||
tmpl := template.Must(template.New("report").Funcs(report.PodmanTemplateFuncs()).Parse(format))
|
||||
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
|
||||
|
||||
_, _ = w.Write(report.ReportHeader("id", "created", "created by", "size", "comment"))
|
||||
err = tmpl.Execute(w, results.Layers)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "Failed to print report"))
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command: podman _image_
|
||||
imageCmd = &cobra.Command{
|
||||
Use: "image",
|
||||
Short: "Manage images",
|
||||
Long: "Manage images",
|
||||
TraverseChildren: true,
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: registry.SubCommandExists,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: imageCmd,
|
||||
})
|
||||
imageCmd.SetHelpTemplate(registry.HelpTemplate())
|
||||
imageCmd.SetUsageTemplate(registry.UsageTemplate())
|
||||
}
|
||||
|
||||
func preRunE(cmd *cobra.Command, args []string) error {
|
||||
_, err := registry.NewImageEngine(cmd, args)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// podman _images_
|
||||
imagesCmd = &cobra.Command{
|
||||
Use: strings.Replace(listCmd.Use, "list", "images", 1),
|
||||
Short: listCmd.Short,
|
||||
Long: listCmd.Long,
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: images,
|
||||
Example: strings.Replace(listCmd.Example, "podman image list", "podman images", -1),
|
||||
}
|
||||
|
||||
imagesOpts = entities.ImageListOptions{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: imagesCmd,
|
||||
})
|
||||
imagesCmd.SetHelpTemplate(registry.HelpTemplate())
|
||||
imagesCmd.SetUsageTemplate(registry.UsageTemplate())
|
||||
|
||||
flags := imagesCmd.Flags()
|
||||
flags.BoolVarP(&imagesOpts.All, "all", "a", false, "Show all images (default hides intermediate images)")
|
||||
flags.BoolVar(&imagesOpts.Digests, "digests", false, "Show digests")
|
||||
flags.StringSliceVarP(&imagesOpts.Filter, "filter", "f", []string{}, "Filter output based on conditions provided (default [])")
|
||||
flags.StringVar(&imagesOpts.Format, "format", "", "Change the output format to JSON or a Go template")
|
||||
flags.BoolVarP(&imagesOpts.Noheading, "noheading", "n", false, "Do not print column headings")
|
||||
// TODO Need to learn how to deal with second name being a string instead of a char.
|
||||
// This needs to be "no-trunc, notruncate"
|
||||
flags.BoolVar(&imagesOpts.NoTrunc, "no-trunc", false, "Do not truncate output")
|
||||
flags.BoolVar(&imagesOpts.NoTrunc, "notruncate", false, "Do not truncate output")
|
||||
flags.BoolVarP(&imagesOpts.Quiet, "quiet", "q", false, "Display only image IDs")
|
||||
flags.StringVar(&imagesOpts.Sort, "sort", "created", "Sort by created, id, repository, size, or tag")
|
||||
flags.BoolVarP(&imagesOpts.History, "history", "", false, "Display the image name history")
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/buildah/pkg/formats"
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
inspectOpts = entities.ImageInspectOptions{}
|
||||
|
||||
// Command: podman image _inspect_
|
||||
inspectCmd = &cobra.Command{
|
||||
Use: "inspect [flags] IMAGE",
|
||||
Short: "Display the configuration of an image",
|
||||
Long: `Displays the low-level information on an image identified by name or ID.`,
|
||||
PreRunE: populateEngines,
|
||||
RunE: imageInspect,
|
||||
Example: `podman image inspect alpine`,
|
||||
}
|
||||
|
||||
containerEngine entities.ContainerEngine
|
||||
)
|
||||
|
||||
// Inspect is unique in that it needs both an ImageEngine and a ContainerEngine
|
||||
func populateEngines(cmd *cobra.Command, args []string) (err error) {
|
||||
// Populate registry.ImageEngine
|
||||
err = preRunE(cmd, args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Populate registry.ContainerEngine
|
||||
containerEngine, err = registry.NewContainerEngine(cmd, args)
|
||||
return
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: inspectCmd,
|
||||
Parent: imageCmd,
|
||||
})
|
||||
|
||||
flags := inspectCmd.Flags()
|
||||
flags.BoolVarP(&inspectOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
|
||||
flags.BoolVarP(&inspectOpts.Size, "size", "s", false, "Display total file size")
|
||||
flags.StringVarP(&inspectOpts.Format, "format", "f", "", "Change the output format to a Go template")
|
||||
|
||||
if registry.GlobalFlags.EngineMode == entities.ABIMode {
|
||||
// TODO: This is the same as V1. We could skip creating the flag altogether in V2...
|
||||
_ = flags.MarkHidden("latest")
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
inspectTypeContainer = "container"
|
||||
inspectTypeImage = "image"
|
||||
inspectAll = "all"
|
||||
)
|
||||
|
||||
func imageInspect(cmd *cobra.Command, args []string) error {
|
||||
inspectType := inspectTypeImage
|
||||
latestContainer := inspectOpts.Latest
|
||||
|
||||
if len(args) == 0 && !latestContainer {
|
||||
return errors.Errorf("container or image name must be specified: podman inspect [options [...]] name")
|
||||
}
|
||||
|
||||
if len(args) > 0 && latestContainer {
|
||||
return errors.Errorf("you cannot provide additional arguments with --latest")
|
||||
}
|
||||
|
||||
if !util.StringInSlice(inspectType, []string{inspectTypeContainer, inspectTypeImage, inspectAll}) {
|
||||
return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll)
|
||||
}
|
||||
|
||||
outputFormat := inspectOpts.Format
|
||||
if strings.Contains(outputFormat, "{{.Id}}") {
|
||||
outputFormat = strings.Replace(outputFormat, "{{.Id}}", formats.IDString, -1)
|
||||
}
|
||||
// These fields were renamed, so we need to provide backward compat for
|
||||
// the old names.
|
||||
if strings.Contains(outputFormat, ".Src") {
|
||||
outputFormat = strings.Replace(outputFormat, ".Src", ".Source", -1)
|
||||
}
|
||||
if strings.Contains(outputFormat, ".Dst") {
|
||||
outputFormat = strings.Replace(outputFormat, ".Dst", ".Destination", -1)
|
||||
}
|
||||
if strings.Contains(outputFormat, ".ImageID") {
|
||||
outputFormat = strings.Replace(outputFormat, ".ImageID", ".Image", -1)
|
||||
}
|
||||
_ = outputFormat
|
||||
// if latestContainer {
|
||||
// lc, err := ctnrRuntime.GetLatestContainer()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// args = append(args, lc.ID())
|
||||
// inspectType = inspectTypeContainer
|
||||
// }
|
||||
|
||||
// inspectedObjects, iterateErr := iterateInput(getContext(), c.Size, args, runtime, inspectType)
|
||||
// if iterateErr != nil {
|
||||
// return iterateErr
|
||||
// }
|
||||
//
|
||||
// var out formats.Writer
|
||||
// if outputFormat != "" && outputFormat != formats.JSONString {
|
||||
// // template
|
||||
// out = formats.StdoutTemplateArray{Output: inspectedObjects, Template: outputFormat}
|
||||
// } else {
|
||||
// // default is json output
|
||||
// out = formats.JSONStructArray{Output: inspectedObjects}
|
||||
// }
|
||||
//
|
||||
// return out.Out()
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command: podman image _list_
|
||||
listCmd = &cobra.Command{
|
||||
Use: "list [flag] [IMAGE]",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List images in local storage",
|
||||
Long: "Lists images previously pulled to the system or created on the system.",
|
||||
RunE: images,
|
||||
Example: `podman image list --format json
|
||||
podman image list --sort repository --format "table {{.ID}} {{.Repository}} {{.Tag}}"
|
||||
podman image list --filter dangling=true`,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: listCmd,
|
||||
Parent: imageCmd,
|
||||
})
|
||||
}
|
||||
|
||||
func images(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
_ "github.com/containers/libpod/cmd/podmanV2/containers"
|
||||
_ "github.com/containers/libpod/cmd/podmanV2/images"
|
||||
_ "github.com/containers/libpod/cmd/podmanV2/networks"
|
||||
_ "github.com/containers/libpod/cmd/podmanV2/pods"
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
_ "github.com/containers/libpod/cmd/podmanV2/volumes"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := libpod.SetXdgDirs(); err != nil {
|
||||
logrus.Errorf(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
initCobra()
|
||||
}
|
||||
|
||||
func initCobra() {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
fallthrough
|
||||
case "windows":
|
||||
registry.GlobalFlags.EngineMode = entities.TunnelMode
|
||||
case "linux":
|
||||
registry.GlobalFlags.EngineMode = entities.ABIMode
|
||||
default:
|
||||
logrus.Errorf("%s is not a supported OS", runtime.GOOS)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// TODO: Is there a Cobra way to "peek" at os.Args?
|
||||
if ok := Contains("--remote", os.Args); ok {
|
||||
registry.GlobalFlags.EngineMode = entities.TunnelMode
|
||||
}
|
||||
|
||||
cobra.OnInitialize(func() {})
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Fprintf(os.Stderr, "Number of commands: %d\n", len(registry.Commands))
|
||||
for _, c := range registry.Commands {
|
||||
if Contains(registry.GlobalFlags.EngineMode, c.Mode) {
|
||||
parent := rootCmd
|
||||
if c.Parent != nil {
|
||||
parent = c.Parent
|
||||
}
|
||||
parent.AddCommand(c.Command)
|
||||
}
|
||||
}
|
||||
|
||||
Execute()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func Contains(item interface{}, slice interface{}) bool {
|
||||
s := reflect.ValueOf(slice)
|
||||
|
||||
switch s.Kind() {
|
||||
case reflect.Array:
|
||||
fallthrough
|
||||
case reflect.Slice:
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
if s.Index(i).Interface() == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command: podman _network_
|
||||
cmd = &cobra.Command{
|
||||
Use: "network",
|
||||
Short: "Manage networks",
|
||||
Long: "Manage networks",
|
||||
TraverseChildren: true,
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: registry.SubCommandExists,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode},
|
||||
Command: cmd,
|
||||
})
|
||||
cmd.SetHelpTemplate(registry.HelpTemplate())
|
||||
cmd.SetUsageTemplate(registry.UsageTemplate())
|
||||
}
|
||||
|
||||
func preRunE(cmd *cobra.Command, args []string) error {
|
||||
_, err := registry.NewContainerEngine(cmd, args)
|
||||
return err
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
package pods
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command: podman _pod_
|
||||
podCmd = &cobra.Command{
|
||||
Use: "pod",
|
||||
Short: "Manage pods",
|
||||
Long: "Manage pods",
|
||||
TraverseChildren: true,
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: registry.SubCommandExists,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: podCmd,
|
||||
})
|
||||
podCmd.SetHelpTemplate(registry.HelpTemplate())
|
||||
podCmd.SetUsageTemplate(registry.UsageTemplate())
|
||||
}
|
||||
|
||||
func preRunE(cmd *cobra.Command, args []string) error {
|
||||
_, err := registry.NewContainerEngine(cmd, args)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package pods
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
psDescription = "List all pods on system including their names, ids and current state."
|
||||
|
||||
// Command: podman pod _ps_
|
||||
psCmd = &cobra.Command{
|
||||
Use: "ps",
|
||||
Aliases: []string{"ls", "list"},
|
||||
Short: "list pods",
|
||||
Long: psDescription,
|
||||
RunE: pods,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: psCmd,
|
||||
Parent: podCmd,
|
||||
})
|
||||
}
|
||||
|
||||
func pods(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/domain/infra"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type CliCommand struct {
|
||||
Mode []entities.EngineMode
|
||||
Command *cobra.Command
|
||||
Parent *cobra.Command
|
||||
}
|
||||
|
||||
var (
|
||||
Commands []CliCommand
|
||||
GlobalFlags entities.EngineFlags
|
||||
imageEngine entities.ImageEngine
|
||||
containerEngine entities.ContainerEngine
|
||||
PodmanTunnel bool
|
||||
)
|
||||
|
||||
// HelpTemplate returns the help template for podman commands
|
||||
// This uses the short and long options.
|
||||
// command should not use this.
|
||||
func HelpTemplate() string {
|
||||
return `{{.Short}}
|
||||
|
||||
Description:
|
||||
{{.Long}}
|
||||
|
||||
{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||
}
|
||||
|
||||
// UsageTemplate returns the usage template for podman commands
|
||||
// This blocks the displaying of the global options. The main podman
|
||||
// command should not use this.
|
||||
func UsageTemplate() string {
|
||||
return `Usage(v2):{{if (and .Runnable (not .HasAvailableSubCommands))}}
|
||||
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
|
||||
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
|
||||
|
||||
Aliases:
|
||||
{{.NameAndAliases}}{{end}}{{if .HasExample}}
|
||||
|
||||
Examples:
|
||||
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}
|
||||
|
||||
Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
|
||||
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
|
||||
|
||||
Flags:
|
||||
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
|
||||
{{end}}
|
||||
`
|
||||
}
|
||||
|
||||
func ImageEngine() entities.ImageEngine {
|
||||
return imageEngine
|
||||
}
|
||||
|
||||
// NewImageEngine is a wrapper for building an ImageEngine to be used for PreRunE functions
|
||||
func NewImageEngine(cmd *cobra.Command, args []string) (entities.ImageEngine, error) {
|
||||
if imageEngine == nil {
|
||||
engine, err := infra.NewImageEngine(GlobalFlags.EngineMode, entities.EngineOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imageEngine = engine
|
||||
}
|
||||
return imageEngine, nil
|
||||
}
|
||||
|
||||
func ContainerEngine() entities.ContainerEngine {
|
||||
return containerEngine
|
||||
}
|
||||
|
||||
// NewContainerEngine is a wrapper for building an ContainerEngine to be used for PreRunE functions
|
||||
func NewContainerEngine(cmd *cobra.Command, args []string) (entities.ContainerEngine, error) {
|
||||
if containerEngine == nil {
|
||||
engine, err := infra.NewContainerEngine(GlobalFlags.EngineMode, entities.EngineOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containerEngine = engine
|
||||
}
|
||||
return containerEngine, nil
|
||||
}
|
||||
|
||||
func SubCommandExists(cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 0 {
|
||||
return errors.Errorf("unrecognized command `%[1]s %[2]s`\nTry '%[1]s --help' for more information.", cmd.CommandPath(), args[0])
|
||||
}
|
||||
return errors.Errorf("missing command '%[1]s COMMAND'\nTry '%[1]s --help' for more information.", cmd.CommandPath())
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package report
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
var defaultFuncMap = template.FuncMap{
|
||||
"ellipsis": func(s string, length int) string {
|
||||
if len(s) > length {
|
||||
return s[:length-3] + "..."
|
||||
}
|
||||
return s
|
||||
},
|
||||
// TODO: Remove on Go 1.14 port
|
||||
"slice": func(s string, i, j int) string {
|
||||
if i > j || len(s) < i {
|
||||
return s
|
||||
}
|
||||
if len(s) < j {
|
||||
return s[i:]
|
||||
}
|
||||
return s[i:j]
|
||||
},
|
||||
"toRFC3339": func(t int64) string {
|
||||
return time.Unix(t, 0).Format(time.RFC3339)
|
||||
},
|
||||
"toHumanDuration": func(t int64) string {
|
||||
return units.HumanDuration(time.Since(time.Unix(t, 0))) + " ago"
|
||||
},
|
||||
"toHumanSize": func(sz int64) string {
|
||||
return units.HumanSize(float64(sz))
|
||||
},
|
||||
}
|
||||
|
||||
func ReportHeader(columns ...string) []byte {
|
||||
hdr := make([]string, len(columns))
|
||||
for i, h := range columns {
|
||||
hdr[i] = strings.ToUpper(h)
|
||||
}
|
||||
return []byte(strings.Join(hdr, "\t") + "\n")
|
||||
}
|
||||
|
||||
func AppendFuncMap(funcMap template.FuncMap) template.FuncMap {
|
||||
merged := PodmanTemplateFuncs()
|
||||
for k, v := range funcMap {
|
||||
merged[k] = v
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
func PodmanTemplateFuncs() template.FuncMap {
|
||||
merged := make(template.FuncMap)
|
||||
for k, v := range defaultFuncMap {
|
||||
merged[k] = v
|
||||
}
|
||||
return merged
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/version"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: path.Base(os.Args[0]),
|
||||
Long: "Manage pods, containers and images",
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
TraverseChildren: true,
|
||||
RunE: registry.SubCommandExists,
|
||||
Version: version.Version,
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Override default --help information of `--version` global flag}
|
||||
var dummyVersion bool
|
||||
rootCmd.PersistentFlags().BoolVarP(&dummyVersion, "version", "v", false, "Version of podman")
|
||||
rootCmd.PersistentFlags().BoolVarP(®istry.PodmanTunnel, "remote", "r", false, "Access service via SSH tunnel")
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command: podman _system_
|
||||
cmd = &cobra.Command{
|
||||
Use: "system",
|
||||
Short: "Manage podman",
|
||||
Long: "Manage podman",
|
||||
TraverseChildren: true,
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: registry.SubCommandExists,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: cmd,
|
||||
})
|
||||
cmd.SetHelpTemplate(registry.HelpTemplate())
|
||||
cmd.SetUsageTemplate(registry.UsageTemplate())
|
||||
}
|
||||
|
||||
func preRunE(cmd *cobra.Command, args []string) error {
|
||||
_, err := registry.NewContainerEngine(cmd, args)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package images
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Command: podman _volume_
|
||||
cmd = &cobra.Command{
|
||||
Use: "volume",
|
||||
Short: "Manage volumes",
|
||||
Long: "Volumes are created in and can be shared between containers",
|
||||
TraverseChildren: true,
|
||||
PersistentPreRunE: preRunE,
|
||||
RunE: registry.SubCommandExists,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: cmd,
|
||||
})
|
||||
cmd.SetHelpTemplate(registry.HelpTemplate())
|
||||
cmd.SetUsageTemplate(registry.UsageTemplate())
|
||||
}
|
||||
|
||||
func preRunE(cmd *cobra.Command, args []string) error {
|
||||
_, err := registry.NewContainerEngine(cmd, args)
|
||||
return err
|
||||
}
|
|
@ -28,7 +28,7 @@ func HistoryImage(w http.ResponseWriter, r *http.Request) {
|
|||
for _, h := range history {
|
||||
l := handlers.HistoryResponse{
|
||||
ID: h.ID,
|
||||
Created: h.Created.UnixNano(),
|
||||
Created: h.Created.Unix(),
|
||||
CreatedBy: h.CreatedBy,
|
||||
Tags: h.Tags,
|
||||
Size: h.Size,
|
||||
|
|
|
@ -109,7 +109,7 @@ func NewConnection(ctx context.Context, uri string, identity ...string) (context
|
|||
}
|
||||
client, err = tcpClient(_url)
|
||||
default:
|
||||
return nil, errors.Errorf("%s is not a support schema", _url.Scheme)
|
||||
return nil, errors.Errorf("'%s' is not a supported schema", _url.Scheme)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to create %sClient", _url.Scheme)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
package entities
|
|
@ -0,0 +1,97 @@
|
|||
package entities
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
type EngineMode string
|
||||
|
||||
const (
|
||||
ABIMode = EngineMode("abi")
|
||||
TunnelMode = EngineMode("tunnel")
|
||||
)
|
||||
|
||||
func (m EngineMode) String() string {
|
||||
return string(m)
|
||||
}
|
||||
|
||||
type EngineOptions struct {
|
||||
Uri *url.URL
|
||||
Identities []string
|
||||
FlagSet pflag.FlagSet
|
||||
Flags EngineFlags
|
||||
}
|
||||
|
||||
type EngineFlags struct {
|
||||
CGroupManager string
|
||||
CniConfigDir string
|
||||
ConmonPath string
|
||||
DefaultMountsFile string
|
||||
EventsBackend string
|
||||
HooksDir []string
|
||||
MaxWorks int
|
||||
Namespace string
|
||||
Root string
|
||||
Runroot string
|
||||
Runtime string
|
||||
StorageDriver string
|
||||
StorageOpts []string
|
||||
Syslog bool
|
||||
Trace bool
|
||||
NetworkCmdPath string
|
||||
|
||||
Config string
|
||||
CpuProfile string
|
||||
LogLevel string
|
||||
TmpDir string
|
||||
|
||||
RemoteUserName string
|
||||
RemoteHost string
|
||||
VarlinkAddress string
|
||||
ConnectionName string
|
||||
RemoteConfigFilePath string
|
||||
Port int
|
||||
IdentityFile string
|
||||
IgnoreHosts bool
|
||||
|
||||
EngineMode EngineMode
|
||||
}
|
||||
|
||||
func NewEngineOptions() (EngineFlags, error) {
|
||||
u, _ := user.Current()
|
||||
return EngineFlags{
|
||||
CGroupManager: define.SystemdCgroupsManager,
|
||||
CniConfigDir: "",
|
||||
Config: "",
|
||||
ConmonPath: filepath.Join("usr", "bin", "conmon"),
|
||||
ConnectionName: "",
|
||||
CpuProfile: "",
|
||||
DefaultMountsFile: "",
|
||||
EventsBackend: "",
|
||||
HooksDir: nil,
|
||||
IdentityFile: "",
|
||||
IgnoreHosts: false,
|
||||
LogLevel: "",
|
||||
MaxWorks: 0,
|
||||
Namespace: "",
|
||||
NetworkCmdPath: "",
|
||||
Port: 0,
|
||||
RemoteConfigFilePath: "",
|
||||
RemoteHost: "",
|
||||
RemoteUserName: "",
|
||||
Root: "",
|
||||
Runroot: filepath.Join("run", "user", u.Uid),
|
||||
Runtime: "",
|
||||
StorageDriver: "overlayfs",
|
||||
StorageOpts: nil,
|
||||
Syslog: false,
|
||||
TmpDir: filepath.Join("run", "user", u.Uid, "libpod", "tmp"),
|
||||
Trace: false,
|
||||
VarlinkAddress: "",
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package entities
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type ContainerEngine interface {
|
||||
ContainerRuntime
|
||||
PodRuntime
|
||||
VolumeRuntime
|
||||
}
|
||||
|
||||
type ContainerRuntime interface {
|
||||
ContainerDelete(ctx context.Context, opts ContainerDeleteOptions) (*ContainerDeleteReport, error)
|
||||
ContainerPrune(ctx context.Context) (*ContainerPruneReport, error)
|
||||
}
|
||||
|
||||
type PodRuntime interface {
|
||||
PodDelete(ctx context.Context, opts PodPruneOptions) (*PodDeleteReport, error)
|
||||
PodPrune(ctx context.Context) (*PodPruneReport, error)
|
||||
}
|
||||
|
||||
type VolumeRuntime interface {
|
||||
VolumeDelete(ctx context.Context, opts VolumeDeleteOptions) (*VolumeDeleteReport, error)
|
||||
VolumePrune(ctx context.Context) (*VolumePruneReport, error)
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package entities
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type ImageEngine interface {
|
||||
Delete(ctx context.Context, nameOrId string, opts ImageDeleteOptions) (*ImageDeleteReport, error)
|
||||
History(ctx context.Context, nameOrId string, opts ImageHistoryOptions) (*ImageHistoryReport, error)
|
||||
List(ctx context.Context, opts ImageListOptions) (*ImageListReport, error)
|
||||
Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
package entities
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Identifier interface allows filters to access ID() of object
|
||||
type Identifier interface {
|
||||
Id() string
|
||||
}
|
||||
|
||||
// Named interface allows filters to access Name() of object
|
||||
type Named interface {
|
||||
Name() string
|
||||
}
|
||||
|
||||
// Named interface allows filters to access Name() of object
|
||||
type Names interface {
|
||||
Names() []string
|
||||
}
|
||||
|
||||
// IdOrName interface allows filters to access ID() or Name() of object
|
||||
type IdOrNamed interface {
|
||||
Identifier
|
||||
Named
|
||||
}
|
||||
|
||||
// IdOrName interface allows filters to access ID() or Names() of object
|
||||
type IdOrNames interface {
|
||||
Identifier
|
||||
Names
|
||||
}
|
||||
|
||||
type ImageFilter func(Image) bool
|
||||
type VolumeFilter func(Volume) bool
|
||||
type ContainerFilter func(Container) bool
|
||||
|
||||
func CompileImageFilters(filters url.Values) ImageFilter {
|
||||
var fns []interface{}
|
||||
|
||||
for name, targets := range filters {
|
||||
switch name {
|
||||
case "id":
|
||||
fns = append(fns, FilterIdFn(targets))
|
||||
case "name":
|
||||
fns = append(fns, FilterNamesFn(targets))
|
||||
case "idOrName":
|
||||
fns = append(fns, FilterIdOrNameFn(targets))
|
||||
}
|
||||
}
|
||||
|
||||
return func(image Image) bool {
|
||||
for _, fn := range fns {
|
||||
if !fn.(ImageFilter)(image) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func CompileContainerFilters(filters url.Values) ContainerFilter {
|
||||
var fns []interface{}
|
||||
|
||||
for name, targets := range filters {
|
||||
switch name {
|
||||
case "id":
|
||||
fns = append(fns, FilterIdFn(targets))
|
||||
case "name":
|
||||
fns = append(fns, FilterNameFn(targets))
|
||||
case "idOrName":
|
||||
fns = append(fns, FilterIdOrNameFn(targets))
|
||||
}
|
||||
}
|
||||
|
||||
return func(ctnr Container) bool {
|
||||
for _, fn := range fns {
|
||||
if !fn.(ContainerFilter)(ctnr) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func CompileVolumeFilters(filters url.Values) VolumeFilter {
|
||||
var fns []interface{}
|
||||
|
||||
for name, targets := range filters {
|
||||
if name == "id" {
|
||||
fns = append(fns, FilterIdFn(targets))
|
||||
}
|
||||
}
|
||||
|
||||
return func(volume Volume) bool {
|
||||
for _, fn := range fns {
|
||||
if !fn.(VolumeFilter)(volume) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func FilterIdFn(id []string) func(Identifier) bool {
|
||||
return func(obj Identifier) bool {
|
||||
for _, v := range id {
|
||||
if strings.Contains(obj.Id(), v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func FilterNameFn(name []string) func(Named) bool {
|
||||
return func(obj Named) bool {
|
||||
for _, v := range name {
|
||||
if strings.Contains(obj.Name(), v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func FilterNamesFn(name []string) func(Names) bool {
|
||||
return func(obj Names) bool {
|
||||
for _, v := range name {
|
||||
for _, n := range obj.Names() {
|
||||
if strings.Contains(n, v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func FilterIdOrNameFn(id []string) func(IdOrNamed) bool {
|
||||
return func(obj IdOrNamed) bool {
|
||||
for _, v := range id {
|
||||
if strings.Contains(obj.Id(), v) || strings.Contains(obj.Name(), v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package entities
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/containers/image/v5/manifest"
|
||||
docker "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/opencontainers/go-digest"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
IdOrNamed
|
||||
ID string `json:"Id"`
|
||||
RepoTags []string `json:",omitempty"`
|
||||
RepoDigests []string `json:",omitempty"`
|
||||
Parent string `json:",omitempty"`
|
||||
Comment string `json:",omitempty"`
|
||||
Created string `json:",omitempty"`
|
||||
Container string `json:",omitempty"`
|
||||
ContainerConfig *container.Config `json:",omitempty"`
|
||||
DockerVersion string `json:",omitempty"`
|
||||
Author string `json:",omitempty"`
|
||||
Config *container.Config `json:",omitempty"`
|
||||
Architecture string `json:",omitempty"`
|
||||
Variant string `json:",omitempty"`
|
||||
Os string `json:",omitempty"`
|
||||
OsVersion string `json:",omitempty"`
|
||||
Size int64 `json:",omitempty"`
|
||||
VirtualSize int64 `json:",omitempty"`
|
||||
GraphDriver docker.GraphDriverData `json:",omitempty"`
|
||||
RootFS docker.RootFS `json:",omitempty"`
|
||||
Metadata docker.ImageMetadata `json:",omitempty"`
|
||||
|
||||
// Podman extensions
|
||||
Digest digest.Digest `json:",omitempty"`
|
||||
PodmanVersion string `json:",omitempty"`
|
||||
ManifestType string `json:",omitempty"`
|
||||
User string `json:",omitempty"`
|
||||
History []v1.History `json:",omitempty"`
|
||||
NamesHistory []string `json:",omitempty"`
|
||||
HealthCheck *manifest.Schema2HealthConfig `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (i *Image) Id() string {
|
||||
return i.ID
|
||||
}
|
||||
|
||||
type ImageSummary struct {
|
||||
Identifier
|
||||
ID string `json:"Id"`
|
||||
ParentId string `json:",omitempty"`
|
||||
RepoTags []string `json:",omitempty"`
|
||||
Created int `json:",omitempty"`
|
||||
Size int `json:",omitempty"`
|
||||
SharedSize int `json:",omitempty"`
|
||||
VirtualSize int `json:",omitempty"`
|
||||
Labels string `json:",omitempty"`
|
||||
Containers int `json:",omitempty"`
|
||||
ReadOnly bool `json:",omitempty"`
|
||||
Dangling bool `json:",omitempty"`
|
||||
|
||||
// Podman extensions
|
||||
Digest digest.Digest `json:",omitempty"`
|
||||
ConfigDigest digest.Digest `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (i *ImageSummary) Id() string {
|
||||
return i.ID
|
||||
}
|
||||
|
||||
func (i *ImageSummary) IsReadOnly() bool {
|
||||
return i.ReadOnly
|
||||
}
|
||||
|
||||
func (i *ImageSummary) IsDangling() bool {
|
||||
return i.Dangling
|
||||
}
|
||||
|
||||
type ImageOptions struct {
|
||||
All bool
|
||||
Digests bool
|
||||
Filter []string
|
||||
Format string
|
||||
Noheading bool
|
||||
NoTrunc bool
|
||||
Quiet bool
|
||||
Sort string
|
||||
History bool
|
||||
}
|
||||
|
||||
type ImageDeleteOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
||||
// ImageDeleteResponse is the response for removing an image from storage and containers
|
||||
// what was untagged vs actually removed
|
||||
type ImageDeleteReport struct {
|
||||
Untagged []string `json:"untagged"`
|
||||
Deleted string `json:"deleted"`
|
||||
}
|
||||
|
||||
type ImageHistoryOptions struct{}
|
||||
|
||||
type ImageHistoryLayer struct {
|
||||
ID string `json:"Id"`
|
||||
Created int64 `json:"Created,omitempty"`
|
||||
CreatedBy string `json:",omitempty"`
|
||||
Tags []string `json:",omitempty"`
|
||||
Size int64 `json:",omitempty"`
|
||||
Comment string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ImageHistoryReport struct {
|
||||
Layers []ImageHistoryLayer
|
||||
}
|
||||
|
||||
type ImageInspectOptions struct {
|
||||
TypeObject string `json:",omitempty"`
|
||||
Format string `json:",omitempty"`
|
||||
Size bool `json:",omitempty"`
|
||||
Latest bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ImageListOptions struct {
|
||||
All bool `json:"all" schema:"all"`
|
||||
Digests bool `json:"digests" schema:"digests"`
|
||||
Filter []string `json:",omitempty"`
|
||||
Filters url.Values `json:"filters" schema:"filters"`
|
||||
Format string `json:",omitempty"`
|
||||
History bool `json:",omitempty"`
|
||||
Noheading bool `json:",omitempty"`
|
||||
NoTrunc bool `json:",omitempty"`
|
||||
Quiet bool `json:",omitempty"`
|
||||
Sort string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ImageListReport struct {
|
||||
Images []ImageSummary
|
||||
}
|
||||
|
||||
type ImagePruneOptions struct {
|
||||
All bool
|
||||
Filter ImageFilter
|
||||
}
|
||||
|
||||
type ImagePruneReport struct {
|
||||
Report Report
|
||||
Size int64
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package entities
|
||||
|
||||
type Container struct {
|
||||
IdOrNamed
|
||||
}
|
||||
|
||||
type Volume struct {
|
||||
Identifier
|
||||
}
|
||||
|
||||
type Report struct {
|
||||
Id []string
|
||||
Err map[string]error
|
||||
}
|
||||
|
||||
type ContainerDeleteOptions struct{}
|
||||
type ContainerDeleteReport struct{ Report }
|
||||
type ContainerPruneReport struct{ Report }
|
||||
|
||||
type PodDeleteReport struct{ Report }
|
||||
type PodPruneOptions struct{}
|
||||
type PodPruneReport struct{ Report }
|
||||
type VolumeDeleteOptions struct{}
|
||||
type VolumeDeleteReport struct{ Report }
|
||||
type VolumePruneReport struct{ Report }
|
|
@ -0,0 +1,131 @@
|
|||
// +build ABISupport
|
||||
|
||||
package abi
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
libpodImage "github.com/containers/libpod/libpod/image"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/domain/utils"
|
||||
)
|
||||
|
||||
func (ir *ImageEngine) Delete(ctx context.Context, nameOrId string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
|
||||
image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results, err := ir.Libpod.RemoveImage(ctx, image, opts.Force)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := entities.ImageDeleteReport{}
|
||||
if err := utils.DeepCopy(&report, results); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &report, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
|
||||
results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, []string{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := entities.ImagePruneReport{}
|
||||
copy(report.Report.Id, results)
|
||||
return &report, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) (*entities.ImageListReport, error) {
|
||||
var (
|
||||
images []*libpodImage.Image
|
||||
err error
|
||||
)
|
||||
|
||||
filters := utils.ToLibpodFilters(opts.Filters)
|
||||
if len(filters) > 0 {
|
||||
images, err = ir.Libpod.ImageRuntime().GetImagesWithFilters(filters)
|
||||
} else {
|
||||
images, err = ir.Libpod.ImageRuntime().GetImages()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := entities.ImageListReport{
|
||||
Images: make([]entities.ImageSummary, len(images)),
|
||||
}
|
||||
for i, img := range images {
|
||||
hold := entities.ImageSummary{}
|
||||
if err := utils.DeepCopy(&hold, img); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
report.Images[i] = hold
|
||||
}
|
||||
return &report, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
|
||||
image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results, err := image.History(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
history := entities.ImageHistoryReport{
|
||||
Layers: make([]entities.ImageHistoryLayer, len(results)),
|
||||
}
|
||||
|
||||
for i, layer := range results {
|
||||
history.Layers[i] = ToDomainHistoryLayer(layer)
|
||||
}
|
||||
return &history, nil
|
||||
}
|
||||
|
||||
func ToDomainHistoryLayer(layer *libpodImage.History) entities.ImageHistoryLayer {
|
||||
l := entities.ImageHistoryLayer{}
|
||||
l.ID = layer.ID
|
||||
l.Created = layer.Created.Unix()
|
||||
l.CreatedBy = layer.CreatedBy
|
||||
copy(l.Tags, layer.Tags)
|
||||
l.Size = layer.Size
|
||||
l.Comment = layer.Comment
|
||||
return l
|
||||
}
|
||||
|
||||
// func (r *imageRuntime) Delete(ctx context.Context, nameOrId string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
|
||||
// image, err := r.libpod.ImageEngine().NewFromLocal(nameOrId)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// results, err := r.libpod.RemoveImage(ctx, image, opts.Force)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// report := entities.ImageDeleteReport{}
|
||||
// if err := utils.DeepCopy(&report, results); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return &report, nil
|
||||
// }
|
||||
//
|
||||
// func (r *imageRuntime) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
|
||||
// // TODO: map FilterOptions
|
||||
// id, err := r.libpod.ImageEngine().PruneImages(ctx, opts.All, []string{})
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// // TODO: Determine Size
|
||||
// report := entities.ImagePruneReport{}
|
||||
// copy(report.Report.Id, id)
|
||||
// return &report, nil
|
||||
// }
|
|
@ -0,0 +1,37 @@
|
|||
package abi
|
||||
|
||||
//
|
||||
// import (
|
||||
// "context"
|
||||
// "testing"
|
||||
//
|
||||
// "github.com/stretchr/testify/mock"
|
||||
// )
|
||||
//
|
||||
// type MockImageRuntime struct {
|
||||
// mock.Mock
|
||||
// }
|
||||
//
|
||||
// func (m *MockImageRuntime) Delete(ctx context.Context, renderer func() interface{}, name string) error {
|
||||
// _ = m.Called(ctx, renderer, name)
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// func TestImageSuccess(t *testing.T) {
|
||||
// actual := func() interface{} { return nil }
|
||||
//
|
||||
// m := new(MockImageRuntime)
|
||||
// m.On(
|
||||
// "Delete",
|
||||
// mock.AnythingOfType("*context.emptyCtx"),
|
||||
// mock.AnythingOfType("func() interface {}"),
|
||||
// "fedora").
|
||||
// Return(nil)
|
||||
//
|
||||
// r := DirectImageRuntime{m}
|
||||
// err := r.Delete(context.TODO(), actual, "fedora")
|
||||
// if err != nil {
|
||||
// t.Errorf("error should be nil, got: %v", err)
|
||||
// }
|
||||
// m.AssertExpectations(t)
|
||||
// }
|
|
@ -0,0 +1,19 @@
|
|||
// +build ABISupport
|
||||
|
||||
package abi
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
)
|
||||
|
||||
// Image-related runtime linked against libpod library
|
||||
type ImageEngine struct {
|
||||
Libpod *libpod.Runtime
|
||||
}
|
||||
|
||||
// Container-related runtime linked against libpod library
|
||||
type ContainerEngine struct {
|
||||
entities.ContainerEngine
|
||||
Libpod *libpod.Runtime
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// +build ABISupport
|
||||
|
||||
package infra
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/libpod/pkg/bindings"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/domain/infra/abi"
|
||||
"github.com/containers/libpod/pkg/domain/infra/tunnel"
|
||||
)
|
||||
|
||||
// NewContainerEngine factory provides a libpod runtime for container-related operations
|
||||
func NewContainerEngine(mode entities.EngineMode, opts entities.EngineOptions) (entities.ContainerEngine, error) {
|
||||
switch mode {
|
||||
case entities.ABIMode:
|
||||
r, err := NewLibpodRuntime(opts.FlagSet, opts.Flags)
|
||||
return &abi.ContainerEngine{ContainerEngine: r}, err
|
||||
case entities.TunnelMode:
|
||||
ctx, err := bindings.NewConnection(context.Background(), opts.Uri.String(), opts.Identities...)
|
||||
return &tunnel.ContainerEngine{ClientCxt: ctx}, err
|
||||
}
|
||||
return nil, fmt.Errorf("runtime mode '%v' is not supported", mode)
|
||||
}
|
||||
|
||||
// NewContainerEngine factory provides a libpod runtime for image-related operations
|
||||
func NewImageEngine(mode entities.EngineMode, opts entities.EngineOptions) (entities.ImageEngine, error) {
|
||||
switch mode {
|
||||
case entities.ABIMode:
|
||||
r, err := NewLibpodImageRuntime(opts.FlagSet, opts.Flags)
|
||||
return r, err
|
||||
case entities.TunnelMode:
|
||||
ctx, err := bindings.NewConnection(context.Background(), opts.Uri.String(), opts.Identities...)
|
||||
return &tunnel.ImageEngine{ClientCxt: ctx}, err
|
||||
}
|
||||
return nil, fmt.Errorf("runtime mode '%v' is not supported", mode)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// +build ABISupport
|
||||
|
||||
package infra
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/domain/infra/abi"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// ContainerEngine Image Proxy will be EOL'ed after podmanV2 is separated from libpod repo
|
||||
|
||||
func NewLibpodImageRuntime(flags pflag.FlagSet, opts entities.EngineFlags) (entities.ImageEngine, error) {
|
||||
r, err := GetRuntime(context.Background(), flags, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &abi.ImageEngine{Libpod: r}, nil
|
||||
}
|
||||
|
||||
func (ir *runtime) ShutdownImageRuntime(force bool) error {
|
||||
return ir.Libpod.Shutdown(force)
|
||||
}
|
|
@ -0,0 +1,331 @@
|
|||
package infra
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/cgroups"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/namespaces"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/pkg/errors"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
type engineOpts struct {
|
||||
name string
|
||||
renumber bool
|
||||
migrate bool
|
||||
noStore bool
|
||||
withFDS bool
|
||||
flags entities.EngineFlags
|
||||
}
|
||||
|
||||
// GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers
|
||||
func GetRuntimeMigrate(ctx context.Context, fs flag.FlagSet, ef entities.EngineFlags, newRuntime string) (*libpod.Runtime, error) {
|
||||
return getRuntime(ctx, fs, &engineOpts{
|
||||
name: newRuntime,
|
||||
renumber: false,
|
||||
migrate: true,
|
||||
noStore: false,
|
||||
withFDS: true,
|
||||
flags: ef,
|
||||
})
|
||||
}
|
||||
|
||||
// GetRuntimeDisableFDs gets a libpod runtime that will disable sd notify
|
||||
func GetRuntimeDisableFDs(ctx context.Context, fs flag.FlagSet, ef entities.EngineFlags) (*libpod.Runtime, error) {
|
||||
return getRuntime(ctx, fs, &engineOpts{
|
||||
renumber: false,
|
||||
migrate: false,
|
||||
noStore: false,
|
||||
withFDS: false,
|
||||
flags: ef,
|
||||
})
|
||||
}
|
||||
|
||||
// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber
|
||||
func GetRuntimeRenumber(ctx context.Context, fs flag.FlagSet, ef entities.EngineFlags) (*libpod.Runtime, error) {
|
||||
return getRuntime(ctx, fs, &engineOpts{
|
||||
renumber: true,
|
||||
migrate: false,
|
||||
noStore: false,
|
||||
withFDS: true,
|
||||
flags: ef,
|
||||
})
|
||||
}
|
||||
|
||||
// GetRuntime generates a new libpod runtime configured by command line options
|
||||
func GetRuntime(ctx context.Context, flags flag.FlagSet, ef entities.EngineFlags) (*libpod.Runtime, error) {
|
||||
return getRuntime(ctx, flags, &engineOpts{
|
||||
renumber: false,
|
||||
migrate: false,
|
||||
noStore: false,
|
||||
withFDS: true,
|
||||
flags: ef,
|
||||
})
|
||||
}
|
||||
|
||||
// GetRuntimeNoStore generates a new libpod runtime configured by command line options
|
||||
func GetRuntimeNoStore(ctx context.Context, fs flag.FlagSet, ef entities.EngineFlags) (*libpod.Runtime, error) {
|
||||
return getRuntime(ctx, fs, &engineOpts{
|
||||
renumber: false,
|
||||
migrate: false,
|
||||
noStore: true,
|
||||
withFDS: true,
|
||||
flags: ef,
|
||||
})
|
||||
}
|
||||
|
||||
func getRuntime(ctx context.Context, fs flag.FlagSet, opts *engineOpts) (*libpod.Runtime, error) {
|
||||
options := []libpod.RuntimeOption{}
|
||||
storageOpts := storage.StoreOptions{}
|
||||
storageSet := false
|
||||
|
||||
uidmapFlag := fs.Lookup("uidmap")
|
||||
gidmapFlag := fs.Lookup("gidmap")
|
||||
subuidname := fs.Lookup("subuidname")
|
||||
subgidname := fs.Lookup("subgidname")
|
||||
if (uidmapFlag != nil && gidmapFlag != nil && subuidname != nil && subgidname != nil) &&
|
||||
(uidmapFlag.Changed || gidmapFlag.Changed || subuidname.Changed || subgidname.Changed) {
|
||||
userns, _ := fs.GetString("userns")
|
||||
uidmapVal, _ := fs.GetStringSlice("uidmap")
|
||||
gidmapVal, _ := fs.GetStringSlice("gidmap")
|
||||
subuidVal, _ := fs.GetString("subuidname")
|
||||
subgidVal, _ := fs.GetString("subgidname")
|
||||
mappings, err := ParseIDMapping(namespaces.UsernsMode(userns), uidmapVal, gidmapVal, subuidVal, subgidVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storageOpts.UIDMap = mappings.UIDMap
|
||||
storageOpts.GIDMap = mappings.GIDMap
|
||||
|
||||
storageSet = true
|
||||
}
|
||||
|
||||
if fs.Changed("root") {
|
||||
storageSet = true
|
||||
storageOpts.GraphRoot = opts.flags.Root
|
||||
}
|
||||
if fs.Changed("runroot") {
|
||||
storageSet = true
|
||||
storageOpts.RunRoot = opts.flags.Runroot
|
||||
}
|
||||
if len(storageOpts.RunRoot) > 50 {
|
||||
return nil, errors.New("the specified runroot is longer than 50 characters")
|
||||
}
|
||||
if fs.Changed("storage-driver") {
|
||||
storageSet = true
|
||||
storageOpts.GraphDriverName = opts.flags.StorageDriver
|
||||
// Overriding the default storage driver caused GraphDriverOptions from storage.conf to be ignored
|
||||
storageOpts.GraphDriverOptions = []string{}
|
||||
}
|
||||
// This should always be checked after storage-driver is checked
|
||||
if len(opts.flags.StorageOpts) > 0 {
|
||||
storageSet = true
|
||||
storageOpts.GraphDriverOptions = opts.flags.StorageOpts
|
||||
}
|
||||
if opts.migrate {
|
||||
options = append(options, libpod.WithMigrate())
|
||||
if opts.name != "" {
|
||||
options = append(options, libpod.WithMigrateRuntime(opts.name))
|
||||
}
|
||||
}
|
||||
|
||||
if opts.renumber {
|
||||
options = append(options, libpod.WithRenumber())
|
||||
}
|
||||
|
||||
// Only set this if the user changes storage config on the command line
|
||||
if storageSet {
|
||||
options = append(options, libpod.WithStorageConfig(storageOpts))
|
||||
}
|
||||
|
||||
if !storageSet && opts.noStore {
|
||||
options = append(options, libpod.WithNoStore())
|
||||
}
|
||||
// TODO CLI flags for image config?
|
||||
// TODO CLI flag for signature policy?
|
||||
|
||||
if len(opts.flags.Namespace) > 0 {
|
||||
options = append(options, libpod.WithNamespace(opts.flags.Namespace))
|
||||
}
|
||||
|
||||
if fs.Changed("runtime") {
|
||||
options = append(options, libpod.WithOCIRuntime(opts.flags.Runtime))
|
||||
}
|
||||
|
||||
if fs.Changed("conmon") {
|
||||
options = append(options, libpod.WithConmonPath(opts.flags.ConmonPath))
|
||||
}
|
||||
if fs.Changed("tmpdir") {
|
||||
options = append(options, libpod.WithTmpDir(opts.flags.TmpDir))
|
||||
}
|
||||
if fs.Changed("network-cmd-path") {
|
||||
options = append(options, libpod.WithNetworkCmdPath(opts.flags.NetworkCmdPath))
|
||||
}
|
||||
|
||||
if fs.Changed("events-backend") {
|
||||
options = append(options, libpod.WithEventsLogger(opts.flags.EventsBackend))
|
||||
}
|
||||
|
||||
if fs.Changed("cgroup-manager") {
|
||||
options = append(options, libpod.WithCgroupManager(opts.flags.CGroupManager))
|
||||
} else {
|
||||
unified, err := cgroups.IsCgroup2UnifiedMode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rootless.IsRootless() && !unified {
|
||||
options = append(options, libpod.WithCgroupManager("cgroupfs"))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO flag to set libpod static dir?
|
||||
// TODO flag to set libpod tmp dir?
|
||||
|
||||
if fs.Changed("cni-config-dir") {
|
||||
options = append(options, libpod.WithCNIConfigDir(opts.flags.CniConfigDir))
|
||||
}
|
||||
if fs.Changed("default-mounts-file") {
|
||||
options = append(options, libpod.WithDefaultMountsFile(opts.flags.DefaultMountsFile))
|
||||
}
|
||||
if fs.Changed("hooks-dir") {
|
||||
options = append(options, libpod.WithHooksDir(opts.flags.HooksDir...))
|
||||
}
|
||||
|
||||
// TODO flag to set CNI plugins dir?
|
||||
|
||||
// TODO I don't think these belong here?
|
||||
// Will follow up with a different PR to address
|
||||
//
|
||||
// Pod create options
|
||||
|
||||
infraImageFlag := fs.Lookup("infra-image")
|
||||
if infraImageFlag != nil && infraImageFlag.Changed {
|
||||
infraImage, _ := fs.GetString("infra-image")
|
||||
options = append(options, libpod.WithDefaultInfraImage(infraImage))
|
||||
}
|
||||
|
||||
infraCommandFlag := fs.Lookup("infra-command")
|
||||
if infraCommandFlag != nil && infraImageFlag.Changed {
|
||||
infraCommand, _ := fs.GetString("infra-command")
|
||||
options = append(options, libpod.WithDefaultInfraCommand(infraCommand))
|
||||
}
|
||||
|
||||
if !opts.withFDS {
|
||||
options = append(options, libpod.WithEnableSDNotify())
|
||||
}
|
||||
if fs.Changed("config") {
|
||||
return libpod.NewRuntimeFromConfig(ctx, opts.flags.Config, options...)
|
||||
}
|
||||
return libpod.NewRuntime(ctx, options...)
|
||||
}
|
||||
|
||||
// ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping
|
||||
func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []string, subUIDMap, subGIDMap string) (*storage.IDMappingOptions, error) {
|
||||
options := storage.IDMappingOptions{
|
||||
HostUIDMapping: true,
|
||||
HostGIDMapping: true,
|
||||
}
|
||||
|
||||
if mode.IsKeepID() {
|
||||
if len(uidMapSlice) > 0 || len(gidMapSlice) > 0 {
|
||||
return nil, errors.New("cannot specify custom mappings with --userns=keep-id")
|
||||
}
|
||||
if len(subUIDMap) > 0 || len(subGIDMap) > 0 {
|
||||
return nil, errors.New("cannot specify subuidmap or subgidmap with --userns=keep-id")
|
||||
}
|
||||
if rootless.IsRootless() {
|
||||
min := func(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
uid := rootless.GetRootlessUID()
|
||||
gid := rootless.GetRootlessGID()
|
||||
|
||||
uids, gids, err := rootless.GetConfiguredMappings()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot read mappings")
|
||||
}
|
||||
maxUID, maxGID := 0, 0
|
||||
for _, u := range uids {
|
||||
maxUID += u.Size
|
||||
}
|
||||
for _, g := range gids {
|
||||
maxGID += g.Size
|
||||
}
|
||||
|
||||
options.UIDMap, options.GIDMap = nil, nil
|
||||
|
||||
options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)})
|
||||
options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1})
|
||||
if maxUID > uid {
|
||||
options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid})
|
||||
}
|
||||
|
||||
options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)})
|
||||
options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1})
|
||||
if maxGID > gid {
|
||||
options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid})
|
||||
}
|
||||
|
||||
options.HostUIDMapping = false
|
||||
options.HostGIDMapping = false
|
||||
}
|
||||
// Simply ignore the setting and do not setup an inner namespace for root as it is a no-op
|
||||
return &options, nil
|
||||
}
|
||||
|
||||
if subGIDMap == "" && subUIDMap != "" {
|
||||
subGIDMap = subUIDMap
|
||||
}
|
||||
if subUIDMap == "" && subGIDMap != "" {
|
||||
subUIDMap = subGIDMap
|
||||
}
|
||||
if len(gidMapSlice) == 0 && len(uidMapSlice) != 0 {
|
||||
gidMapSlice = uidMapSlice
|
||||
}
|
||||
if len(uidMapSlice) == 0 && len(gidMapSlice) != 0 {
|
||||
uidMapSlice = gidMapSlice
|
||||
}
|
||||
if len(uidMapSlice) == 0 && subUIDMap == "" && os.Getuid() != 0 {
|
||||
uidMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getuid())}
|
||||
}
|
||||
if len(gidMapSlice) == 0 && subGIDMap == "" && os.Getuid() != 0 {
|
||||
gidMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getgid())}
|
||||
}
|
||||
|
||||
if subUIDMap != "" && subGIDMap != "" {
|
||||
mappings, err := idtools.NewIDMappings(subUIDMap, subGIDMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.UIDMap = mappings.UIDs()
|
||||
options.GIDMap = mappings.GIDs()
|
||||
}
|
||||
parsedUIDMap, err := idtools.ParseIDMap(uidMapSlice, "UID")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsedGIDMap, err := idtools.ParseIDMap(gidMapSlice, "GID")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.UIDMap = append(options.UIDMap, parsedUIDMap...)
|
||||
options.GIDMap = append(options.GIDMap, parsedGIDMap...)
|
||||
if len(options.UIDMap) > 0 {
|
||||
options.HostUIDMapping = false
|
||||
}
|
||||
if len(options.GIDMap) > 0 {
|
||||
options.HostGIDMapping = false
|
||||
}
|
||||
return &options, nil
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// +build ABISupport
|
||||
|
||||
package infra
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// ContainerEngine Proxy will be EOL'ed after podmanV2 is separated from libpod repo
|
||||
|
||||
type runtime struct {
|
||||
entities.ContainerEngine
|
||||
Libpod *libpod.Runtime
|
||||
}
|
||||
|
||||
func NewLibpodRuntime(flags flag.FlagSet, opts entities.EngineFlags) (entities.ContainerEngine, error) {
|
||||
r, err := GetRuntime(context.Background(), flags, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &runtime{Libpod: r}, nil
|
||||
}
|
||||
|
||||
func (r *runtime) ShutdownRuntime(force bool) error {
|
||||
return r.Libpod.Shutdown(force)
|
||||
}
|
||||
|
||||
func (r *runtime) ContainerDelete(ctx context.Context, opts entities.ContainerDeleteOptions) (*entities.ContainerDeleteReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *runtime) ContainerPrune(ctx context.Context) (*entities.ContainerPruneReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *runtime) PodDelete(ctx context.Context, opts entities.PodPruneOptions) (*entities.PodDeleteReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *runtime) PodPrune(ctx context.Context) (*entities.PodPruneReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *runtime) VolumeDelete(ctx context.Context, opts entities.VolumeDeleteOptions) (*entities.VolumeDeleteReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *runtime) VolumePrune(ctx context.Context) (*entities.VolumePruneReport, error) {
|
||||
panic("implement me")
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// +build !ABISupport
|
||||
|
||||
package infra
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/libpod/pkg/bindings"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/domain/infra/tunnel"
|
||||
)
|
||||
|
||||
func NewContainerEngine(mode entities.EngineMode, opts entities.EngineOptions) (entities.ContainerEngine, error) {
|
||||
switch mode {
|
||||
case entities.ABIMode:
|
||||
return nil, fmt.Errorf("direct runtime not supported")
|
||||
case entities.TunnelMode:
|
||||
ctx, err := bindings.NewConnection(context.Background(), opts.Uri.String(), opts.Identities...)
|
||||
return &tunnel.ContainerEngine{ClientCxt: ctx}, err
|
||||
}
|
||||
return nil, fmt.Errorf("runtime mode '%v' is not supported", mode)
|
||||
}
|
||||
|
||||
// NewImageEngine factory provides a libpod runtime for image-related operations
|
||||
func NewImageEngine(mode entities.EngineMode, opts entities.EngineOptions) (entities.ImageEngine, error) {
|
||||
switch mode {
|
||||
case entities.ABIMode:
|
||||
return nil, fmt.Errorf("direct image runtime not supported")
|
||||
case entities.TunnelMode:
|
||||
ctx, err := bindings.NewConnection(context.Background(), opts.Uri.String(), opts.Identities...)
|
||||
return &tunnel.ImageEngine{ClientCxt: ctx}, err
|
||||
}
|
||||
return nil, fmt.Errorf("runtime mode '%v' is not supported", mode)
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
|
||||
images "github.com/containers/libpod/pkg/bindings/images"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/domain/utils"
|
||||
)
|
||||
|
||||
func (ir *ImageEngine) Delete(ctx context.Context, nameOrId string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
|
||||
results, err := images.Remove(ir.ClientCxt, nameOrId, &opts.Force)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := entities.ImageDeleteReport{
|
||||
Untagged: nil,
|
||||
Deleted: "",
|
||||
}
|
||||
|
||||
for _, e := range results {
|
||||
if a, ok := e["Deleted"]; ok {
|
||||
report.Deleted = a
|
||||
}
|
||||
|
||||
if a, ok := e["Untagged"]; ok {
|
||||
report.Untagged = append(report.Untagged, a)
|
||||
}
|
||||
}
|
||||
return &report, err
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) (*entities.ImageListReport, error) {
|
||||
images, err := images.List(ir.ClientCxt, &opts.All, opts.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := entities.ImageListReport{
|
||||
Images: make([]entities.ImageSummary, len(images)),
|
||||
}
|
||||
for i, img := range images {
|
||||
hold := entities.ImageSummary{}
|
||||
if err := utils.DeepCopy(&hold, img); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
report.Images[i] = hold
|
||||
}
|
||||
return &report, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
|
||||
results, err := images.History(ir.ClientCxt, nameOrId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
history := entities.ImageHistoryReport{
|
||||
Layers: make([]entities.ImageHistoryLayer, len(results)),
|
||||
}
|
||||
|
||||
for i, layer := range results {
|
||||
hold := entities.ImageHistoryLayer{}
|
||||
_ = utils.DeepCopy(&hold, layer)
|
||||
history.Layers[i] = hold
|
||||
}
|
||||
return &history, nil
|
||||
}
|
||||
|
||||
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
|
||||
results, err := images.Prune(ir.ClientCxt, url.Values{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
report := entities.ImagePruneReport{}
|
||||
copy(report.Report.Id, results)
|
||||
return &report, nil
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package tunnel
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
)
|
||||
|
||||
// Image-related runtime using an ssh-tunnel to utilize Podman service
|
||||
type ImageEngine struct {
|
||||
ClientCxt context.Context
|
||||
}
|
||||
|
||||
// Container-related runtime using an ssh-tunnel to utilize Podman service
|
||||
type ContainerEngine struct {
|
||||
ClientCxt context.Context
|
||||
}
|
||||
|
||||
func (r *ContainerEngine) Shutdown(force bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ContainerEngine) ContainerDelete(ctx context.Context, opts entities.ContainerDeleteOptions) (*entities.ContainerDeleteReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *ContainerEngine) ContainerPrune(ctx context.Context) (*entities.ContainerPruneReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *ContainerEngine) PodDelete(ctx context.Context, opts entities.PodPruneOptions) (*entities.PodDeleteReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *ContainerEngine) PodPrune(ctx context.Context) (*entities.PodPruneReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *ContainerEngine) VolumeDelete(ctx context.Context, opts entities.VolumeDeleteOptions) (*entities.VolumeDeleteReport, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r *ContainerEngine) VolumePrune(ctx context.Context) (*entities.VolumePruneReport, error) {
|
||||
panic("implement me")
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
// DeepCopy does a deep copy of a structure
|
||||
// Error checking of parameters delegated to json engine
|
||||
var DeepCopy = func(dst interface{}, src interface{}) error {
|
||||
payload, err := json.Marshal(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(payload, dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ToLibpodFilters(f url.Values) (filters []string) {
|
||||
for k, v := range f {
|
||||
filters = append(filters, k+"="+v[0])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ToUrlValues(f []string) (filters url.Values) {
|
||||
filters = make(url.Values)
|
||||
for _, v := range f {
|
||||
t := strings.SplitN(v, "=", 2)
|
||||
filters.Add(t[0], t[1])
|
||||
}
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue