Merge pull request #5686 from baude/v2load

podmanv2 load
This commit is contained in:
OpenShift Merge Robot
2020-04-01 22:54:22 +02:00
committed by GitHub
13 changed files with 125 additions and 14 deletions

View File

@ -1,2 +1,2 @@
all: all:
GO111MODULE=off go build -tags 'ABISupport' GO111MODULE=off go build -tags 'ABISupport systemd'

View File

@ -0,0 +1,61 @@
package images
import (
"context"
"fmt"
"github.com/containers/libpod/cmd/podmanV2/registry"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
)
var (
loadDescription = "Loads an image from a locally stored archive (tar file) into container storage."
loadCommand = &cobra.Command{
Use: "load [flags] [NAME[:TAG]]",
Short: "Load an image from container archive",
Long: loadDescription,
RunE: load,
Args: cobra.MaximumNArgs(1),
PersistentPreRunE: preRunE,
}
)
var (
loadOpts entities.ImageLoadOptions
)
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: loadCommand,
})
loadCommand.SetHelpTemplate(registry.HelpTemplate())
loadCommand.SetUsageTemplate(registry.UsageTemplate())
flags := loadCommand.Flags()
flags.StringVarP(&loadOpts.Input, "input", "i", "", "Read from specified archive file (default: stdin)")
flags.BoolVarP(&loadOpts.Quiet, "quiet", "q", false, "Suppress the output")
flags.StringVar(&loadOpts.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file")
if registry.IsRemote() {
_ = flags.MarkHidden("signature-policy")
}
}
func load(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
repo, err := image.NormalizedTag(args[0])
if err != nil {
return err
}
loadOpts.Name = repo.Name()
}
response, err := registry.ImageEngine().Load(context.Background(), loadOpts)
if err != nil {
return err
}
fmt.Println("Loaded image: " + response.Name)
return nil
}

View File

