From 5cfd7a313fcae7c748b5bae84de779b28d4ea01b Mon Sep 17 00:00:00 2001 From: baude Date: Mon, 13 Nov 2017 12:40:21 -0600 Subject: Address run/create performance issues Fixed the logic where we observed different performance results when running an image by its fqname vs a shortname. In the case of the latter, we resolve the name without using the network. Signed-off-by: baude Closes: #37 Approved by: rhatdan --- cmd/kpod/create.go | 10 +++++-- cmd/kpod/run.go | 11 +++++-- libpod/runtime_img.go | 80 ++++++++++++++++++++++++++++++++++++++++++++------- libpod/util.go | 10 +++++++ 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/cmd/kpod/create.go b/cmd/kpod/create.go index 55f02e8e6..bbfeaebae 100644 --- a/cmd/kpod/create.go +++ b/cmd/kpod/create.go @@ -135,6 +135,7 @@ var createCommand = cli.Command{ func createCmd(c *cli.Context) error { // TODO should allow user to create based off a directory on the host not just image // Need CLI support for this + var imageName string if err := validateFlags(c, createFlags); err != nil { return err } @@ -151,7 +152,8 @@ func createCmd(c *cli.Context) error { // Deal with the image after all the args have been checked createImage := runtime.NewImage(createConfig.image) - if !createImage.HasImageLocal() { + createImage.LocalName, _ = createImage.GetLocalImageName() + if createImage.LocalName == "" { // The image wasnt found by the user input'd name or its fqname // Pull the image fmt.Printf("Trying to pull %s...", createImage.PullName) @@ -163,7 +165,11 @@ func createCmd(c *cli.Context) error { return err } defer runtime.Shutdown(false) - imageName, err := createImage.GetFQName() + if createImage.LocalName != "" { + imageName = createImage.LocalName + } else { + imageName, err = createImage.GetFQName() + } if err != nil { return err } diff --git a/cmd/kpod/run.go b/cmd/kpod/run.go index 6b67b55cd..84da12e6a 100644 --- a/cmd/kpod/run.go +++ b/cmd/kpod/run.go @@ -22,6 +22,7 @@ var runCommand = cli.Command{ } func runCmd(c *cli.Context) error { + var imageName string if err := validateFlags(c, createFlags); err != nil { return err } @@ -37,8 +38,8 @@ func runCmd(c *cli.Context) error { } createImage := runtime.NewImage(createConfig.image) - - if !createImage.HasImageLocal() { + createImage.LocalName, _ = createImage.GetLocalImageName() + if createImage.LocalName == "" { // The image wasnt found by the user input'd name or its fqname // Pull the image fmt.Printf("Trying to pull %s...", createImage.PullName) @@ -52,7 +53,11 @@ func runCmd(c *cli.Context) error { defer runtime.Shutdown(false) logrus.Debug("spec is ", runtimeSpec) - imageName, err := createImage.GetFQName() + if createImage.LocalName != "" { + imageName = createImage.LocalName + } else { + imageName, err = createImage.GetFQName() + } if err != nil { return err } diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index 8a5258e75..0fa003799 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -127,6 +127,7 @@ type Image struct { Transport string beenDecomposed bool PullName string + LocalName string } // NewImage creates a new image object based on its name @@ -139,9 +140,21 @@ func (r *Runtime) NewImage(name string) Image { // GetImageID returns the image ID of the image func (k *Image) GetImageID() (string, error) { + // If the ID field is already populated, then + // return it. if k.ID != "" { return k.ID, nil } + // If we have the name of the image locally, then + // get the image and returns its ID + if k.LocalName != "" { + img, err := k.runtime.GetImage(k.LocalName) + if err == nil { + return img.ID, nil + } + } + // If neither the ID is known and no local name + // is know, we search it out. image, _ := k.GetFQName() img, err := k.runtime.GetImage(image) if err != nil { @@ -270,26 +283,73 @@ func (k *Image) Decompose() error { return nil } -// HasImageLocal returns a bool true if the image is already pulled -func (k *Image) HasImageLocal() bool { +func getTags(nameInput string) (reference.NamedTagged, bool, error) { + inputRef, err := reference.Parse(nameInput) + if err != nil { + return nil, false, errors.Wrapf(err, "unable to obtain tag from input name") + } + tagged, isTagged := inputRef.(reference.NamedTagged) + + return tagged, isTagged, nil +} + +// GetLocalImageName returns the name of the image if it is local. +// It will return an empty string and error if not found. +func (k *Image) GetLocalImageName() (string, error) { _, err := k.runtime.GetImage(k.Name) - if err == nil { - return true + if err != nil { + return "", errors.Wrapf(err, "unable to obtain local image") } - fqname, _ := k.GetFQName() + localImages, err := k.runtime.GetImages(&ImageFilterParams{}) + if err != nil { + return "", errors.Wrapf(err, "unable to obtain local image") + } + _, isTagged, err := getTags(k.Name) + if err != nil { + return "", err + } + for _, image := range localImages { + for _, name := range image.Names { + imgRef, err := reference.Parse(name) + if err != nil { + continue + } + var imageName string + imageNameOnly := reference.Path(imgRef.(reference.Named)) + if isTagged { + imageNameTag, _, err := getTags(name) + if err != nil { + continue + } + imageName = fmt.Sprintf("%s:%s", imageNameOnly, imageNameTag.Tag()) + } else { + imageName = imageNameOnly + } - _, err = k.runtime.GetImage(fqname) - if err == nil { - return true + if imageName == k.Name { + return name, nil + } + imageSplit := strings.Split(imageName, "/") + baseName := imageSplit[len(imageSplit)-1] + if baseName == k.Name { + return name, nil + } + } } - return false + fqname, _ := k.GetFQName() + return fqname, nil } // HasLatest determines if we have the latest image local func (k *Image) HasLatest() (bool, error) { - if !k.HasImageLocal() { + localName, err := k.GetLocalImageName() + if err != nil { + return false, err + } + if localName == "" { return false, nil } + fqname, err := k.GetFQName() if err != nil { return false, err diff --git a/libpod/util.go b/libpod/util.go index 0270af07c..61546f23e 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -1,8 +1,10 @@ package libpod import ( + "fmt" "os" "path/filepath" + "time" ) // WriteFile writes a provided string to a provided path @@ -32,3 +34,11 @@ func StringInSlice(s string, sl []string) bool { } return false } + +// FuncTimer helps measure the execution time of a function +// For debug purposes, do not leave in code +// used like defer FuncTimer("foo") +func FuncTimer(funcName string) { + elapsed := time.Since(time.Now()) + fmt.Printf("%s executed in %d ms\n", funcName, elapsed) +} -- cgit v1.2.3-54-g00ecf