summaryrefslogtreecommitdiff
path: root/pkg/varlinkapi/images.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/varlinkapi/images.go')
-rw-r--r--pkg/varlinkapi/images.go373
1 files changed, 292 insertions, 81 deletions
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 8deb4cbe2..210f139ce 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -13,7 +13,6 @@ import (
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
- "github.com/containers/image/docker"
dockerarchive "github.com/containers/image/docker/archive"
"github.com/containers/image/manifest"
"github.com/containers/image/transports/alltransports"
@@ -22,7 +21,6 @@ import (
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
- sysreg "github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
"github.com/containers/storage/pkg/archive"
@@ -75,7 +73,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, id string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(id)
if err != nil {
- return call.ReplyImageNotFound(id)
+ return call.ReplyImageNotFound(id, err.Error())
}
labels, err := newImage.Labels(getContext())
if err != nil {
@@ -137,7 +135,7 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
logrus.Debugf("untar of %s successful", contextDir)
// All output (stdout, stderr) is captured in output as well
- output := bytes.NewBuffer([]byte{})
+ var output bytes.Buffer
commonOpts := &buildah.CommonBuildOptions{
AddHost: config.BuildOptions.AddHosts,
@@ -170,20 +168,20 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
Compression: stringCompressionToArchiveType(config.Compression),
ContextDirectory: newContextDir,
DefaultMountsFilePath: config.DefaultsMountFilePath,
- Err: output,
+ Err: &output,
ForceRmIntermediateCtrs: config.ForceRmIntermediateCtrs,
IIDFile: config.Iidfile,
Labels: config.Label,
Layers: config.Layers,
NoCache: config.Nocache,
- Out: output,
+ Out: &output,
Output: config.Output,
NamespaceOptions: namespace,
OutputFormat: config.OutputFormat,
PullPolicy: stringPullPolicyToType(config.PullPolicy),
Quiet: config.Quiet,
RemoveIntermediateCtrs: config.RemoteIntermediateCtrs,
- ReportWriter: output,
+ ReportWriter: &output,
RuntimeArgs: config.RuntimeArgs,
SignaturePolicyPath: config.SignaturePolicyPath,
Squash: config.Squash,
@@ -208,7 +206,13 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
newPathDockerFiles = append(newPathDockerFiles, filepath.Join(newContextDir, base))
}
- c := build(i.Runtime, options, newPathDockerFiles)
+ c := make(chan error)
+ go func() {
+ err := i.Runtime.Build(getContext(), options, newPathDockerFiles...)
+ c <- err
+ close(c)
+ }()
+
var log []string
done := false
for {
@@ -257,23 +261,12 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
return call.ReplyBuildImage(br)
}
-func build(runtime *libpod.Runtime, options imagebuildah.BuildOptions, dockerfiles []string) chan error {
- c := make(chan error)
- go func() {
- err := runtime.Build(getContext(), options, dockerfiles...)
- c <- err
- close(c)
- }()
-
- return c
-}
-
// InspectImage returns an image's inspect information as a string that can be serialized.
// Requires an image ID or name
func (i *LibpodAPI) InspectImage(call iopodman.VarlinkCall, name string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
inspectInfo, err := newImage.Inspect(getContext())
if err != nil {
@@ -291,7 +284,7 @@ func (i *LibpodAPI) InspectImage(call iopodman.VarlinkCall, name string) error {
func (i *LibpodAPI) HistoryImage(call iopodman.VarlinkCall, name string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
history, err := newImage.History(getContext())
if err != nil {
@@ -320,7 +313,7 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe
)
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(err.Error())
+ return call.ReplyImageNotFound(name, err.Error())
}
destname := name
if tag != "" {
@@ -416,7 +409,7 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe
func (i *LibpodAPI) TagImage(call iopodman.VarlinkCall, name, tag string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
if err := newImage.TagImage(tag); err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -430,7 +423,7 @@ func (i *LibpodAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bo
ctx := getContext()
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
_, err = i.Runtime.RemoveImage(ctx, newImage, force)
if err != nil {
@@ -441,54 +434,53 @@ func (i *LibpodAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bo
// SearchImages searches all registries configured in /etc/containers/registries.conf for an image
// Requires an image name and a search limit as int
-func (i *LibpodAPI) SearchImages(call iopodman.VarlinkCall, query string, limit *int64, tlsVerify *bool) error {
- sc := image.GetSystemContext("", "", false)
+func (i *LibpodAPI) SearchImages(call iopodman.VarlinkCall, query string, limit *int64, tlsVerify *bool, filter iopodman.ImageSearchFilter) error {
+ // Transform all arguments to proper types first
+ argLimit := 0
+ argTLSVerify := types.OptionalBoolUndefined
+ argIsOfficial := types.OptionalBoolUndefined
+ argIsAutomated := types.OptionalBoolUndefined
+ if limit != nil {
+ argLimit = int(*limit)
+ }
if tlsVerify != nil {
- sc.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!*tlsVerify)
+ argTLSVerify = types.NewOptionalBool(!*tlsVerify)
+ }
+ if filter.Is_official != nil {
+ argIsOfficial = types.NewOptionalBool(*filter.Is_official)
+ }
+ if filter.Is_automated != nil {
+ argIsAutomated = types.NewOptionalBool(*filter.Is_automated)
}
- var registries []string
- // Check if search query has a registry in it
- registry, err := sysreg.GetRegistry(query)
- if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("error getting registry from %q: %q", query, err))
+ // Transform a SearchFilter the backend can deal with
+ sFilter := image.SearchFilter{
+ IsOfficial: argIsOfficial,
+ IsAutomated: argIsAutomated,
+ Stars: int(filter.Star_count),
}
- if registry != "" {
- registries = append(registries, registry)
- query = query[len(registry)+1:]
- } else {
- registries, err = sysreg.GetRegistries()
- if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to get system registries: %q", err))
- }
+
+ searchOptions := image.SearchOptions{
+ Limit: argLimit,
+ Filter: sFilter,
+ InsecureSkipTLSVerify: argTLSVerify,
+ }
+ results, err := image.SearchImages(query, searchOptions)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
}
+
var imageResults []iopodman.ImageSearchResult
- for _, reg := range registries {
- var lim = 1000
- if limit != nil {
- lim = int(*limit)
- }
- results, err := docker.SearchRegistry(getContext(), sc, reg, query, lim)
- if err != nil {
- // If we are searching multiple registries, don't make something like an
- // auth error fatal. Unfortunately we cannot differentiate between auth
- // errors and other possibles errors
- if len(registries) > 1 {
- continue
- }
- return call.ReplyErrorOccurred(err.Error())
- }
- for _, result := range results {
- i := iopodman.ImageSearchResult{
- Registry: reg,
- Description: result.Description,
- Is_official: result.IsOfficial,
- Is_automated: result.IsAutomated,
- Name: result.Name,
- Star_count: int64(result.StarCount),
- }
- imageResults = append(imageResults, i)
+ for _, result := range results {
+ i := iopodman.ImageSearchResult{
+ Registry: result.Index,
+ Description: result.Description,
+ Is_official: result.Official == "[OK]",
+ Is_automated: result.Automated == "[OK]",
+ Name: result.Name,
+ Star_count: int64(result.Stars),
}
+ imageResults = append(imageResults, i)
}
return call.ReplySearchImages(imageResults)
}
@@ -520,7 +512,7 @@ func (i *LibpodAPI) DeleteUnusedImages(call iopodman.VarlinkCall) error {
func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, changes []string, author, message string, pause bool, manifestType string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
sc := image.GetSystemContext(i.Runtime.GetConfig().SignaturePolicyPath, "", false)
var mimeType string
@@ -584,7 +576,7 @@ func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, me
func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination string, compress bool, tags []string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
additionalTags, err := image.GetAdditionalTags(tags)
@@ -622,24 +614,74 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, certDir, c
so := image.SigningOptions{}
- if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
- srcRef, err := alltransports.ParseImageName(name)
- if err != nil {
- return errors.Wrapf(err, "error parsing %q", name)
+ if call.WantsMore() {
+ call.Continues = true
+ }
+ output := bytes.NewBuffer([]byte{})
+ c := make(chan error)
+ go func() {
+ //err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, output, compress, so, &dockerRegistryOptions, nil)
+ if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
+ srcRef, err := alltransports.ParseImageName(name)
+ if err != nil {
+ c <- errors.Wrapf(err, "error parsing %q", name)
+ }
+ newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, signaturePolicy, output)
+ if err != nil {
+ c <- errors.Wrapf(err, "error pulling image from %q", name)
+ }
+ imageID = newImage[0].ID()
+ } else {
+ newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", output, &dockerRegistryOptions, so, false, nil)
+ if err != nil {
+ c <- errors.Wrapf(err, "unable to pull %s", name)
+ }
+ imageID = newImage.ID()
}
- newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, signaturePolicy, nil)
- if err != nil {
- return errors.Wrapf(err, "error pulling image from %q", name)
+ c <- nil
+ close(c)
+ }()
+
+ var log []string
+ done := false
+ for {
+ line, err := output.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Errorf("reading of output during pull failed for %s", name)
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ time.Sleep(1 * time.Second)
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyPullImage(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
}
- imageID = newImage[0].ID()
- } else {
- newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false, nil)
- if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s: %s", name, err.Error()))
+ if done {
+ break
}
- imageID = newImage.ID()
}
- return call.ReplyPullImage(imageID)
+ call.Continues = false
+
+ br := iopodman.MoreResponse{
+ Logs: log,
+ Id: imageID,
+ }
+ return call.ReplyPullImage(br)
}
// ImageExists returns bool as to whether the input image exists in local storage
@@ -694,3 +736,172 @@ func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall, all bool) error {
}
return call.ReplyImagesPrune(prunedImages)
}
+
+// ImageSave ....
+func (i *LibpodAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageSaveOptions) error {
+ newImage, err := i.Runtime.ImageRuntime().NewFromLocal(options.Name)
+ if err != nil {
+ if errors.Cause(err) == libpod.ErrNoSuchImage {
+ return call.ReplyImageNotFound(options.Name, err.Error())
+ }
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ // Determine if we are dealing with a tarball or dir
+ var output string
+ outputToDir := false
+ if options.Format == "oci-archive" || options.Format == "docker-archive" {
+ tempfile, err := ioutil.TempFile("", "varlink_send")
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ output = tempfile.Name()
+ tempfile.Close()
+ } else {
+ var err error
+ outputToDir = true
+ output, err = ioutil.TempDir("", "varlink_send")
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ }
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if call.WantsMore() {
+ call.Continues = true
+ }
+
+ saveOutput := bytes.NewBuffer([]byte{})
+ c := make(chan error)
+ go func() {
+ err := newImage.Save(getContext(), options.Name, options.Format, output, options.MoreTags, options.Quiet, options.Compress)
+ c <- err
+ close(c)
+ }()
+ var log []string
+ done := false
+ for {
+ line, err := saveOutput.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Errorf("reading of output during save failed for %s", newImage.ID())
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ time.Sleep(1 * time.Second)
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyImageSave(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if done {
+ break
+ }
+ }
+ call.Continues = false
+
+ sendfile := output
+ // Image has been saved to `output`
+ if outputToDir {
+ // If the output is a directory, we need to tar up the directory to send it back
+ //Create a tempfile for the directory tarball
+ outputFile, err := ioutil.TempFile("", "varlink_save_dir")
+ if err != nil {
+ return err
+ }
+ defer outputFile.Close()
+ if err := utils.TarToFilesystem(output, outputFile); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ sendfile = outputFile.Name()
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ Id: sendfile,
+ }
+ return call.ReplyPushImage(br)
+}
+
+// LoadImage ...
+func (i *LibpodAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string, deleteInputFile, quiet bool) error {
+ var (
+ names string
+ writer io.Writer
+ err error
+ )
+ if !quiet {
+ writer = os.Stderr
+ }
+
+ if call.WantsMore() {
+ call.Continues = true
+ }
+ output := bytes.NewBuffer([]byte{})
+
+ c := make(chan error)
+ go func() {
+ names, err = i.Runtime.LoadImage(getContext(), name, inputFile, writer, "")
+ c <- err
+ close(c)
+ }()
+
+ var log []string
+ done := false
+ for {
+ line, err := output.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Error(err)
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ time.Sleep(1 * time.Second)
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyLoadImage(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if done {
+ break
+ }
+ }
+ call.Continues = false
+
+ br := iopodman.MoreResponse{
+ Logs: log,
+ Id: names,
+ }
+ if deleteInputFile {
+ if err := os.Remove(inputFile); err != nil {
+ logrus.Errorf("unable to delete input file %s", inputFile)
+ }
+ }
+ return call.ReplyLoadImage(br)
+}