@ -15,6 +15,7 @@ import (
_ "github.com/containers/libpod/cmd/podmanV2/volumes" _ "github.com/containers/libpod/cmd/podmanV2/volumes"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/storage/pkg/reexec"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -45,6 +46,11 @@ func init() {
} }
func main() { func main() {
if reexec.Init() {
// We were invoked with a different argv[0] indicating that we
// had a specific job to do as a subprocess, and it's done.
return
}
for _, c := range registry.Commands { for _, c := range registry.Commands {
if Contains(registry.EngineOptions.EngineMode, c.Mode) { if Contains(registry.EngineOptions.EngineMode, c.Mode) {
parent := rootCmd parent := rootCmd

View File

@ -512,8 +512,8 @@ func getImageDigest(ctx context.Context, src types.ImageReference, sc *types.Sys
return "@" + imageDigest.Hex(), nil return "@" + imageDigest.Hex(), nil
} }
// normalizedTag returns the canonical version of tag for use in Image.Names() // NormalizedTag returns the canonical version of tag for use in Image.Names()
func normalizedTag(tag string) (reference.Named, error) { func NormalizedTag(tag string) (reference.Named, error) {
decomposedTag, err := decompose(tag) decomposedTag, err := decompose(tag)
if err != nil { if err != nil {
return nil, err return nil, err
@ -541,7 +541,7 @@ func (i *Image) TagImage(tag string) error {
if err := i.reloadImage(); err != nil { if err := i.reloadImage(); err != nil {
return err return err
} }
ref, err := normalizedTag(tag) ref, err := NormalizedTag(tag)
if err != nil { if err != nil {
return err return err
} }

View File

@ -292,7 +292,7 @@ func TestNormalizedTag(t *testing.T) {
{"ns/busybox:latest", "localhost/ns/busybox:latest"}, // Unqualified with a dot-less namespace {"ns/busybox:latest", "localhost/ns/busybox:latest"}, // Unqualified with a dot-less namespace
{"docker.io/busybox:latest", "docker.io/library/busybox:latest"}, // docker.io without /library/ {"docker.io/busybox:latest", "docker.io/library/busybox:latest"}, // docker.io without /library/
} { } {
res, err := normalizedTag(c.input) res, err := NormalizedTag(c.input)
if c.expected == "" { if c.expected == "" {
assert.Error(t, err, c.input) assert.Error(t, err, c.input)
} else { } else {

View File

@ -254,7 +254,7 @@ func ImagesLoad(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
utils.WriteResponse(w, http.StatusOK, handlers.LibpodImagesLoadReport{ID: loadedImage}) utils.WriteResponse(w, http.StatusOK, entities.ImageLoadReport{Name: loadedImage})
} }
func ImagesImport(w http.ResponseWriter, r *http.Request) { func ImagesImport(w http.ResponseWriter, r *http.Request) {

View File

@ -31,7 +31,7 @@ type swagImageInspect struct {
// swagger:response DocsLibpodImagesLoadResponse // swagger:response DocsLibpodImagesLoadResponse
type swagLibpodImagesLoadResponse struct { type swagLibpodImagesLoadResponse struct {
// in:body // in:body
Body []LibpodImagesLoadReport Body entities.ImageLoadReport
} }
// Import response // Import response

View File

@ -91,11 +91,11 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse,
return history, response.Process(&history) return history, response.Process(&history)
} }
func Load(ctx context.Context, r io.Reader, name *string) (string, error) { func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadReport, error) {
var id handlers.IDResponse var report entities.ImageLoadReport
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return "", err return nil, err
} }
params := url.Values{} params := url.Values{}
if name != nil { if name != nil {
@ -103,9 +103,9 @@ func Load(ctx context.Context, r io.Reader, name *string) (string, error) {
} }
response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params) response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params)
if err != nil { if err != nil {
return "", err return nil, err
} }
return id.ID, response.Process(&id) return &report, response.Process(&report)
} }
// Remove deletes an image from local storage. The optional force parameter will forcibly remove // Remove deletes an image from local storage. The optional force parameter will forcibly remove

View File

@ -219,7 +219,7 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
names, err := images.Load(bt.conn, f, nil) names, err := images.Load(bt.conn, f, nil)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(names).To(Equal(alpine.name)) Expect(names.Name).To(Equal(alpine.name))
exists, err = images.Exists(bt.conn, alpine.name) exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(exists).To(BeTrue()) Expect(exists).To(BeTrue())
@ -235,7 +235,7 @@ var _ = Describe("Podman images", func() {
newName := "quay.io/newname:fizzle" newName := "quay.io/newname:fizzle"
names, err = images.Load(bt.conn, f, &newName) names, err = images.Load(bt.conn, f, &newName)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(names).To(Equal(alpine.name)) Expect(names.Name).To(Equal(alpine.name))
exists, err = images.Exists(bt.conn, newName) exists, err = images.Exists(bt.conn, newName)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(exists).To(BeTrue()) Expect(exists).To(BeTrue())

View File

@ -14,4 +14,5 @@ type ImageEngine interface {
Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error) Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error)
Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error
Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
} }

View File

@ -172,3 +172,15 @@ type ImageInspectReport struct {
Images []*ImageData Images []*ImageData
Errors map[string]error Errors map[string]error
} }
type ImageLoadOptions struct {
Name string
Tag string
Input string
Quiet bool
SignaturePolicy string
}
type ImageLoadReport struct {
Name string
}

View File

@ -315,3 +315,24 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrId string, tags []string
} }
return nil return nil
} }
func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) (*entities.ImageLoadReport, error) {
var (
writer io.Writer
)
if !opts.Quiet {
writer = os.Stderr
}
name, err := ir.Libpod.LoadImage(ctx, opts.Name, opts.Input, writer, opts.SignaturePolicy)
if err != nil {
return nil, err
}
newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(name)
if err != nil {
return nil, errors.Wrap(err, "image loaded but no additional tags were created")
}
if err := newImage.TagImage(opts.Name); err != nil {
return nil, errors.Wrapf(err, "error adding %q to image %q", opts.Name, newImage.InputName)
}
return &entities.ImageLoadReport{Name: name}, nil
}

View File

@ -2,6 +2,7 @@ package tunnel
import ( import (
"context" "context"
"os"
"github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/docker/reference"
images "github.com/containers/libpod/pkg/bindings/images" images "github.com/containers/libpod/pkg/bindings/images"
@ -157,3 +158,12 @@ func (ir *ImageEngine) Inspect(_ context.Context, names []string, opts entities.
} }
return &report, nil return &report, nil
} }
func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) (*entities.ImageLoadReport, error) {
f, err := os.Open(opts.Input)
if err != nil {
return nil, err
}
defer f.Close()
return images.Load(ir.ClientCxt, f, &opts.Name)
}