aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_create.go10
-rw-r--r--pkg/api/handlers/compat/images.go121
-rw-r--r--pkg/api/handlers/compat/images_history.go4
-rw-r--r--pkg/api/handlers/compat/images_prune.go8
-rw-r--r--pkg/api/handlers/compat/images_remove.go4
-rw-r--r--pkg/api/handlers/compat/images_search.go4
-rw-r--r--pkg/api/handlers/compat/images_tag.go8
-rw-r--r--pkg/api/handlers/libpod/images.go106
-rw-r--r--pkg/api/handlers/libpod/images_pull.go144
-rw-r--r--pkg/api/handlers/libpod/manifests.go69
-rw-r--r--pkg/api/handlers/libpod/system.go44
-rw-r--r--pkg/api/handlers/swagger/swagger.go21
-rw-r--r--pkg/api/handlers/types.go92
-rw-r--r--pkg/api/handlers/utils/errors.go3
-rw-r--r--pkg/api/handlers/utils/images.go62
-rw-r--r--pkg/autoupdate/autoupdate.go57
-rw-r--r--pkg/bindings/images/pull.go4
-rw-r--r--pkg/bindings/test/images_test.go4
-rw-r--r--pkg/bindings/test/system_test.go11
-rw-r--r--pkg/checkpoint/checkpoint_restore.go36
-rw-r--r--pkg/domain/entities/manifest.go1
-rw-r--r--pkg/domain/infra/abi/containers.go16
-rw-r--r--pkg/domain/infra/abi/containers_runlabel.go86
-rw-r--r--pkg/domain/infra/abi/images.go582
-rw-r--r--pkg/domain/infra/abi/images_list.go61
-rw-r--r--pkg/domain/infra/abi/manifest.go327
-rw-r--r--pkg/domain/infra/abi/play.go59
-rw-r--r--pkg/domain/infra/abi/system.go21
-rw-r--r--pkg/domain/infra/tunnel/images.go4
-rw-r--r--pkg/errorhandling/errorhandling.go6
-rw-r--r--pkg/ps/ps.go8
-rw-r--r--pkg/specgen/config_unsupported.go4
-rw-r--r--pkg/specgen/generate/config_linux_cgo.go4
-rw-r--r--pkg/specgen/generate/config_linux_nocgo.go4
-rw-r--r--pkg/specgen/generate/container.go93
-rw-r--r--pkg/specgen/generate/container_create.go43
-rw-r--r--pkg/specgen/generate/kube/kube.go6
-rw-r--r--pkg/specgen/generate/namespaces.go8
-rw-r--r--pkg/specgen/generate/oci.go22
-rw-r--r--pkg/specgen/generate/ports.go14
-rw-r--r--pkg/specgen/generate/security.go4
-rw-r--r--pkg/specgen/generate/storage.go8
-rw-r--r--pkg/util/utils.go17
43 files changed, 995 insertions, 1215 deletions
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 93934f1de..162a98135 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -6,12 +6,12 @@ import (
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/podman/v3/pkg/specgen"
+ "github.com/containers/storage"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -50,14 +50,14 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
return
}
- newImage, err := runtime.ImageRuntime().NewFromLocal(body.Config.Image)
+ newImage, resolvedName, err := runtime.LibimageRuntime().LookupImage(body.Config.Image, nil)
if err != nil {
- if errors.Cause(err) == define.ErrNoSuchImage {
+ if errors.Cause(err) == storage.ErrImageUnknown {
utils.Error(w, "No such image", http.StatusNotFound, err)
return
}
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "NewFromLocal()"))
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error looking up image"))
return
}
@@ -71,7 +71,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
imgNameOrID := newImage.ID()
// if the img had multi names with the same sha256 ID, should use the InputName, not the ID
if len(newImage.Names()) > 1 {
- imageRef, err := utils.ParseDockerReference(newImage.InputName)
+ imageRef, err := utils.ParseDockerReference(resolvedName)
if err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
return
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index e5caa9ea5..0b9367a17 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -4,23 +4,24 @@ import (
"context"
"encoding/json"
"fmt"
- "io"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/containers/buildah"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
- image2 "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/auth"
"github.com/containers/podman/v3/pkg/channel"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/containers/podman/v3/pkg/util"
+ "github.com/containers/podman/v3/pkg/domain/infra/abi"
+ "github.com/containers/storage"
"github.com/gorilla/schema"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
@@ -47,26 +48,35 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
// 500 server
runtime := r.Context().Value("runtime").(*libpod.Runtime)
- name := utils.GetName(r)
- newImage, err := runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
- return
- }
tmpfile, err := ioutil.TempFile("", "api.tar")
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
return
}
defer os.Remove(tmpfile.Name())
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
+
+ name := utils.GetName(r)
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ saveOptions := entities.ImageSaveOptions{
+ Format: "docker-archive",
+ Output: tmpfile.Name(),
+ }
+
+ if err := imageEngine.Save(r.Context(), name, nil, saveOptions); err != nil {
+ if errors.Cause(err) == storage.ErrImageUnknown {
+ utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
+ return
+ }
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
return
}
- if err := newImage.Save(r.Context(), name, "docker-archive", tmpfile.Name(), []string{}, false, false, true); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to save image"))
+
+ if err := tmpfile.Close(); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
return
}
+
rdr, err := os.Open(tmpfile.Name())
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to read the exported tarfile"))
@@ -105,7 +115,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
- sc := image2.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
+ sc := runtime.SystemContext()
tag := "latest"
options := libpod.ContainerCommitOptions{
Pause: true,
@@ -180,20 +190,13 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file"))
}
}
- iid, err := runtime.Import(r.Context(), source, "", "", query.Changes, "", false)
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+ report, err := imageEngine.Import(r.Context(), entities.ImageImportOptions{Source: source, Changes: query.Changes})
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to import tarball"))
return
}
- tmpfile, err := ioutil.TempFile("", "fromsrc.tar")
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
- return
- }
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
- return
- }
// Success
utils.WriteResponse(w, http.StatusOK, struct {
Status string `json:"status"`
@@ -201,9 +204,9 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
ProgressDetail map[string]string `json:"progressDetail"`
Id string `json:"id"` // nolint
}{
- Status: iid,
+ Status: report.Id,
ProgressDetail: map[string]string{},
- Id: iid,
+ Id: report.Id,
})
}
@@ -235,36 +238,34 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
}
defer auth.RemoveAuthfile(authfile)
- registryOpts := image2.DockerRegistryOptions{DockerRegistryCreds: authConf}
- if sys := runtime.SystemContext(); sys != nil {
- registryOpts.DockerCertPath = sys.DockerCertPath
+ pullOptions := &libimage.PullOptions{}
+ pullOptions.AuthFilePath = authfile
+ if authConf != nil {
+ pullOptions.Username = authConf.Username
+ pullOptions.Password = authConf.Password
+ pullOptions.IdentityToken = authConf.IdentityToken
}
+ pullOptions.Writer = os.Stderr // allows for debugging on the server
stderr := channel.NewWriter(make(chan []byte))
defer stderr.Close()
progress := make(chan types.ProgressProperties)
+ pullOptions.Progress = progress
var img string
runCtx, cancel := context.WithCancel(context.Background())
go func() {
defer cancel()
-
- newImage, err := runtime.ImageRuntime().New(
- runCtx,
- fromImage,
- "", // signature policy
- authfile,
- nil, // writer
- &registryOpts,
- image2.SigningOptions{},
- nil, // label
- util.PullImageAlways,
- progress)
+ pulledImages, err := runtime.LibimageRuntime().Pull(runCtx, fromImage, config.PullPolicyAlways, pullOptions)
if err != nil {
stderr.Write([]byte(err.Error() + "\n"))
} else {
- img = newImage.ID()
+ if len(pulledImages) == 0 {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.New("internal error: no images pulled"))
+ return
+ }
+ img = pulledImages[0].ID()
}
}()
@@ -347,7 +348,7 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
if err != nil {
// Here we need to fiddle with the error message because docker-py is looking for "No
// such image" to determine on how to raise the correct exception.
- errMsg := strings.ReplaceAll(err.Error(), "no such image", "No such image")
+ errMsg := strings.ReplaceAll(err.Error(), "image not known", "No such image")
utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Errorf("failed to find image %s: %s", name, errMsg))
return
}
@@ -379,13 +380,14 @@ func GetImages(w http.ResponseWriter, r *http.Request) {
func LoadImages(w http.ResponseWriter, r *http.Request) {
// TODO this is basically wrong
+ // TODO ... improve these ^ messages to something useful
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
query := struct {
- Changes map[string]string `json:"changes"`
- Message string `json:"message"`
- Quiet bool `json:"quiet"`
+ Changes map[string]string `json:"changes"` // Ignored
+ Message string `json:"message"` // Ignored
+ Quiet bool `json:"quiet"` // Ignored
}{
// This is where you can override the golang default value for one of fields
}
@@ -395,10 +397,8 @@ func LoadImages(w http.ResponseWriter, r *http.Request) {
return
}
- var (
- err error
- writer io.Writer
- )
+ // First write the body to a temporary file that we can later attempt
+ // to load.
f, err := ioutil.TempFile("", "api_load.tar")
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile"))
@@ -414,15 +414,25 @@ func LoadImages(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file"))
return
}
- id, err := runtime.LoadImage(r.Context(), f.Name(), writer, "")
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ loadOptions := entities.ImageLoadOptions{Input: f.Name()}
+ loadReport, err := imageEngine.Load(r.Context(), loadOptions)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to load image"))
return
}
+
+ if len(loadReport.Names) != 1 {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Errorf("%d instead of 1 were loaded", len(loadReport.Names)))
+ return
+ }
+
utils.WriteResponse(w, http.StatusOK, struct {
Stream string `json:"stream"`
}{
- Stream: fmt.Sprintf("Loaded image: %s\n", id),
+ Stream: fmt.Sprintf("Loaded image: %s\n", loadReport.Names[0]),
})
}
@@ -453,10 +463,15 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
return
}
- if err := runtime.ImageRuntime().SaveImages(r.Context(), images, "docker-archive", tmpfile.Name(), false, true); err != nil {
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ saveOptions := entities.ImageSaveOptions{Output: tmpfile.Name()}
+ if err := imageEngine.Save(r.Context(), images[0], images[1:], saveOptions); err != nil {
utils.InternalServerError(w, err)
return
}
+
rdr, err := os.Open(tmpfile.Name())
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to read the exported tarfile"))
diff --git a/pkg/api/handlers/compat/images_history.go b/pkg/api/handlers/compat/images_history.go
index a02ed179c..ea596890f 100644
--- a/pkg/api/handlers/compat/images_history.go
+++ b/pkg/api/handlers/compat/images_history.go
@@ -3,6 +3,7 @@ package compat
import (
"net/http"
+ "github.com/containers/common/libimage"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
@@ -13,7 +14,8 @@ func HistoryImage(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
- newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+ lookupOptions := &libimage.LookupImageOptions{IgnorePlatform: true}
+ newImage, _, err := runtime.LibimageRuntime().LookupImage(name, lookupOptions)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name))
return
diff --git a/pkg/api/handlers/compat/images_prune.go b/pkg/api/handlers/compat/images_prune.go
index ddf559ec6..bbbfb5577 100644
--- a/pkg/api/handlers/compat/images_prune.go
+++ b/pkg/api/handlers/compat/images_prune.go
@@ -8,6 +8,8 @@ import (
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
+ "github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/podman/v3/pkg/util"
"github.com/docker/docker/api/types"
"github.com/pkg/errors"
@@ -30,7 +32,11 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
filters = append(filters, fmt.Sprintf("%s=%s", k, val))
}
}
- imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), false, filters)
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ pruneOptions := entities.ImagePruneOptions{Filter: filters}
+ imagePruneReports, err := imageEngine.Prune(r.Context(), pruneOptions)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/compat/images_remove.go b/pkg/api/handlers/compat/images_remove.go
index e89558a86..390f25caf 100644
--- a/pkg/api/handlers/compat/images_remove.go
+++ b/pkg/api/handlers/compat/images_remove.go
@@ -4,10 +4,10 @@ import (
"net/http"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
+ "github.com/containers/storage"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -41,7 +41,7 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) {
report, rmerrors := imageEngine.Remove(r.Context(), []string{name}, options)
if len(rmerrors) > 0 && rmerrors[0] != nil {
err := rmerrors[0]
- if errors.Cause(err) == define.ErrNoSuchImage {
+ if errors.Cause(err) == storage.ErrImageUnknown {
utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
return
}
diff --git a/pkg/api/handlers/compat/images_search.go b/pkg/api/handlers/compat/images_search.go
index 18974f424..13a3693fa 100644
--- a/pkg/api/handlers/compat/images_search.go
+++ b/pkg/api/handlers/compat/images_search.go
@@ -6,11 +6,11 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/auth"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
+ "github.com/containers/storage"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -64,7 +64,7 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
}
if !utils.IsLibpodRequest(r) {
if len(reports) == 0 {
- utils.ImageNotFound(w, query.Term, define.ErrNoSuchImage)
+ utils.ImageNotFound(w, query.Term, storage.ErrImageUnknown)
return
}
}
diff --git a/pkg/api/handlers/compat/images_tag.go b/pkg/api/handlers/compat/images_tag.go
index 0d0c204f3..8d256f4fa 100644
--- a/pkg/api/handlers/compat/images_tag.go
+++ b/pkg/api/handlers/compat/images_tag.go
@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
+ "github.com/containers/common/libimage"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/pkg/errors"
@@ -14,11 +15,14 @@ func TagImage(w http.ResponseWriter, r *http.Request) {
// /v1.xx/images/(name)/tag
name := utils.GetName(r)
- newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+
+ lookupOptions := &libimage.LookupImageOptions{IgnorePlatform: true}
+ newImage, _, err := runtime.LibimageRuntime().LookupImage(name, lookupOptions)
if err != nil {
utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
return
}
+
tag := "latest"
if len(r.Form.Get("tag")) > 0 {
tag = r.Form.Get("tag")
@@ -29,7 +33,7 @@ func TagImage(w http.ResponseWriter, r *http.Request) {
}
repo := r.Form.Get("repo")
tagName := fmt.Sprintf("%s:%s", repo, tag)
- if err := newImage.TagImage(tagName); err != nil {
+ if err := newImage.Tag(tagName); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 92882cc40..a90408bfd 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -11,11 +11,12 @@ import (
"strings"
"github.com/containers/buildah"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/filters"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/auth"
@@ -24,6 +25,7 @@ import (
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/util"
utils2 "github.com/containers/podman/v3/utils"
+ "github.com/containers/storage"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -74,7 +76,7 @@ func ImageTree(w http.ResponseWriter, r *http.Request) {
options := entities.ImageTreeOptions{WhatRequires: query.WhatRequires}
report, err := ir.Tree(r.Context(), name, options)
if err != nil {
- if errors.Cause(err) == define.ErrNoSuchImage {
+ if errors.Cause(err) == storage.ErrImageUnknown {
utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name))
return
}
@@ -91,7 +93,7 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name))
return
}
- inspect, err := newImage.Inspect(r.Context())
+ inspect, err := newImage.Inspect(r.Context(), true)
if err != nil {
utils.Error(w, "Server error", http.StatusInternalServerError, errors.Wrapf(err, "failed in inspect image %s", inspect.ID))
return
@@ -100,22 +102,44 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
}
func GetImages(w http.ResponseWriter, r *http.Request) {
- images, err := utils.GetImages(w, r)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ query := struct {
+ All bool
+ Digests bool
+ Filter string // Docker 1.24 compatibility
+ }{
+ // This is where you can override the golang default value for one of fields
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+ if _, found := r.URL.Query()["digests"]; found && query.Digests {
+ utils.UnSupportedParameter("digests")
+ return
+ }
+
+ filterList, err := filters.FiltersFromRequest(r)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed get images"))
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- var summaries = make([]*entities.ImageSummary, len(images))
- for j, img := range images {
- is, err := handlers.ImageToImageSummary(img)
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed transform image summaries"))
- return
- }
- // libpod has additional fields that we need to populate.
- is.ReadOnly = img.IsReadOnly()
- summaries[j] = is
+ if !utils.IsLibpodRequest(r) && len(query.Filter) > 0 { // Docker 1.24 compatibility
+ filterList = append(filterList, "reference="+query.Filter)
}
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ listOptions := entities.ImageListOptions{All: query.All, Filter: filterList}
+ summaries, err := imageEngine.List(r.Context(), listOptions)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
+ return
+ }
+
utils.WriteResponse(w, http.StatusOK, summaries)
}
@@ -135,7 +159,8 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
if dErr := decoder.Decode(&query, r.URL.Query()); dErr != nil || err != nil {
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
- errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ errors.
+ Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
@@ -156,7 +181,13 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
}
}
- imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ pruneOptions := entities.ImagePruneOptions{
+ All: query.All,
+ Filter: libpodFilters,
+ }
+ imagePruneReports, err := imageEngine.Prune(r.Context(), pruneOptions)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
@@ -183,11 +214,13 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
return
}
name := utils.GetName(r)
- newImage, err := runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
+
+ lookupOptions := &libimage.LookupImageOptions{IgnorePlatform: true}
+ if _, _, err := runtime.LibimageRuntime().LookupImage(name, lookupOptions); err != nil {
utils.ImageNotFound(w, name, err)
return
}
+
switch query.Format {
case define.OCIArchive, define.V2s2Archive:
tmpfile, err := ioutil.TempFile("", "api.tar")
@@ -211,7 +244,15 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "unknown format", http.StatusInternalServerError, errors.Errorf("unknown format %q", query.Format))
return
}
- if err := newImage.Save(r.Context(), name, query.Format, output, []string{}, false, query.Compress, true); err != nil {
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ saveOptions := entities.ImageSaveOptions{
+ Compress: query.Compress,
+ Format: query.Format,
+ Output: output,
+ }
+ if err := imageEngine.Save(r.Context(), name, nil, saveOptions); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
return
}
@@ -347,12 +388,15 @@ func ImagesLoad(w http.ResponseWriter, r *http.Request) {
return
}
- loadedImage, err := runtime.LoadImage(context.Background(), tmpfile.Name(), os.Stderr, "")
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ loadOptions := entities.ImageLoadOptions{Input: tmpfile.Name()}
+ loadReport, err := imageEngine.Load(r.Context(), loadOptions)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to load image"))
return
}
- utils.WriteResponse(w, http.StatusOK, entities.ImageLoadReport{Names: strings.Split(loadedImage, ",")})
+ utils.WriteResponse(w, http.StatusOK, loadReport)
}
func ImagesImport(w http.ResponseWriter, r *http.Request) {
@@ -392,13 +436,21 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) {
tmpfile.Close()
source = tmpfile.Name()
}
- importedImage, err := runtime.Import(context.Background(), source, query.Reference, "", query.Changes, query.Message, true)
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+ importOptions := entities.ImageImportOptions{
+ Changes: query.Changes,
+ Message: query.Message,
+ Reference: query.Reference,
+ Source: source,
+ }
+ report, err := imageEngine.Import(r.Context(), importOptions)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to import image"))
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to import tarball"))
return
}
- utils.WriteResponse(w, http.StatusOK, entities.ImageImportReport{Id: importedImage})
+ utils.WriteResponse(w, http.StatusOK, report)
}
// PushImage is the handler for the compat http endpoint for pushing images.
@@ -497,7 +549,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "failed to get runtime config", http.StatusInternalServerError, errors.Wrap(err, "failed to get runtime config"))
return
}
- sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
+ sc := runtime.SystemContext()
tag := "latest"
options := libpod.ContainerCommitOptions{
Pause: true,
@@ -579,7 +631,7 @@ func UntagImage(w http.ResponseWriter, r *http.Request) {
name := utils.GetName(r)
if err := imageEngine.Untag(r.Context(), name, tags, opts); err != nil {
- if errors.Cause(err) == define.ErrNoSuchImage {
+ if errors.Cause(err) == storage.ErrImageUnknown {
utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
} else {
utils.Error(w, "failed to untag", http.StatusInternalServerError, err)
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
index e2e4b53b4..7545ba235 100644
--- a/pkg/api/handlers/libpod/images_pull.go
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -3,20 +3,16 @@ package libpod
import (
"context"
"encoding/json"
- "fmt"
"net/http"
- "strings"
- "github.com/containers/image/v5/docker"
- "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/auth"
"github.com/containers/podman/v3/pkg/channel"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/containers/podman/v3/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -51,28 +47,23 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
return
}
- imageRef, err := utils.ParseDockerReference(query.Reference)
- if err != nil {
+ // Make sure that the reference has no transport or the docker one.
+ if _, err := utils.ParseDockerReference(query.Reference); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
return
}
- // Trim the docker-transport prefix.
- rawImage := strings.TrimPrefix(query.Reference, fmt.Sprintf("%s://", docker.Transport.Name()))
+ pullOptions := &libimage.PullOptions{}
+ pullOptions.AllTags = query.AllTags
+ pullOptions.Architecture = query.Arch
+ pullOptions.OS = query.OS
+ pullOptions.Variant = query.Variant
- // all-tags doesn't work with a tagged reference, so let's check early
- namedRef, err := reference.Parse(rawImage)
- if err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "error parsing reference %q", rawImage))
- return
- }
- if _, isTagged := namedRef.(reference.Tagged); isTagged && query.AllTags {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Errorf("reference %q must not have a tag for all-tags", rawImage))
- return
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ pullOptions.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
}
+ // Do the auth dance.
authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String()))
@@ -80,71 +71,25 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
}
defer auth.RemoveAuthfile(authfile)
- // Setup the registry options
- dockerRegistryOptions := image.DockerRegistryOptions{
- DockerRegistryCreds: authConf,
- OSChoice: query.OS,
- ArchitectureChoice: query.Arch,
- VariantChoice: query.Variant,
- }
- if _, found := r.URL.Query()["tlsVerify"]; found {
- dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
- }
-
- sys := runtime.SystemContext()
- if sys == nil {
- sys = image.GetSystemContext("", authfile, false)
- }
- dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
- sys.DockerAuthConfig = authConf
-
- // Prepare the images we want to pull
- imagesToPull := []string{}
- imageName := namedRef.String()
-
- if !query.AllTags {
- imagesToPull = append(imagesToPull, imageName)
- } else {
- tags, err := docker.GetRepositoryTags(context.Background(), sys, imageRef)
- if err != nil {
- utils.InternalServerError(w, errors.Wrap(err, "error getting repository tags"))
- return
- }
- for _, tag := range tags {
- imagesToPull = append(imagesToPull, fmt.Sprintf("%s:%s", imageName, tag))
- }
+ pullOptions.AuthFilePath = authfile
+ if authConf != nil {
+ pullOptions.Username = authConf.Username
+ pullOptions.Password = authConf.Password
+ pullOptions.IdentityToken = authConf.IdentityToken
}
writer := channel.NewWriter(make(chan []byte))
defer writer.Close()
- stderr := channel.NewWriter(make(chan []byte))
- defer stderr.Close()
+ pullOptions.Writer = writer
- images := make([]string, 0, len(imagesToPull))
+ var pulledImages []*libimage.Image
+ var pullError error
runCtx, cancel := context.WithCancel(context.Background())
- go func(imgs []string) {
+ go func() {
defer cancel()
- // Finally pull the images
- for _, img := range imgs {
- newImage, err := runtime.ImageRuntime().New(
- runCtx,
- img,
- "",
- authfile,
- writer,
- &dockerRegistryOptions,
- image.SigningOptions{},
- nil,
- util.PullImageAlways,
- nil)
- if err != nil {
- stderr.Write([]byte(err.Error() + "\n"))
- } else {
- images = append(images, newImage.ID())
- }
- }
- }(imagesToPull)
+ pulledImages, pullError = runtime.LibimageRuntime().Pull(runCtx, query.Reference, config.PullPolicyAlways, pullOptions)
+ }()
flush := func() {
if flusher, ok := w.(http.Flusher); ok {
@@ -158,45 +103,32 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
enc := json.NewEncoder(w)
enc.SetEscapeHTML(true)
- var failed bool
-loop: // break out of for/select infinite loop
for {
var report entities.ImagePullReport
select {
- case e := <-writer.Chan():
- report.Stream = string(e)
- if err := enc.Encode(report); err != nil {
- stderr.Write([]byte(err.Error()))
- }
- flush()
- case e := <-stderr.Chan():
- failed = true
- report.Error = string(e)
+ case s := <-writer.Chan():
+ report.Stream = string(s)
if err := enc.Encode(report); err != nil {
- logrus.Warnf("Failed to json encode error %q", err.Error())
+ logrus.Warnf("Failed to encode json: %v", err)
}
flush()
case <-runCtx.Done():
- if !failed {
- // Send all image id's pulled in 'images' stanza
- report.Images = images
- if err := enc.Encode(report); err != nil {
- logrus.Warnf("Failed to json encode error %q", err.Error())
- }
-
- report.Images = nil
+ for _, image := range pulledImages {
+ report.Images = append(report.Images, image.ID())
// Pull last ID from list and publish in 'id' stanza. This maintains previous API contract
- report.ID = images[len(images)-1]
- if err := enc.Encode(report); err != nil {
- logrus.Warnf("Failed to json encode error %q", err.Error())
- }
-
- flush()
+ report.ID = image.ID()
+ }
+ if pullError != nil {
+ report.Error = pullError.Error()
+ }
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to encode json: %v", err)
}
- break loop // break out of for/select infinite loop
+ flush()
+ return
case <-r.Context().Done():
// Client has closed connection
- break loop // break out of for/select infinite loop
+ return
}
}
}
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index 6a491ae48..f21eb2e80 100644
--- a/pkg/api/handlers/libpod/manifests.go
+++ b/pkg/api/handlers/libpod/manifests.go
@@ -9,7 +9,6 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/auth"
@@ -45,13 +44,10 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
}
}
- rtc, err := runtime.GetConfig()
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
- manID, err := image.CreateManifestList(runtime.ImageRuntime(), *sc, query.Name, query.Image, query.All)
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ createOptions := entities.ManifestCreateOptions{All: query.All}
+ manID, err := imageEngine.ManifestCreate(r.Context(), query.Name, query.Image, createOptions)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -64,8 +60,8 @@ func ExistsManifest(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
- ic := abi.ImageEngine{Libpod: runtime}
- report, err := ic.ManifestExists(r.Context(), name)
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+ report, err := imageEngine.ManifestExists(r.Context(), name)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
@@ -80,45 +76,46 @@ func ExistsManifest(w http.ResponseWriter, r *http.Request) {
func ManifestInspect(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
+
imageEngine := abi.ImageEngine{Libpod: runtime}
- inspectReport, inspectError := imageEngine.ManifestInspect(r.Context(), name)
- if inspectError != nil {
- utils.Error(w, "Something went wrong.", http.StatusNotFound, inspectError)
+ rawManifest, err := imageEngine.ManifestInspect(r.Context(), name)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusNotFound, err)
return
}
- var list manifest.Schema2List
- if err := json.Unmarshal(inspectReport, &list); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Unmarshal()"))
+ var schema2List manifest.Schema2List
+ if err := json.Unmarshal(rawManifest, &schema2List); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- if list.Manifests == nil {
- list.Manifests = make([]manifest.Schema2ManifestDescriptor, 0)
- }
- utils.WriteResponse(w, http.StatusOK, &list)
+ utils.WriteResponse(w, http.StatusOK, schema2List)
}
func ManifestAdd(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
- var manifestInput image.ManifestAddOpts
- if err := json.NewDecoder(r.Body).Decode(&manifestInput); err != nil {
+ var addOptions entities.ManifestAddOptions
+ if err := json.NewDecoder(r.Body).Decode(&addOptions); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
+
name := utils.GetName(r)
- newImage, err := runtime.ImageRuntime().NewFromLocal(name)
- if err != nil {
- utils.ImageNotFound(w, name, err)
+ if _, err := runtime.LibimageRuntime().LookupManifestList(name); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusNotFound, err)
return
}
- rtc, err := runtime.GetConfig()
- if err != nil {
- utils.InternalServerError(w, err)
- return
+
+ // FIXME: we really need to clean up the manifest API. Swagger states
+ // the arguments were strings not string slices. The use of string
+ // slices, mixing lists and images is incredibly confusing.
+ if len(addOptions.Images) == 1 {
+ addOptions.Images = append(addOptions.Images, name)
}
- sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
- newID, err := newImage.AddManifest(*sc, manifestInput)
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+ newID, err := imageEngine.ManifestAdd(r.Context(), addOptions)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -140,9 +137,9 @@ func ManifestRemove(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- newImage, err := runtime.ImageRuntime().NewFromLocal(name)
+ manifestList, err := runtime.LibimageRuntime().LookupManifestList(name)
if err != nil {
- utils.ImageNotFound(w, name, err)
+ utils.Error(w, "Something went wrong.", http.StatusNotFound, err)
return
}
d, err := digest.Parse(query.Digest)
@@ -150,13 +147,13 @@ func ManifestRemove(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "invalid digest", http.StatusBadRequest, err)
return
}
- newID, err := newImage.RemoveManifest(d)
- if err != nil {
+ if err := manifestList.RemoveInstance(d); err != nil {
utils.InternalServerError(w, err)
return
}
- utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: newID})
+ utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: manifestList.ID()})
}
+
func ManifestPush(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
diff --git a/pkg/api/handlers/libpod/system.go b/pkg/api/handlers/libpod/system.go
index 2b4cef1bb..bca92a4af 100644
--- a/pkg/api/handlers/libpod/system.go
+++ b/pkg/api/handlers/libpod/system.go
@@ -4,21 +4,19 @@ import (
"net/http"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/pkg/api/handlers/compat"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
+ "github.com/containers/podman/v3/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
// SystemPrune removes unused data
func SystemPrune(w http.ResponseWriter, r *http.Request) {
- var (
- decoder = r.Context().Value("decoder").(*schema.Decoder)
- runtime = r.Context().Value("runtime").(*libpod.Runtime)
- systemPruneReport = new(entities.SystemPruneReport)
- )
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+
query := struct {
All bool `schema:"all"`
Volumes bool `schema:"volumes"`
@@ -29,39 +27,27 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
-
- podPruneReport, err := PodPruneHelper(r)
+ filterMap, err := util.PrepareFilters(r)
if err != nil {
- utils.InternalServerError(w, err)
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- systemPruneReport.PodPruneReport = podPruneReport
- // We could parallelize this, should we?
- containerPruneReports, err := compat.PruneContainersHelper(r, nil)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- systemPruneReport.ContainerPruneReports = containerPruneReports
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
- imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
+ pruneOptions := entities.SystemPruneOptions{
+ All: query.All,
+ Volume: query.Volumes,
+ Filters: *filterMap,
+ }
+ report, err := containerEngine.SystemPrune(r.Context(), pruneOptions)
if err != nil {
utils.InternalServerError(w, err)
return
}
- systemPruneReport.ImagePruneReports = imagePruneReports
-
- if query.Volumes {
- volumePruneReports, err := pruneVolumesHelper(r)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- systemPruneReport.VolumePruneReports = volumePruneReports
- }
- utils.WriteResponse(w, http.StatusOK, systemPruneReport)
+ utils.WriteResponse(w, http.StatusOK, report)
}
func DiskUsage(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/api/handlers/swagger/swagger.go b/pkg/api/handlers/swagger/swagger.go
index 384e06cac..ef3d12df8 100644
--- a/pkg/api/handlers/swagger/swagger.go
+++ b/pkg/api/handlers/swagger/swagger.go
@@ -2,7 +2,6 @@ package swagger
import (
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/inspect"
@@ -66,7 +65,10 @@ type swagLibpodPlayKubeResponse struct {
// swagger:response DocsImageDeleteResponse
type swagImageDeleteResponse struct {
// in:body
- Body []image.ImageDeleteResponse
+ Body []struct {
+ Untagged []string `json:"untagged"`
+ Deleted string `json:"deleted"`
+ }
}
// Search results
@@ -74,7 +76,20 @@ type swagImageDeleteResponse struct {
type swagSearchResponse struct {
// in:body
Body struct {
- image.SearchResult
+ // Index is the image index (e.g., "docker.io" or "quay.io")
+ Index string
+ // Name is the canonical name of the image (e.g., "docker.io/library/alpine").
+ Name string
+ // Description of the image.
+ Description string
+ // Stars is the number of stars of the image.
+ Stars int
+ // Official indicates if it's an official image.
+ Official string
+ // Automated indicates if the image was created by an automated build.
+ Automated string
+ // Tag is the image tag
+ Tag string
}
}
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 736203171..52d7633af 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -2,12 +2,9 @@ package handlers
import (
"context"
- "encoding/json"
- "fmt"
"time"
- "github.com/containers/image/v5/manifest"
- libpodImage "github.com/containers/podman/v3/libpod/image"
+ "github.com/containers/common/libimage"
"github.com/containers/podman/v3/pkg/domain/entities"
docker "github.com/docker/docker/api/types"
dockerContainer "github.com/docker/docker/api/types/container"
@@ -173,8 +170,8 @@ type ExecStartConfig struct {
Tty bool `json:"Tty"`
}
-func ImageToImageSummary(l *libpodImage.Image) (*entities.ImageSummary, error) {
- imageData, err := l.Inspect(context.TODO())
+func ImageToImageSummary(l *libimage.Image) (*entities.ImageSummary, error) {
+ imageData, err := l.Inspect(context.TODO(), true)
if err != nil {
return nil, errors.Wrapf(err, "failed to obtain summary for image %s", l.ID())
}
@@ -197,17 +194,17 @@ func ImageToImageSummary(l *libpodImage.Image) (*entities.ImageSummary, error) {
Labels: imageData.Labels,
Containers: containerCount,
ReadOnly: l.IsReadOnly(),
- Dangling: l.Dangling(),
+ Dangling: l.IsDangling(),
Names: l.Names(),
Digest: string(imageData.Digest),
- ConfigDigest: string(l.ConfigDigest),
+ ConfigDigest: "", // TODO: libpod/image didn't set it but libimage should
History: imageData.NamesHistory,
}
return &is, nil
}
-func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageInspect, error) {
- info, err := l.Inspect(context.Background())
+func ImageDataToImageInspect(ctx context.Context, l *libimage.Image) (*ImageInspect, error) {
+ info, err := l.Inspect(context.Background(), true)
if err != nil {
return nil, err
}
@@ -216,37 +213,17 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
return nil, err
}
- // TODO the rest of these still need wiring!
+ // TODO: many fields in Config still need wiring
config := dockerContainer.Config{
- // Hostname: "",
- // Domainname: "",
- User: info.User,
- // AttachStdin: false,
- // AttachStdout: false,
- // AttachStderr: false,
+ User: info.User,
ExposedPorts: ports,
- // Tty: false,
- // OpenStdin: false,
- // StdinOnce: false,
- Env: info.Config.Env,
- Cmd: info.Config.Cmd,
- // Healthcheck: l.ImageData.HealthCheck,
- // ArgsEscaped: false,
- // Image: "",
- Volumes: info.Config.Volumes,
- WorkingDir: info.Config.WorkingDir,
- Entrypoint: info.Config.Entrypoint,
- // NetworkDisabled: false,
- // MacAddress: "",
- // OnBuild: info.Config.OnBuild,
- Labels: info.Labels,
- StopSignal: info.Config.StopSignal,
- // StopTimeout: nil,
- // Shell: nil,
- }
- ic, err := l.ToImageRef(ctx)
- if err != nil {
- return nil, err
+ Env: info.Config.Env,
+ Cmd: info.Config.Cmd,
+ Volumes: info.Config.Volumes,
+ WorkingDir: info.Config.WorkingDir,
+ Entrypoint: info.Config.Entrypoint,
+ Labels: info.Labels,
+ StopSignal: info.Config.StopSignal,
}
rootfs := docker.RootFS{}
@@ -257,6 +234,11 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
rootfs.Layers = append(rootfs.Layers, string(layer))
}
}
+
+ graphDriver := docker.GraphDriverData{
+ Name: info.GraphDriver.Name,
+ Data: info.GraphDriver.Data,
+ }
dockerImageInspect := docker.ImageInspect{
Architecture: info.Architecture,
Author: info.Author,
@@ -264,8 +246,8 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
Config: &config,
Created: l.Created().Format(time.RFC3339Nano),
DockerVersion: info.Version,
- GraphDriver: docker.GraphDriverData{},
- ID: fmt.Sprintf("sha256:%s", l.ID()),
+ GraphDriver: graphDriver,
+ ID: "sha256:" + l.ID(),
Metadata: docker.ImageMetadata{},
Os: info.Os,
OsVersion: info.Version,
@@ -277,33 +259,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
Variant: "",
VirtualSize: info.VirtualSize,
}
- bi := ic.ConfigInfo()
- // For docker images, we need to get the Container id and config
- // and populate the image with it.
- if bi.MediaType == manifest.DockerV2Schema2ConfigMediaType {
- d := manifest.Schema2Image{}
- b, err := ic.ConfigBlob(ctx)
- if err != nil {
- return nil, err
- }
- if err := json.Unmarshal(b, &d); err != nil {
- return nil, err
- }
- // populate the Container id into the image
- dockerImageInspect.Container = d.Container
- containerConfig := dockerContainer.Config{}
- configBytes, err := json.Marshal(d.ContainerConfig)
- if err != nil {
- return nil, err
- }
- if err := json.Unmarshal(configBytes, &containerConfig); err != nil {
- return nil, err
- }
- // populate the Container config in the image
- dockerImageInspect.ContainerConfig = &containerConfig
- // populate parent
- dockerImageInspect.Parent = d.Parent.String()
- }
+ // TODO: consider filling the container config.
return &ImageInspect{dockerImageInspect}, nil
}
diff --git a/pkg/api/handlers/utils/errors.go b/pkg/api/handlers/utils/errors.go
index d22ad414f..4a8005bfd 100644
--- a/pkg/api/handlers/utils/errors.go
+++ b/pkg/api/handlers/utils/errors.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/errorhandling"
+ "github.com/containers/storage"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
@@ -49,7 +50,7 @@ func ContainerNotFound(w http.ResponseWriter, name string, err error) {
}
func ImageNotFound(w http.ResponseWriter, name string, err error) {
- if errors.Cause(err) != define.ErrNoSuchImage {
+ if errors.Cause(err) != storage.ErrImageUnknown {
InternalServerError(w, err)
}
msg := fmt.Sprintf("No such image: %s", name)
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
index da3c9e985..2662cd368 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -3,15 +3,14 @@ package utils
import (
"fmt"
"net/http"
- "strings"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/filters"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/image"
- "github.com/containers/podman/v3/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -54,7 +53,7 @@ func ParseStorageReference(name string) (types.ImageReference, error) {
// GetImages is a common function used to get images for libpod and other compatibility
// mechanisms
-func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
+func GetImages(w http.ResponseWriter, r *http.Request) ([]*libimage.Image, error) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
query := struct {
@@ -65,56 +64,37 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
// This is where you can override the golang default value for one of fields
}
- filterMap, err := util.PrepareFilters(r)
- if err != nil {
- return nil, err
- }
-
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
return nil, err
}
- var filters = []string{}
if _, found := r.URL.Query()["digests"]; found && query.Digests {
UnSupportedParameter("digests")
}
- var images []*image.Image
- queryFilters := *filterMap
+ filterList, err := filters.FiltersFromRequest(r)
+ if err != nil {
+ return nil, err
+ }
if !IsLibpodRequest(r) && len(query.Filter) > 0 { // Docker 1.24 compatibility
- if queryFilters == nil {
- queryFilters = make(map[string][]string)
- }
- queryFilters["reference"] = append(queryFilters["reference"], query.Filter)
+ filterList = append(filterList, "reference="+query.Filter)
}
- if len(queryFilters) > 0 {
- for k, v := range queryFilters {
- filters = append(filters, fmt.Sprintf("%s=%s", k, strings.Join(v, "=")))
- }
- images, err = runtime.ImageRuntime().GetImagesWithFilters(filters)
- if err != nil {
- return images, err
- }
- } else {
- images, err = runtime.ImageRuntime().GetImages()
- if err != nil {
- return images, err
- }
- }
- if query.All {
- return images, nil
+ if !query.All {
+ // Filter intermediate images unless we want to list *all*.
+ // NOTE: it's a positive filter, so `intermediate=false` means
+ // to display non-intermediate images.
+ filterList = append(filterList, "intermediate=false")
}
+ listOptions := &libimage.ListImagesOptions{Filters: filterList}
+ return runtime.LibimageRuntime().ListImages(r.Context(), nil, listOptions)
+}
- filter, err := runtime.ImageRuntime().IntermediateFilter(r.Context(), images)
+func GetImage(r *http.Request, name string) (*libimage.Image, error) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ lookupOptions := &libimage.LookupImageOptions{IgnorePlatform: true}
+ image, _, err := runtime.LibimageRuntime().LookupImage(name, lookupOptions)
if err != nil {
return nil, err
}
- images = image.FilterImages(images, []image.ResultFilter{filter})
-
- return images, nil
-}
-
-func GetImage(r *http.Request, name string) (*image.Image, error) {
- runtime := r.Context().Value("runtime").(*libpod.Runtime)
- return runtime.ImageRuntime().NewFromLocal(name)
+ return image, err
}
diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go
index e4b43109f..0a13e7e74 100644
--- a/pkg/autoupdate/autoupdate.go
+++ b/pkg/autoupdate/autoupdate.go
@@ -5,16 +5,16 @@ import (
"os"
"sort"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/systemd"
systemdDefine "github.com/containers/podman/v3/pkg/systemd/define"
- "github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -126,12 +126,15 @@ func AutoUpdate(runtime *libpod.Runtime, options Options) ([]string, []error) {
return nil, errs
}
- // Create a map from `image ID -> *image.Image` for image lookups.
- imagesSlice, err := runtime.ImageRuntime().GetImages()
+ // Create a map from `image ID -> *libimage.Image` for image lookups.
+ listOptions := &libimage.ListImagesOptions{
+ Filters: []string{"readonly=false"},
+ }
+ imagesSlice, err := runtime.LibimageRuntime().ListImages(context.Background(), nil, listOptions)
if err != nil {
return nil, []error{err}
}
- imageMap := make(map[string]*image.Image)
+ imageMap := make(map[string]*libimage.Image)
for i := range imagesSlice {
imageMap[imagesSlice[i].ID()] = imagesSlice[i]
}
@@ -190,7 +193,7 @@ func AutoUpdate(runtime *libpod.Runtime, options Options) ([]string, []error) {
errs = append(errs, errors.Errorf("error locally auto-updating container %q: raw-image name is empty", cid))
}
// This avoids restarting containers unnecessarily.
- needsUpdate, err := newerLocalImageAvailable(image, rawImageName)
+ needsUpdate, err := newerLocalImageAvailable(runtime, image, rawImageName)
if err != nil {
errs = append(errs, errors.Wrapf(err, "error locally auto-updating container %q: image check for %q failed", cid, rawImageName))
continue
@@ -288,13 +291,13 @@ func readAuthenticationPath(ctr *libpod.Container, options Options) {
// newerRemoteImageAvailable returns true if there corresponding image on the remote
// registry is newer.
-func newerRemoteImageAvailable(runtime *libpod.Runtime, img *image.Image, origName string, options Options) (bool, error) {
+func newerRemoteImageAvailable(runtime *libpod.Runtime, img *libimage.Image, origName string, options Options) (bool, error) {
remoteRef, err := docker.ParseReference("//" + origName)
if err != nil {
return false, err
}
- data, err := img.Inspect(context.Background())
+ data, err := img.Inspect(context.Background(), false)
if err != nil {
return false, err
}
@@ -326,13 +329,8 @@ func newerRemoteImageAvailable(runtime *libpod.Runtime, img *image.Image, origNa
}
// newerLocalImageAvailable returns true if the container and local image have different digests
-func newerLocalImageAvailable(img *image.Image, rawImageName string) (bool, error) {
- rt, err := libpod.NewRuntime(context.TODO())
- if err != nil {
- return false, err
- }
-
- localImg, err := rt.ImageRuntime().NewFromLocal(rawImageName)
+func newerLocalImageAvailable(runtime *libpod.Runtime, img *libimage.Image, rawImageName string) (bool, error) {
+ localImg, _, err := runtime.LibimageRuntime().LookupImage(rawImageName, nil)
if err != nil {
return false, err
}
@@ -345,31 +343,14 @@ func newerLocalImageAvailable(img *image.Image, rawImageName string) (bool, erro
}
// updateImage pulls the specified image.
-func updateImage(runtime *libpod.Runtime, name string, options Options) (*image.Image, error) {
- sys := runtime.SystemContext()
- registryOpts := image.DockerRegistryOptions{}
- signaturePolicyPath := ""
-
- if sys != nil {
- registryOpts.OSChoice = sys.OSChoice
- registryOpts.ArchitectureChoice = sys.OSChoice
- registryOpts.DockerCertPath = sys.DockerCertPath
- signaturePolicyPath = sys.SignaturePolicyPath
- }
+func updateImage(runtime *libpod.Runtime, name string, options Options) (*libimage.Image, error) {
+ pullOptions := &libimage.PullOptions{}
+ pullOptions.AuthFilePath = options.Authfile
+ pullOptions.Writer = os.Stderr
- newImage, err := runtime.ImageRuntime().New(context.Background(),
- docker.Transport.Name()+"://"+name,
- signaturePolicyPath,
- options.Authfile,
- os.Stderr,
- &registryOpts,
- image.SigningOptions{},
- nil,
- util.PullImageAlways,
- nil,
- )
+ pulledImages, err := runtime.LibimageRuntime().Pull(context.Background(), name, config.PullPolicyAlways, pullOptions)
if err != nil {
return nil, err
}
- return newImage, nil
+ return pulledImages[0], nil
}
diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go
index f4da2d521..9780c3bff 100644
--- a/pkg/bindings/images/pull.go
+++ b/pkg/bindings/images/pull.go
@@ -3,7 +3,6 @@ package images
import (
"context"
"encoding/json"
- "errors"
"fmt"
"io"
"io/ioutil"
@@ -15,6 +14,7 @@ import (
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/hashicorp/go-multierror"
+ "github.com/pkg/errors"
)
// Pull is the binding for libpod's v2 endpoints for pulling images. Note that
@@ -91,7 +91,7 @@ func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string,
images = report.Images
case report.ID != "":
default:
- return images, errors.New("failed to parse pull results stream, unexpected input")
+ return images, errors.Errorf("failed to parse pull results stream, unexpected input: %v", report)
}
}
return images, mErr
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 688bf049f..ff8f72c85 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -9,7 +9,6 @@ import (
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/bindings/containers"
"github.com/containers/podman/v3/pkg/bindings/images"
- dreports "github.com/containers/podman/v3/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -116,7 +115,7 @@ var _ = Describe("Podman images", func() {
// Removing the image "alpine" where force = true
options := new(images.RemoveOptions).WithForce(true)
response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options)
- Expect(len(errs)).To(BeZero())
+ Expect(errs).To(BeNil())
// To be extra sure, check if the previously created container
// is gone as well.
_, err = containers.Inspect(bt.conn, "top", nil)
@@ -346,7 +345,6 @@ var _ = Describe("Podman images", func() {
results, err := images.Prune(bt.conn, options)
Expect(err).NotTo(HaveOccurred())
Expect(len(results)).To(BeNumerically(">", 0))
- Expect(dreports.PruneReportsIds(results)).To(ContainElement("docker.io/library/alpine:latest"))
})
// TODO: we really need to extent to pull tests once we have a more sophisticated CI.
diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go
index 68e9d9301..aecc5db81 100644
--- a/pkg/bindings/test/system_test.go
+++ b/pkg/bindings/test/system_test.go
@@ -83,8 +83,6 @@ var _ = Describe("Podman system", func() {
Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
- Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
- To(ContainElement("docker.io/library/alpine:latest"))
Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
})
@@ -193,13 +191,8 @@ var _ = Describe("Podman system", func() {
systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0))
- // TODO fix system filter handling so all components can handle filters
- // This check **should** be "Equal(0)" since we are passing label
- // filters however the Prune function doesn't seem to pass filters
- // to each component.
- Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReports)).
- To(BeNumerically(">", 0))
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(0))
+ Expect(len(systemPruneResponse.ImagePruneReports)).To(Equal(0))
// Alpine image should not be pruned as used by running container
Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
ToNot(ContainElement("docker.io/library/alpine:latest"))
diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go
index 77a993128..7a8f71c66 100644
--- a/pkg/checkpoint/checkpoint_restore.go
+++ b/pkg/checkpoint/checkpoint_restore.go
@@ -6,11 +6,11 @@ import (
"os"
metadata "github.com/checkpoint-restore/checkpointctl/lib"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling"
- "github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage/pkg/archive"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@@ -62,19 +62,19 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
}
// Load config.dump from temporary directory
- config := new(libpod.ContainerConfig)
- if _, err = metadata.ReadJSONFile(config, dir, metadata.ConfigDumpFile); err != nil {
+ ctrConfig := new(libpod.ContainerConfig)
+ if _, err = metadata.ReadJSONFile(ctrConfig, dir, metadata.ConfigDumpFile); err != nil {
return nil, err
}
// This should not happen as checkpoints with these options are not exported.
- if len(config.Dependencies) > 0 {
+ if len(ctrConfig.Dependencies) > 0 {
return nil, errors.Errorf("Cannot import checkpoints of containers with dependencies")
}
// Volumes included in the checkpoint should not exist
if !restoreOptions.IgnoreVolumes {
- for _, vol := range config.NamedVolumes {
+ for _, vol := range ctrConfig.NamedVolumes {
exists, err := runtime.HasVolume(vol.Name)
if err != nil {
return nil, err
@@ -85,33 +85,24 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
}
}
- ctrID := config.ID
+ ctrID := ctrConfig.ID
newName := false
// Check if the restored container gets a new name
if restoreOptions.Name != "" {
- config.ID = ""
- config.Name = restoreOptions.Name
+ ctrConfig.ID = ""
+ ctrConfig.Name = restoreOptions.Name
newName = true
}
- ctrName := config.Name
-
- // The code to load the images is copied from create.go
- // In create.go this only set if '--quiet' does not exist.
- writer := os.Stderr
- rtc, err := runtime.GetConfig()
- if err != nil {
- return nil, err
- }
-
- _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.Engine.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, nil, util.PullImageMissing, nil)
- if err != nil {
+ pullOptions := &libimage.PullOptions{}
+ pullOptions.Writer = os.Stderr
+ if _, err := runtime.LibimageRuntime().Pull(ctx, ctrConfig.RootfsImageName, config.PullPolicyMissing, pullOptions); err != nil {
return nil, err
}
// Now create a new container from the just loaded information
- container, err := runtime.RestoreContainer(ctx, dumpSpec, config)
+ container, err := runtime.RestoreContainer(ctx, dumpSpec, ctrConfig)
if err != nil {
return nil, err
}
@@ -122,6 +113,7 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
}
containerConfig := container.Config()
+ ctrName := ctrConfig.Name
if containerConfig.Name != ctrName {
return nil, errors.Errorf("Name of restored container (%s) does not match requested name (%s)", containerConfig.Name, ctrName)
}
diff --git a/pkg/domain/entities/manifest.go b/pkg/domain/entities/manifest.go
index 6a645e20b..3f89e4d30 100644
--- a/pkg/domain/entities/manifest.go
+++ b/pkg/domain/entities/manifest.go
@@ -8,6 +8,7 @@ type ManifestCreateOptions struct {
All bool `schema:"all"`
}
+// swagger:model ManifestAddOpts
type ManifestAddOptions struct {
All bool `json:"all" schema:"all"`
Annotation []string `json:"annotation" schema:"annotation"`
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 82f2a2424..ef3ccab0c 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -15,7 +15,6 @@ import (
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/events"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/libpod/logs"
"github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/checkpoint"
@@ -23,6 +22,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities/reports"
dfilters "github.com/containers/podman/v3/pkg/domain/filters"
"github.com/containers/podman/v3/pkg/domain/infra/abi/terminal"
+ "github.com/containers/podman/v3/pkg/errorhandling"
parallelctr "github.com/containers/podman/v3/pkg/parallel/ctr"
"github.com/containers/podman/v3/pkg/ps"
"github.com/containers/podman/v3/pkg/rootless"
@@ -438,7 +438,8 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
default:
return nil, errors.Errorf("unrecognized image format %q", options.Format)
}
- sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
+
+ sc := ic.Libpod.SystemContext()
coptions := buildah.CommitOptions{
SignaturePolicyPath: rtc.Engine.SignaturePolicyPath,
ReportWriter: options.Writer,
@@ -999,14 +1000,9 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
if options.RemoveImage {
_, imageName := ctr.Image()
- ctrImage, err := ic.Libpod.ImageRuntime().NewFromLocal(imageName)
- if err != nil {
- report.RmiErr = err
- reports = append(reports, &report)
- continue
- }
- _, err = ic.Libpod.RemoveImage(ctx, ctrImage, false)
- report.RmiErr = err
+ imageEngine := ImageEngine{Libpod: ic.Libpod}
+ _, rmErrors := imageEngine.Remove(ctx, []string{imageName}, entities.ImageRemoveOptions{})
+ report.RmiErr = errorhandling.JoinErrors(rmErrors)
}
reports = append(reports, &report)
diff --git a/pkg/domain/infra/abi/containers_runlabel.go b/pkg/domain/infra/abi/containers_runlabel.go
index 2cabab988..199ae43ad 100644
--- a/pkg/domain/infra/abi/containers_runlabel.go
+++ b/pkg/domain/infra/abi/containers_runlabel.go
@@ -7,8 +7,9 @@ import (
"path/filepath"
"strings"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/domain/entities"
envLib "github.com/containers/podman/v3/pkg/env"
"github.com/containers/podman/v3/utils"
@@ -18,21 +19,48 @@ import (
)
func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string, imageRef string, args []string, options entities.ContainerRunlabelOptions) error {
- // First, get the image and pull it if needed.
- img, err := ic.runlabelImage(ctx, label, imageRef, options)
+ pullOptions := &libimage.PullOptions{}
+ pullOptions.AuthFilePath = options.Authfile
+ pullOptions.CertDirPath = options.CertDir
+ pullOptions.Credentials = options.Credentials
+ pullOptions.SignaturePolicyPath = options.SignaturePolicy
+ pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
+
+ pullPolicy := config.PullPolicyNever
+ if options.Pull {
+ pullPolicy = config.PullPolicyMissing
+ }
+ if !options.Quiet {
+ pullOptions.Writer = os.Stderr
+ }
+
+ pulledImages, err := ic.Libpod.LibimageRuntime().Pull(ctx, imageRef, pullPolicy, pullOptions)
if err != nil {
return err
}
+
+ if len(pulledImages) != 1 {
+ return errors.Errorf("internal error: expected an image to be pulled (or an error)")
+ }
+
// Extract the runlabel from the image.
- runlabel, err := img.GetLabel(ctx, label)
+ labels, err := pulledImages[0].Labels(ctx)
if err != nil {
return err
}
+
+ var runlabel string
+ for k, v := range labels {
+ if strings.EqualFold(k, label) {
+ runlabel = v
+ break
+ }
+ }
if runlabel == "" {
return errors.Errorf("cannot find the value of label: %s in image: %s", label, imageRef)
}
- cmd, env, err := generateRunlabelCommand(runlabel, img, args, options)
+ cmd, env, err := generateRunlabelCommand(runlabel, pulledImages[0], imageRef, args, options)
if err != nil {
return err
}
@@ -76,36 +104,9 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string,
return utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...)
}
-// runlabelImage returns an image based on the specified image AND options.
-func (ic *ContainerEngine) runlabelImage(ctx context.Context, label string, imageRef string, options entities.ContainerRunlabelOptions) (*image.Image, error) {
- // First, look up the image locally. If we get an error and requested
- // to pull, fallthrough and pull it.
- img, err := ic.Libpod.ImageRuntime().NewFromLocal(imageRef)
- switch {
- case err == nil:
- return img, nil
- case !options.Pull:
- return nil, err
- default:
- // Fallthrough and pull!
- }
-
- pullOptions := entities.ImagePullOptions{
- Quiet: options.Quiet,
- CertDir: options.CertDir,
- SkipTLSVerify: options.SkipTLSVerify,
- SignaturePolicy: options.SignaturePolicy,
- Authfile: options.Authfile,
- }
- if _, err := pull(ctx, ic.Libpod.ImageRuntime(), imageRef, pullOptions, &label); err != nil {
- return nil, err
- }
- return ic.Libpod.ImageRuntime().NewFromLocal(imageRef)
-}
-
// generateRunlabelCommand generates the to-be-executed command as a string
// slice along with a base environment.
-func generateRunlabelCommand(runlabel string, img *image.Image, args []string, options entities.ContainerRunlabelOptions) ([]string, []string, error) {
+func generateRunlabelCommand(runlabel string, img *libimage.Image, inputName string, args []string, options entities.ContainerRunlabelOptions) ([]string, []string, error) {
var (
err error
name, imageName string
@@ -113,24 +114,25 @@ func generateRunlabelCommand(runlabel string, img *image.Image, args []string, o
cmd []string
)
- // TODO: How do we get global opts as done in v1?
-
// Extract the imageName (or ID).
- imgNames := img.Names()
+ imgNames := img.NamesHistory()
if len(imgNames) == 0 {
imageName = img.ID()
} else {
+ // The newest name is the first entry in the `NamesHistory`
+ // slice.
imageName = imgNames[0]
}
// Use the user-specified name or extract one from the image.
- if options.Name != "" {
- name = options.Name
- } else {
- name, err = image.GetImageBaseName(imageName)
- if err != nil {
- return nil, nil, err
+ name = options.Name
+ if name == "" {
+ normalize := imageName
+ if !strings.HasPrefix(img.ID(), inputName) {
+ normalize = inputName
}
+ splitImageName := strings.Split(normalize, "/")
+ name = splitImageName[len(splitImageName)-1]
}
// Append the user-specified arguments to the runlabel (command).
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 84c7ebecd..0364b00a3 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -3,15 +3,14 @@ package abi
import (
"context"
"fmt"
- "io"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
"strconv"
- "strings"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
@@ -19,14 +18,11 @@ import (
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
- "github.com/containers/image/v5/types"
- "github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
domainUtils "github.com/containers/podman/v3/pkg/domain/utils"
+ "github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/rootless"
- "github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage"
dockerRef "github.com/docker/distribution/reference"
"github.com/opencontainers/go-digest"
@@ -36,31 +32,84 @@ import (
)
func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
- _, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+ exists, err := ir.Libpod.LibimageRuntime().Exists(nameOrID)
if err != nil {
- if errors.Cause(err) == define.ErrMultipleImages {
- return &entities.BoolReport{Value: true}, nil
- }
- if errors.Cause(err) != define.ErrNoSuchImage {
- return nil, err
- }
+ return nil, err
}
- return &entities.BoolReport{Value: err == nil}, nil
+ return &entities.BoolReport{Value: exists}, nil
}
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
- reports, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
- if err != nil {
- return nil, err
+ // NOTE: the terms "dangling" and "intermediate" are not used
+ // consistently across our code base. In libimage, "dangling" means
+ // that an image has no tags. "intermediate" means that an image is
+ // dangling and that no other image depends on it (i.e., has no
+ // children).
+ //
+ // While pruning usually refers to "dangling" images, it has always
+ // removed "intermediate" ones.
+ defaultOptions := &libimage.RemoveImagesOptions{
+ Filters: append(opts.Filter, "intermediate=true", "containers=false", "readonly=false"),
+ WithSize: true,
+ }
+
+ // `image prune --all` means to *also* remove images which are not in
+ // use by any container. Since image filters are chained, we need to
+ // do two look ups since the default ones are a subset of all.
+ unusedOptions := &libimage.RemoveImagesOptions{
+ Filters: append(opts.Filter, "containers=false", "readonly=false"),
+ WithSize: true,
+ }
+
+ var pruneReports []*reports.PruneReport
+
+ // Now prune all images until we converge.
+ numPreviouslyRemovedImages := 1
+ for {
+ removedDefault, rmErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, nil, defaultOptions)
+ if rmErrors != nil {
+ return nil, errorhandling.JoinErrors(rmErrors)
+ }
+ removedUnused, rmErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, nil, unusedOptions)
+ if rmErrors != nil {
+ return nil, errorhandling.JoinErrors(rmErrors)
+ }
+
+ for _, rmReport := range append(removedDefault, removedUnused...) {
+ r := *rmReport
+ pruneReports = append(pruneReports, &reports.PruneReport{
+ Id: r.ID,
+ Size: uint64(r.Size),
+ })
+ }
+
+ numRemovedImages := len(removedDefault) + len(removedUnused)
+ if numRemovedImages+numPreviouslyRemovedImages == 0 {
+ break
+ }
+ numPreviouslyRemovedImages = numRemovedImages
}
- return reports, err
+
+ return pruneReports, nil
+}
+
+func toDomainHistoryLayer(layer *libimage.ImageHistory) entities.ImageHistoryLayer {
+ l := entities.ImageHistoryLayer{}
+ l.ID = layer.ID
+ l.Created = *layer.Created
+ l.CreatedBy = layer.CreatedBy
+ copy(l.Tags, layer.Tags)
+ l.Size = layer.Size
+ l.Comment = layer.Comment
+ return l
}
func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
- image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+ image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, &libimage.LookupImageOptions{IgnorePlatform: true})
if err != nil {
return nil, err
}
+
results, err := image.History(ctx)
if err != nil {
return nil, err
@@ -70,17 +119,17 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entiti
Layers: make([]entities.ImageHistoryLayer, len(results)),
}
- for i, layer := range results {
- history.Layers[i] = ToDomainHistoryLayer(layer)
+ for i := range results {
+ history.Layers[i] = toDomainHistoryLayer(&results[i])
}
return &history, nil
}
func (ir *ImageEngine) Mount(ctx context.Context, nameOrIDs []string, opts entities.ImageMountOptions) ([]*entities.ImageMountReport, error) {
- var (
- images []*image.Image
- err error
- )
+ if opts.All && len(nameOrIDs) > 0 {
+ return nil, errors.Errorf("cannot mix --all with images")
+ }
+
if os.Geteuid() != 0 {
if driver := ir.Libpod.StorageConfig().GraphDriverName; driver != "vfs" {
// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
@@ -96,219 +145,129 @@ func (ir *ImageEngine) Mount(ctx context.Context, nameOrIDs []string, opts entit
os.Exit(ret)
}
}
+
+ listImagesOptions := &libimage.ListImagesOptions{}
if opts.All {
- allImages, err := ir.Libpod.ImageRuntime().GetImages()
- if err != nil {
- return nil, err
- }
- for _, img := range allImages {
- if !img.IsReadOnly() {
- images = append(images, img)
- }
- }
- } else {
- for _, i := range nameOrIDs {
- img, err := ir.Libpod.ImageRuntime().NewFromLocal(i)
- if err != nil {
- return nil, err
- }
- images = append(images, img)
- }
+ listImagesOptions.Filters = []string{"readonly=false"}
}
- reports := make([]*entities.ImageMountReport, 0, len(images))
- for _, img := range images {
- report := entities.ImageMountReport{Id: img.ID()}
- if img.IsReadOnly() {
- report.Err = errors.Errorf("mounting readonly %s image not supported", img.ID())
- } else {
- report.Path, report.Err = img.Mount([]string{}, "")
- }
- reports = append(reports, &report)
- }
- if len(reports) > 0 {
- return reports, nil
- }
-
- images, err = ir.Libpod.ImageRuntime().GetImages()
+ images, err := ir.Libpod.LibimageRuntime().ListImages(ctx, nameOrIDs, listImagesOptions)
if err != nil {
return nil, err
}
+
+ mountReports := []*entities.ImageMountReport{}
+ listMountsOnly := !opts.All && len(nameOrIDs) == 0
for _, i := range images {
- mounted, path, err := i.Mounted()
- if err != nil {
- if errors.Cause(err) == storage.ErrLayerUnknown {
- continue
- }
- return nil, err
- }
- if mounted {
- tags, err := i.RepoTags()
+ // TODO: the .Err fields are not used. This pre-dates the
+ // libimage migration but should be addressed at some point.
+ // A quick glimpse at cmd/podman/image/mount.go suggests that
+ // the errors needed to be handled there as well.
+ var mountPoint string
+ var err error
+ if listMountsOnly {
+ // We're only looking for mounted images.
+ mountPoint, err = i.Mountpoint()
if err != nil {
return nil, err
}
- reports = append(reports, &entities.ImageMountReport{
- Id: i.ID(),
- Name: string(i.Digest()),
- Repositories: tags,
- Path: path,
- })
- }
- }
- return reports, nil
-}
-
-func (ir *ImageEngine) Unmount(ctx context.Context, nameOrIDs []string, options entities.ImageUnmountOptions) ([]*entities.ImageUnmountReport, error) {
- var images []*image.Image
-
- if options.All {
- allImages, err := ir.Libpod.ImageRuntime().GetImages()
- if err != nil {
- return nil, err
- }
- for _, img := range allImages {
- if !img.IsReadOnly() {
- images = append(images, img)
+ // Not mounted, so skip.
+ if mountPoint == "" {
+ continue
}
- }
- } else {
- for _, i := range nameOrIDs {
- img, err := ir.Libpod.ImageRuntime().NewFromLocal(i)
+ } else {
+ mountPoint, err = i.Mount(ctx, nil, "")
if err != nil {
return nil, err
}
- images = append(images, img)
}
- }
- reports := []*entities.ImageUnmountReport{}
- for _, img := range images {
- report := entities.ImageUnmountReport{Id: img.ID()}
- mounted, _, err := img.Mounted()
+ tags, err := i.RepoTags()
if err != nil {
- // Errors will be caught in Unmount call below
- // Default assumption to mounted
- mounted = true
- }
- if !mounted {
- continue
- }
- if err := img.Unmount(options.Force); err != nil {
- if options.All && errors.Cause(err) == storage.ErrLayerNotMounted {
- logrus.Debugf("Error umounting image %s, storage.ErrLayerNotMounted", img.ID())
- continue
- }
- report.Err = errors.Wrapf(err, "error unmounting image %s", img.ID())
+ return nil, err
}
- reports = append(reports, &report)
+ mountReports = append(mountReports, &entities.ImageMountReport{
+ Id: i.ID(),
+ Name: string(i.Digest()),
+ Repositories: tags,
+ Path: mountPoint,
+ })
}
- return reports, nil
+ return mountReports, nil
}
-func ToDomainHistoryLayer(layer *image.History) entities.ImageHistoryLayer {
- l := entities.ImageHistoryLayer{}
- l.ID = layer.ID
- l.Created = *layer.Created
- l.CreatedBy = layer.CreatedBy
- copy(l.Tags, layer.Tags)
- l.Size = layer.Size
- l.Comment = layer.Comment
- return l
-}
-
-func pull(ctx context.Context, runtime *image.Runtime, rawImage string, options entities.ImagePullOptions, label *string) (*entities.ImagePullReport, error) {
- var writer io.Writer
- if !options.Quiet {
- writer = os.Stderr
- }
-
- dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
- imageRef, err := alltransports.ParseImageName(rawImage)
- if err != nil {
- imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, rawImage))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid image reference %q", rawImage)
- }
+func (ir *ImageEngine) Unmount(ctx context.Context, nameOrIDs []string, options entities.ImageUnmountOptions) ([]*entities.ImageUnmountReport, error) {
+ if options.All && len(nameOrIDs) > 0 {
+ return nil, errors.Errorf("cannot mix --all with images")
}
- var registryCreds *types.DockerAuthConfig
- if len(options.Username) > 0 && len(options.Password) > 0 {
- registryCreds = &types.DockerAuthConfig{
- Username: options.Username,
- Password: options.Password,
- }
+ listImagesOptions := &libimage.ListImagesOptions{}
+ if options.All {
+ listImagesOptions.Filters = []string{"readonly=false"}
}
- dockerRegistryOptions := image.DockerRegistryOptions{
- DockerRegistryCreds: registryCreds,
- DockerCertPath: options.CertDir,
- OSChoice: options.OS,
- ArchitectureChoice: options.Arch,
- VariantChoice: options.Variant,
- DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
+ images, err := ir.Libpod.LibimageRuntime().ListImages(ctx, nameOrIDs, listImagesOptions)
+ if err != nil {
+ return nil, err
}
- if !options.AllTags {
- newImage, err := runtime.New(ctx, rawImage, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, label, options.PullPolicy, nil)
+ unmountReports := []*entities.ImageUnmountReport{}
+ for _, image := range images {
+ r := &entities.ImageUnmountReport{Id: image.ID()}
+ mountPoint, err := image.Mountpoint()
if err != nil {
- return nil, err
+ r.Err = err
+ unmountReports = append(unmountReports, r)
+ continue
}
- return &entities.ImagePullReport{Images: []string{newImage.ID()}}, nil
- }
-
- // --all-tags requires the docker transport
- if imageRef.Transport().Name() != docker.Transport.Name() {
- return nil, errors.New("--all-tags requires docker transport")
+ if mountPoint == "" {
+ // Skip if the image wasn't mounted.
+ continue
+ }
+ r.Err = image.Unmount(options.Force)
+ unmountReports = append(unmountReports, r)
}
+ return unmountReports, nil
+}
- // Trim the docker-transport prefix.
- rawImage = strings.TrimPrefix(rawImage, docker.Transport.Name())
+func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) {
+ pullOptions := &libimage.PullOptions{AllTags: options.AllTags}
+ pullOptions.AuthFilePath = options.Authfile
+ pullOptions.CertDirPath = options.CertDir
+ pullOptions.Username = options.Username
+ pullOptions.Password = options.Password
+ pullOptions.Architecture = options.Arch
+ pullOptions.OS = options.OS
+ pullOptions.Variant = options.Variant
+ pullOptions.SignaturePolicyPath = options.SignaturePolicy
+ pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
- // all-tags doesn't work with a tagged reference, so let's check early
- namedRef, err := reference.Parse(rawImage)
- if err != nil {
- return nil, errors.Wrapf(err, "error parsing %q", rawImage)
- }
- if _, isTagged := namedRef.(reference.Tagged); isTagged {
- return nil, errors.New("--all-tags requires a reference without a tag")
+ if !options.Quiet {
+ pullOptions.Writer = os.Stderr
}
- systemContext := image.GetSystemContext("", options.Authfile, false)
- tags, err := docker.GetRepositoryTags(ctx, systemContext, imageRef)
+ pulledImages, err := ir.Libpod.LibimageRuntime().Pull(ctx, rawImage, options.PullPolicy, pullOptions)
if err != nil {
- return nil, errors.Wrapf(err, "error getting repository tags")
+ return nil, err
}
- foundIDs := []string{}
- for _, tag := range tags {
- name := rawImage + ":" + tag
- newImage, err := runtime.New(ctx, name, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways, nil)
- if err != nil {
- logrus.Errorf("error pulling image %q", name)
- continue
- }
- foundIDs = append(foundIDs, newImage.ID())
+ pulledIDs := make([]string, len(pulledImages))
+ for i := range pulledImages {
+ pulledIDs[i] = pulledImages[i].ID()
}
- if len(tags) != len(foundIDs) {
- return nil, err
- }
- return &entities.ImagePullReport{Images: foundIDs}, nil
-}
-
-func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) {
- return pull(ctx, ir.Libpod.ImageRuntime(), rawImage, options, nil)
+ return &entities.ImagePullReport{Images: pulledIDs}, nil
}
func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) {
reports := []*entities.ImageInspectReport{}
errs := []error{}
for _, i := range namesOrIDs {
- img, err := ir.Libpod.ImageRuntime().NewFromLocal(i)
+ img, _, err := ir.Libpod.LibimageRuntime().LookupImage(i, &libimage.LookupImageOptions{IgnorePlatform: true})
if err != nil {
// This is probably a no such image, treat as nonfatal.
errs = append(errs, err)
continue
}
- result, err := img.Inspect(ctx)
+ result, err := img.Inspect(ctx, true)
if err != nil {
// This is more likely to be fatal.
return nil, nil, err
@@ -323,11 +282,6 @@ func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts en
}
func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
- var writer io.Writer
- if !options.Quiet {
- writer = os.Stderr
- }
-
var manifestType string
switch options.Format {
case "":
@@ -342,58 +296,56 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
return errors.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", options.Format)
}
- var registryCreds *types.DockerAuthConfig
- if len(options.Username) > 0 && len(options.Password) > 0 {
- registryCreds = &types.DockerAuthConfig{
- Username: options.Username,
- Password: options.Password,
- }
- }
- dockerRegistryOptions := image.DockerRegistryOptions{
- DockerRegistryCreds: registryCreds,
- DockerCertPath: options.CertDir,
- DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
- }
+ pushOptions := &libimage.PushOptions{}
+ pushOptions.AuthFilePath = options.Authfile
+ pushOptions.CertDirPath = options.CertDir
+ pushOptions.DirForceCompress = options.Compress
+ pushOptions.Username = options.Username
+ pushOptions.Password = options.Password
+ pushOptions.ManifestMIMEType = manifestType
+ pushOptions.RemoveSignatures = options.RemoveSignatures
+ pushOptions.SignBy = options.SignBy
+ pushOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
- signOptions := image.SigningOptions{
- RemoveSignatures: options.RemoveSignatures,
- SignBy: options.SignBy,
+ if !options.Quiet {
+ pushOptions.Writer = os.Stderr
}
- newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(source)
- if err != nil {
- return err
- }
+ pushedManifestBytes, pushError := ir.Libpod.LibimageRuntime().Push(ctx, source, destination, pushOptions)
+ if pushError == nil {
+ if options.DigestFile != "" {
+ manifestDigest, err := manifest.Digest(pushedManifestBytes)
+ if err != nil {
+ return err
+ }
- err = newImage.PushImageToHeuristicDestination(
- ctx,
- destination,
- manifestType,
- options.Authfile,
- options.DigestFile,
- options.SignaturePolicy,
- writer,
- options.Compress,
- signOptions,
- &dockerRegistryOptions,
- nil,
- options.Progress)
- if err != nil && errors.Cause(err) != storage.ErrImageUnknown {
+ if err := ioutil.WriteFile(options.DigestFile, []byte(manifestDigest.String()), 0644); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ // If the image could not be found, we may be referring to a manifest
+ // list but could not find a matching image instance in the local
+ // containers storage. In that case, fall back and attempt to push the
+ // (entire) manifest.
+ if errors.Cause(pushError) == storage.ErrImageUnknown {
// Image might be a manifest list so attempt a manifest push
- if _, manifestErr := ir.ManifestPush(ctx, source, destination, options); manifestErr == nil {
+ _, manifestErr := ir.ManifestPush(ctx, source, destination, options)
+ if manifestErr == nil {
return nil
}
}
- return err
+ return pushError
}
func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
- newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+ image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, &libimage.LookupImageOptions{IgnorePlatform: true})
if err != nil {
return err
}
for _, tag := range tags {
- if err := newImage.TagImage(tag); err != nil {
+ if err := image.Tag(tag); err != nil {
return err
}
}
@@ -401,54 +353,71 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string,
}
func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error {
- newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+ image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, &libimage.LookupImageOptions{IgnorePlatform: true})
if err != nil {
return err
}
// If only one arg is provided, all names are to be untagged
if len(tags) == 0 {
- tags = newImage.Names()
+ tags = image.Names()
}
for _, tag := range tags {
- if err := newImage.UntagImage(tag); err != nil {
+ if err := image.Untag(tag); err != nil {
return err
}
}
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.Input, writer, opts.SignaturePolicy)
- if err != nil {
- return nil, err
+func (ir *ImageEngine) Load(ctx context.Context, options entities.ImageLoadOptions) (*entities.ImageLoadReport, error) {
+ loadOptions := &libimage.LoadOptions{}
+ loadOptions.SignaturePolicyPath = options.SignaturePolicy
+ if !options.Quiet {
+ loadOptions.Writer = os.Stderr
}
- return &entities.ImageLoadReport{Names: strings.Split(name, ",")}, nil
-}
-func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOptions) (*entities.ImageImportReport, error) {
- id, err := ir.Libpod.Import(ctx, opts.Source, opts.Reference, opts.SignaturePolicy, opts.Changes, opts.Message, opts.Quiet)
+ loadedImages, err := ir.Libpod.LibimageRuntime().Load(ctx, options.Input, loadOptions)
if err != nil {
return nil, err
}
- return &entities.ImageImportReport{Id: id}, nil
+ return &entities.ImageLoadReport{Names: loadedImages}, nil
}
func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error {
+ saveOptions := &libimage.SaveOptions{}
+ saveOptions.DirForceCompress = options.Compress
+ saveOptions.RemoveSignatures = options.RemoveSignatures
+
+ if !options.Quiet {
+ saveOptions.Writer = os.Stderr
+ }
+
+ names := []string{nameOrID}
if options.MultiImageArchive {
- nameOrIDs := append([]string{nameOrID}, tags...)
- return ir.Libpod.ImageRuntime().SaveImages(ctx, nameOrIDs, options.Format, options.Output, options.Quiet, true)
+ names = append(names, tags...)
+ } else {
+ saveOptions.AdditionalTags = tags
}
- newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+ return ir.Libpod.LibimageRuntime().Save(ctx, names, options.Format, options.Output, saveOptions)
+}
+
+func (ir *ImageEngine) Import(ctx context.Context, options entities.ImageImportOptions) (*entities.ImageImportReport, error) {
+ importOptions := &libimage.ImportOptions{}
+ importOptions.Changes = options.Changes
+ importOptions.CommitMessage = options.Message
+ importOptions.Tag = options.Reference
+ importOptions.SignaturePolicyPath = options.SignaturePolicy
+
+ if !options.Quiet {
+ importOptions.Writer = os.Stderr
+ }
+
+ imageID, err := ir.Libpod.LibimageRuntime().Import(ctx, options.Source, importOptions)
if err != nil {
- return err
+ return nil, err
}
- return newImage.Save(ctx, nameOrID, options.Format, options.Output, tags, options.Quiet, options.Compress, true)
+
+ return &entities.ImageImportReport{Id: imageID}, nil
}
func (ir *ImageEngine) Diff(_ context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
@@ -460,12 +429,12 @@ func (ir *ImageEngine) Diff(_ context.Context, nameOrID string, _ entities.DiffO
}
func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
- filter, err := image.ParseSearchFilter(opts.Filters)
+ filter, err := libimage.ParseSearchFilter(opts.Filters)
if err != nil {
return nil, err
}
- searchOpts := image.SearchOptions{
+ searchOptions := &libimage.SearchOptions{
Authfile: opts.Authfile,
Filter: *filter,
Limit: opts.Limit,
@@ -474,7 +443,7 @@ func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.Im
ListTags: opts.ListTags,
}
- searchResults, err := image.SearchImages(term, searchOpts)
+ searchResults, err := ir.Libpod.LibimageRuntime().Search(ctx, term, searchOptions)
if err != nil {
return nil, err
}
@@ -510,15 +479,15 @@ func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts
}
func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
- img, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
+ image, _, err := ir.Libpod.LibimageRuntime().LookupImage(nameOrID, &libimage.LookupImageOptions{IgnorePlatform: true})
if err != nil {
return nil, err
}
- results, err := img.GenerateTree(opts.WhatRequires)
+ tree, err := image.Tree(opts.WhatRequires)
if err != nil {
return nil, err
}
- return &entities.ImageTreeReport{Tree: results}, nil
+ return &entities.ImageTreeReport{Tree: tree}, nil
}
// removeErrorsToExitCode returns an exit code for the specified slice of
@@ -542,9 +511,9 @@ func removeErrorsToExitCode(rmErrors []error) int {
for _, e := range rmErrors {
switch errors.Cause(e) {
- case define.ErrNoSuchImage:
+ case storage.ErrImageUnknown, storage.ErrLayerUnknown:
noSuchImageErrors = true
- case define.ErrImageInUse, storage.ErrImageUsedByContainer:
+ case storage.ErrImageUsedByContainer:
inUseErrors = true
default:
otherErrors = true
@@ -574,84 +543,25 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie
report.ExitCode = removeErrorsToExitCode(rmErrors)
}()
- // deleteImage is an anonymous function to conveniently delete an image
- // without having to pass all local data around.
- deleteImage := func(img *image.Image) error {
- results, err := ir.Libpod.RemoveImage(ctx, img, opts.Force)
- switch errors.Cause(err) {
- case nil:
- // Removal worked, so let's report it.
- report.Deleted = append(report.Deleted, results.Deleted)
- report.Untagged = append(report.Untagged, results.Untagged...)
- return nil
- case storage.ErrImageUnknown, storage.ErrLayerUnknown:
- // The image must have been removed already (see #6510)
- // or the storage is corrupted (see #9617).
- report.Deleted = append(report.Deleted, img.ID())
- report.Untagged = append(report.Untagged, img.ID())
- return nil
- default:
- // Fatal error.
- return err
- }
+ libimageOptions := &libimage.RemoveImagesOptions{}
+ libimageOptions.Filters = []string{"readonly=false"}
+ libimageOptions.Force = opts.Force
+ if !opts.All {
+ libimageOptions.Filters = append(libimageOptions.Filters, "intermediate=false")
}
+ libimageOptions.RemoveContainerFunc = ir.Libpod.RemoveContainersForImageCallback(ctx)
- // Delete all images from the local storage.
- if opts.All {
- previousImages := 0
- // Remove all images one-by-one.
- for {
- storageImages, err := ir.Libpod.ImageRuntime().GetRWImages()
- if err != nil {
- rmErrors = append(rmErrors, err)
- return
- }
- // No images (left) to remove, so we're done.
- if len(storageImages) == 0 {
- return
- }
- // Prevent infinity loops by making a delete-progress check.
- if previousImages == len(storageImages) {
- rmErrors = append(rmErrors, errors.New("unable to delete all images, check errors and re-run image removal if needed"))
- break
- }
- previousImages = len(storageImages)
- // Delete all "leaves" (i.e., images without child images).
- for _, img := range storageImages {
- isParent, err := img.IsParent(ctx)
- if err != nil {
- logrus.Warnf("%v, ignoring the error", err)
- isParent = false
- }
- // Skip parent images.
- if isParent {
- continue
- }
- if err := deleteImage(img); err != nil {
- rmErrors = append(rmErrors, err)
- }
- }
- }
-
- return
- }
+ libimageReport, libimageErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, images, libimageOptions)
- // Delete only the specified images.
- for _, id := range images {
- img, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
- if err != nil {
- // attempt to remove image from storage
- if forceErr := ir.Libpod.RemoveImageFromStorage(id); forceErr == nil {
- continue
- }
- rmErrors = append(rmErrors, err)
- continue
- }
- err = deleteImage(img)
- if err != nil {
- rmErrors = append(rmErrors, err)
+ for _, r := range libimageReport {
+ if r.Removed {
+ report.Deleted = append(report.Deleted, r.ID)
}
+ report.Untagged = append(report.Untagged, r.Untagged...)
}
+
+ rmErrors = libimageErrors
+
return //nolint
}
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index 3b8aabeb7..b0e947991 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -3,23 +3,25 @@ package abi
import (
"context"
- libpodImage "github.com/containers/podman/v3/libpod/image"
+ "github.com/containers/common/libimage"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
)
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
- images, err := ir.Libpod.ImageRuntime().GetImagesWithFilters(opts.Filter)
- if err != nil {
- return nil, err
+ listImagesOptions := &libimage.ListImagesOptions{
+ Filters: opts.Filter,
}
-
if !opts.All {
- filter, err := ir.Libpod.ImageRuntime().IntermediateFilter(ctx, images)
- if err != nil {
- return nil, err
- }
- images = libpodImage.FilterImages(images, []libpodImage.ResultFilter{filter})
+ // Filter intermediate images unless we want to list *all*.
+ // NOTE: it's a positive filter, so `intermediate=false` means
+ // to display non-intermediate images.
+ listImagesOptions.Filters = append(listImagesOptions.Filters, "intermediate=false")
+ }
+
+ images, err := ir.Libpod.LibimageRuntime().ListImages(ctx, nil, listImagesOptions)
+ if err != nil {
+ return nil, err
}
summaries := []*entities.ImageSummary{}
@@ -30,24 +32,21 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
}
e := entities.ImageSummary{
- ID: img.ID(),
- ConfigDigest: string(img.ConfigDigest),
- Created: img.Created().Unix(),
- Dangling: img.Dangling(),
- Digest: string(img.Digest()),
- RepoDigests: digests,
- History: img.NamesHistory(),
- Names: img.Names(),
- ReadOnly: img.IsReadOnly(),
- SharedSize: 0,
- RepoTags: img.Names(), // may include tags and digests
+ ID: img.ID(),
+ // ConfigDigest: string(img.ConfigDigest),
+ Created: img.Created().Unix(),
+ Dangling: img.IsDangling(),
+ Digest: string(img.Digest()),
+ RepoDigests: digests,
+ History: img.NamesHistory(),
+ Names: img.Names(),
+ ReadOnly: img.IsReadOnly(),
+ SharedSize: 0,
+ RepoTags: img.Names(), // may include tags and digests
}
e.Labels, err = img.Labels(ctx)
if err != nil {
- // Ignore empty manifest lists.
- if errors.Cause(err) != libpodImage.ErrImageIsBareList {
- return nil, errors.Wrapf(err, "error retrieving label for image %q: you may need to remove the image to resolve the error", img.ID())
- }
+ return nil, errors.Wrapf(err, "error retrieving label for image %q: you may need to remove the image to resolve the error", img.ID())
}
ctnrs, err := img.Containers()
@@ -56,20 +55,22 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
}
e.Containers = len(ctnrs)
- sz, err := img.Size(ctx)
+ sz, err := img.Size()
if err != nil {
return nil, errors.Wrapf(err, "error retrieving size of image %q: you may need to remove the image to resolve the error", img.ID())
}
- e.Size = int64(*sz)
+ e.Size = sz
// This is good enough for now, but has to be
// replaced later with correct calculation logic
- e.VirtualSize = int64(*sz)
+ e.VirtualSize = sz
- parent, err := img.ParentID(ctx)
+ parent, err := img.Parent(ctx)
if err != nil {
return nil, errors.Wrapf(err, "error retrieving parent of image %q: you may need to remove the image to resolve the error", img.ID())
}
- e.ParentId = parent
+ if parent != nil {
+ e.ParentId = parent.ID()
+ }
summaries = append(summaries, &e)
}
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 8e3c50fac..f932cf21d 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -4,21 +4,17 @@ import (
"bytes"
"context"
"encoding/json"
- "fmt"
"os"
"strings"
- "github.com/containers/buildah/manifests"
- buildahManifests "github.com/containers/buildah/pkg/manifests"
- buildahUtil "github.com/containers/buildah/util"
+ "github.com/containers/common/libimage"
cp "github.com/containers/image/v5/copy"
- "github.com/containers/image/v5/docker"
"github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/pkg/shortnames"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
- "github.com/containers/image/v5/types"
- libpodImage "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/storage"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
@@ -26,51 +22,103 @@ import (
)
// ManifestCreate implements logic for creating manifest lists via ImageEngine
-func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []string, opts entities.ManifestCreateOptions) (string, error) {
- fullNames, err := buildahUtil.ExpandNames(names, "", ir.Libpod.SystemContext(), ir.Libpod.GetStore())
- if err != nil {
- return "", errors.Wrapf(err, "error encountered while expanding image name %q", names)
+func (ir *ImageEngine) ManifestCreate(ctx context.Context, names []string, images []string, opts entities.ManifestCreateOptions) (string, error) {
+ // FIXME: change the interface of manifest create `names []string` ->
+ // `name string`.
+ if len(names) == 0 {
+ return "", errors.New("no name specified for creating a manifest list")
}
- imageID, err := libpodImage.CreateManifestList(ir.Libpod.ImageRuntime(), *ir.Libpod.SystemContext(), fullNames, images, opts.All)
+ name := names[0]
+
+ manifestList, err := ir.Libpod.LibimageRuntime().CreateManifestList(name)
if err != nil {
- return imageID, err
+ return "", err
}
- return imageID, err
+
+ addOptions := &libimage.ManifestListAddOptions{All: opts.All}
+ for _, image := range images {
+ if _, err := manifestList.Add(ctx, image, addOptions); err != nil {
+ return "", err
+ }
+ }
+
+ return manifestList.ID(), nil
}
// ManifestExists checks if a manifest list with the given name exists in local storage
func (ir *ImageEngine) ManifestExists(ctx context.Context, name string) (*entities.BoolReport, error) {
- if image, err := ir.Libpod.ImageRuntime().NewFromLocal(name); err == nil {
- exists, err := image.ExistsManifest()
- if err != nil && errors.Cause(err) != buildahManifests.ErrManifestTypeNotSupported {
- return nil, err
+ image, _, err := ir.Libpod.LibimageRuntime().LookupImage(name, &libimage.LookupImageOptions{IgnorePlatform: true})
+ if err != nil {
+ if errors.Cause(err) == storage.ErrImageUnknown {
+ return &entities.BoolReport{Value: false}, nil
}
- return &entities.BoolReport{Value: exists}, nil
+ return nil, err
+ }
+
+ isManifestList, err := image.IsManifestList(ctx)
+ if err != nil {
+ return nil, err
}
- return &entities.BoolReport{Value: false}, nil
+ return &entities.BoolReport{Value: isManifestList}, nil
}
// ManifestInspect returns the content of a manifest list or image
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte, error) {
- if newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(name); err == nil {
- // return the manifest in local storage
- if list, err := newImage.InspectManifest(); err == nil {
- buf, err := json.MarshalIndent(list, "", " ")
- if err != nil {
- return buf, errors.Wrapf(err, "error rendering manifest %s for display", name)
- }
- return buf, nil
- // no return if local image is not a list of images type
- // continue on getting valid manifest through remote service
- } else if errors.Cause(err) != buildahManifests.ErrManifestTypeNotSupported {
- return nil, errors.Wrapf(err, "loading manifest %q", name)
+ // NOTE: we have to do a bit of a limbo here as `podman manifest
+ // inspect foo` wants to do a remote-inspect of foo iff "foo" in the
+ // containers storage is an ordinary image but not a manifest list.
+
+ lookupOptions := &libimage.LookupImageOptions{IgnorePlatform: true}
+ image, _, err := ir.Libpod.LibimageRuntime().LookupImage(name, lookupOptions)
+ if err != nil {
+ // If the image doesn't exist, do a remote inspect.
+ if errors.Cause(err) == storage.ErrImageUnknown {
+ return ir.remoteManifestInspect(ctx, name)
}
+ return nil, err
+ }
+
+ isManifestList, err := image.IsManifestList(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ // If the image isn't a manifest list, do a remote inspect.
+ if !isManifestList {
+ return ir.remoteManifestInspect(ctx, name)
}
- sc := ir.Libpod.SystemContext()
- refs, err := buildahUtil.ResolveNameToReferences(ir.Libpod.GetStore(), sc, name)
+
+ manifestList, err := image.ToManifestList()
if err != nil {
return nil, err
}
+
+ schema2List, err := manifestList.Inspect()
+ if err != nil {
+ return nil, err
+ }
+
+ rawSchema2List, err := json.Marshal(schema2List)
+ if err != nil {
+ return nil, err
+ }
+
+ var b bytes.Buffer
+ if err := json.Indent(&b, rawSchema2List, "", " "); err != nil {
+ return nil, errors.Wrapf(err, "error rendering manifest %s for display", name)
+ }
+ return b.Bytes(), nil
+}
+
+// inspect a remote manifest list.
+func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string) ([]byte, error) {
+ sys := ir.Libpod.SystemContext()
+
+ resolved, err := shortnames.Resolve(sys, name)
+ if err != nil {
+ return nil, err
+ }
+
var (
latestErr error
result []byte
@@ -84,8 +132,13 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
latestErr = errors.Wrapf(latestErr, "tried %v\n", e)
}
}
- for _, ref := range refs {
- src, err := ref.NewImageSource(ctx, sc)
+
+ for _, candidate := range resolved.PullCandidates {
+ ref, err := alltransports.ParseImageName("docker://" + candidate.Value.String())
+ if err != nil {
+ return nil, err
+ }
+ src, err := ref.NewImageSource(ctx, sys)
if err != nil {
appendErr(errors.Wrapf(err, "reading image %q", transports.ImageName(ref)))
continue
@@ -102,6 +155,7 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
manType = manifestType
break
}
+
if len(result) == 0 && latestErr != nil {
return nil, latestErr
}
@@ -138,29 +192,41 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
// ManifestAdd adds images to the manifest list
func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAddOptions) (string, error) {
- imageSpec := opts.Images[0]
- listImageSpec := opts.Images[1]
- dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
- _, err := alltransports.ParseImageName(imageSpec)
+ // FIXME: the name options below are *mandatory* arguments and should
+ // be reflected as such in the signature.
+
+ if len(opts.Images) < 2 {
+ return "", errors.New("manifest add requires two images")
+ }
+
+ imageName := opts.Images[0]
+ listName := opts.Images[1]
+
+ manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(listName)
if err != nil {
- _, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, imageSpec))
- if err != nil {
- return "", errors.Errorf("invalid image reference %q", imageSpec)
- }
+ return "", err
}
- listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(listImageSpec)
+
+ addOptions := &libimage.ManifestListAddOptions{
+ All: opts.All,
+ AuthFilePath: opts.Authfile,
+ CertDirPath: opts.CertDir,
+ InsecureSkipTLSVerify: opts.SkipTLSVerify,
+ Username: opts.Username,
+ Password: opts.Password,
+ }
+
+ instanceDigest, err := manifestList.Add(ctx, imageName, addOptions)
if err != nil {
- return "", errors.Wrapf(err, "error retrieving local image from image name %s", listImageSpec)
+ return "", err
}
- manifestAddOpts := libpodImage.ManifestAddOpts{
- All: opts.All,
- Arch: opts.Arch,
- Features: opts.Features,
- Images: opts.Images,
- OS: opts.OS,
- OSVersion: opts.OSVersion,
- Variant: opts.Variant,
+ annotateOptions := &libimage.ManifestListAnnotateOptions{
+ Architecture: opts.Arch,
+ Features: opts.Features,
+ OS: opts.OS,
+ OSVersion: opts.OSVersion,
+ Variant: opts.Variant,
}
if len(opts.Annotation) != 0 {
annotations := make(map[string]string)
@@ -171,51 +237,44 @@ func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAd
}
annotations[spec[0]] = spec[1]
}
- manifestAddOpts.Annotation = annotations
- }
-
- // Set the system context.
- sys := ir.Libpod.SystemContext()
- if sys != nil {
- sys = &types.SystemContext{}
+ annotateOptions.Annotations = annotations
}
- sys.AuthFilePath = opts.Authfile
- sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
- sys.DockerCertPath = opts.CertDir
- if opts.Username != "" && opts.Password != "" {
- sys.DockerAuthConfig = &types.DockerAuthConfig{
- Username: opts.Username,
- Password: opts.Password,
- }
+ if err := manifestList.AnnotateInstance(instanceDigest, annotateOptions); err != nil {
+ return "", err
}
- listID, err := listImage.AddManifest(*sys, manifestAddOpts)
- if err != nil {
- return listID, err
- }
- return listID, nil
+ return manifestList.ID(), nil
}
// ManifestAnnotate updates an entry of the manifest list
func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opts entities.ManifestAnnotateOptions) (string, error) {
- listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0])
- if err != nil {
- return "", errors.Wrapf(err, "error retrieving local image from image name %s", names[0])
+ // FIXME: the `names` are *mandatory* arguments and should be
+ // reflected as such in the signature.
+
+ if len(names) < 2 {
+ return "", errors.New("manifest annotate requires two names")
}
- digest, err := digest.Parse(names[1])
+
+ listName := names[0]
+ instanceDigest, err := digest.Parse(names[1])
if err != nil {
return "", errors.Errorf(`invalid image digest "%s": %v`, names[1], err)
}
- manifestAnnotateOpts := libpodImage.ManifestAnnotateOpts{
- Arch: opts.Arch,
- Features: opts.Features,
- OS: opts.OS,
- OSFeatures: opts.OSFeatures,
- OSVersion: opts.OSVersion,
- Variant: opts.Variant,
+
+ manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(listName)
+ if err != nil {
+ return "", err
+ }
+
+ annotateOptions := &libimage.ManifestListAnnotateOptions{
+ Architecture: opts.Arch,
+ Features: opts.Features,
+ OS: opts.OS,
+ OSVersion: opts.OSVersion,
+ Variant: opts.Variant,
}
- if len(opts.Annotation) > 0 {
+ if len(opts.Annotation) != 0 {
annotations := make(map[string]string)
for _, annotationSpec := range opts.Annotation {
spec := strings.SplitN(annotationSpec, "=", 2)
@@ -224,48 +283,49 @@ func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opt
}
annotations[spec[0]] = spec[1]
}
- manifestAnnotateOpts.Annotation = annotations
+ annotateOptions.Annotations = annotations
}
- updatedListID, err := listImage.AnnotateManifest(*ir.Libpod.SystemContext(), digest, manifestAnnotateOpts)
- if err == nil {
- return fmt.Sprintf("%s: %s", updatedListID, digest.String()), nil
+
+ if err := manifestList.AnnotateInstance(instanceDigest, annotateOptions); err != nil {
+ return "", err
}
- return "", err
+
+ return manifestList.ID(), nil
}
// ManifestRemove removes specified digest from the specified manifest list
func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (string, error) {
+ // FIXME: the `names` are *mandatory* arguments and should be
+ // reflected as such in the signature.
+
+ if len(names) < 2 {
+ return "", errors.New("manifest remove requires two names")
+ }
+
+ listName := names[0]
instanceDigest, err := digest.Parse(names[1])
if err != nil {
return "", errors.Errorf(`invalid image digest "%s": %v`, names[1], err)
}
- listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0])
+
+ manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(listName)
if err != nil {
- return "", errors.Wrapf(err, "error retrieving local image from image name %s", names[0])
+ return "", err
}
- updatedListID, err := listImage.RemoveManifest(instanceDigest)
- if err == nil {
- return fmt.Sprintf("%s :%s\n", updatedListID, instanceDigest.String()), nil
+
+ if err := manifestList.RemoveInstance(instanceDigest); err != nil {
+ return "", err
}
- return "", err
+
+ return manifestList.ID(), nil
}
// ManifestPush pushes a manifest list or image index to the destination
func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination string, opts entities.ImagePushOptions) (string, error) {
- listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(name)
+ manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(name)
if err != nil {
return "", errors.Wrapf(err, "error retrieving local image from image name %s", name)
}
- dest, err := alltransports.ParseImageName(destination)
- if err != nil {
- oldErr := err
- // Try adding the images default transport
- destination2 := libpodImage.DefaultTransport + destination
- dest, err = alltransports.ParseImageName(destination2)
- if err != nil {
- return "", oldErr
- }
- }
var manifestType string
if opts.Format != "" {
@@ -279,40 +339,33 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin
}
}
- // Set the system context.
- sys := ir.Libpod.SystemContext()
- if sys == nil {
- sys = new(types.SystemContext)
- }
- sys.AuthFilePath = opts.Authfile
- sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
- sys.DockerCertPath = opts.CertDir
-
- if opts.Username != "" && opts.Password != "" {
- sys.DockerAuthConfig = &types.DockerAuthConfig{
- Username: opts.Username,
- Password: opts.Password,
- }
- }
+ pushOptions := &libimage.ManifestListPushOptions{}
+ pushOptions.AuthFilePath = opts.Authfile
+ pushOptions.CertDirPath = opts.CertDir
+ pushOptions.Username = opts.Username
+ pushOptions.Password = opts.Password
+ pushOptions.ImageListSelection = cp.CopySpecificImages
+ pushOptions.ManifestMIMEType = manifestType
+ pushOptions.RemoveSignatures = opts.RemoveSignatures
+ pushOptions.SignBy = opts.SignBy
- options := manifests.PushOptions{
- Store: ir.Libpod.GetStore(),
- SystemContext: sys,
- ImageListSelection: cp.CopySpecificImages,
- Instances: nil,
- RemoveSignatures: opts.RemoveSignatures,
- SignBy: opts.SignBy,
- ManifestType: manifestType,
- }
if opts.All {
- options.ImageListSelection = cp.CopyAllImages
+ pushOptions.ImageListSelection = cp.CopyAllImages
}
if !opts.Quiet {
- options.ReportWriter = os.Stderr
+ pushOptions.Writer = os.Stderr
}
- manDigest, err := listImage.PushManifest(dest, options)
- if err == nil && opts.Rm {
- _, err = ir.Libpod.GetStore().DeleteImage(listImage.ID(), true)
+
+ manDigest, err := manifestList.Push(ctx, destination, pushOptions)
+ if err != nil {
+ return "", err
+ }
+
+ if opts.Rm {
+ if _, err := ir.Libpod.GetStore().DeleteImage(manifestList.ID(), true); err != nil {
+ return "", errors.Wrap(err, "error removing manifest after push")
+ }
}
+
return manDigest.String(), err
}
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 6ddd4a042..d235c9ed8 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -10,17 +10,17 @@ import (
"strconv"
"strings"
+ "github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate"
"github.com/containers/podman/v3/pkg/specgen/generate/kube"
"github.com/containers/podman/v3/pkg/util"
- "github.com/docker/distribution/reference"
"github.com/ghodss/yaml"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -154,10 +154,9 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM
func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions, ipIndex *int) (*entities.PlayKubeReport, error) {
var (
- registryCreds *types.DockerAuthConfig
- writer io.Writer
- playKubePod entities.PlayKubePod
- report entities.PlayKubeReport
+ writer io.Writer
+ playKubePod entities.PlayKubePod
+ report entities.PlayKubeReport
)
// Create the secret manager before hand
@@ -220,19 +219,6 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
writer = os.Stderr
}
- if len(options.Username) > 0 && len(options.Password) > 0 {
- registryCreds = &types.DockerAuthConfig{
- Username: options.Username,
- Password: options.Password,
- }
- }
-
- dockerRegistryOptions := image.DockerRegistryOptions{
- DockerRegistryCreds: registryCreds,
- DockerCertPath: options.CertDir,
- DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
- }
-
volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes)
if err != nil {
return nil, err
@@ -273,35 +259,36 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers))
for _, container := range podYAML.Spec.Containers {
- pullPolicy := util.PullImageMissing
+ // NOTE: set the pull policy to "newer". This will cover cases
+ // where the "latest" tag requires a pull and will also
+ // transparently handle "localhost/" prefixed files which *may*
+ // refer to a locally built image OR an image running a
+ // registry on localhost.
+ pullPolicy := config.PullPolicyNewer
if len(container.ImagePullPolicy) > 0 {
- pullPolicy, err = util.ValidatePullType(string(container.ImagePullPolicy))
+ pullPolicy, err = config.ParsePullPolicy(string(container.ImagePullPolicy))
if err != nil {
return nil, err
}
}
- named, err := reference.ParseNormalizedNamed(container.Image)
- if err != nil {
- return nil, errors.Wrapf(err, "Failed to parse image %q", container.Image)
- }
- // In kube, if the image is tagged with latest, it should always pull
- // but if the domain is localhost, that means the image was built locally
- // so do not attempt a pull.
- if tagged, isTagged := named.(reference.NamedTagged); isTagged {
- if tagged.Tag() == image.LatestTag && reference.Domain(named) != image.DefaultLocalRegistry {
- pullPolicy = util.PullImageAlways
- }
- }
-
// This ensures the image is the image store
- newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy, nil)
+ pullOptions := &libimage.PullOptions{}
+ pullOptions.AuthFilePath = options.Authfile
+ pullOptions.CertDirPath = options.CertDir
+ pullOptions.SignaturePolicyPath = options.SignaturePolicy
+ pullOptions.Writer = writer
+ pullOptions.Username = options.Username
+ pullOptions.Password = options.Password
+ pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
+
+ pulledImages, err := ic.Libpod.LibimageRuntime().Pull(ctx, container.Image, pullPolicy, pullOptions)
if err != nil {
return nil, err
}
specgenOpts := kube.CtrSpecGenOptions{
Container: container,
- Image: newImage,
+ Image: pulledImages[0],
Volumes: volumes,
PodID: pod.ID(),
PodName: podName,
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 9bba0fa6c..ebe59e871 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -164,7 +164,10 @@ func movePauseProcessToScope(r *libpod.Runtime) error {
// SystemPrune removes unused data from the system. Pruning pods, containers, volumes and images.
func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
var systemPruneReport = new(entities.SystemPruneReport)
- var filters []string
+ filters := []string{}
+ for k, v := range options.Filters {
+ filters = append(filters, fmt.Sprintf("%s=%s", k, v[0]))
+ }
reclaimedSpace := (uint64)(0)
found := true
for found {
@@ -188,10 +191,12 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
}
reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(containerPruneReports)
systemPruneReport.ContainerPruneReports = append(systemPruneReport.ContainerPruneReports, containerPruneReports...)
- for k, v := range options.Filters {
- filters = append(filters, fmt.Sprintf("%s=%s", k, v[0]))
+ imagePruneOptions := entities.ImagePruneOptions{
+ All: options.All,
+ Filter: filters,
}
- imagePruneReports, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters)
+ imageEngine := ImageEngine{Libpod: ic.Libpod}
+ imagePruneReports, err := imageEngine.Prune(ctx, imagePruneOptions)
reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(imagePruneReports)
if err != nil {
@@ -225,13 +230,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
dfImages = []*entities.SystemDfImageReport{}
)
- // Compute disk-usage stats for all local images.
- imgs, err := ic.Libpod.ImageRuntime().GetImages()
- if err != nil {
- return nil, err
- }
-
- imageStats, err := ic.Libpod.ImageRuntime().DiskUsage(ctx, imgs)
+ imageStats, err := ic.Libpod.LibimageRuntime().DiskUsage(ctx)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 90b6e104b..3fd9a755d 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -8,10 +8,10 @@ import (
"strings"
"time"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
- "github.com/containers/podman/v3/libpod/image"
images "github.com/containers/podman/v3/pkg/bindings/images"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
@@ -311,7 +311,7 @@ func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.Dif
func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
mappedFilters := make(map[string][]string)
- filters, err := image.ParseSearchFilter(opts.Filters)
+ filters, err := libimage.ParseSearchFilter(opts.Filters)
if err != nil {
return nil, err
}
diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go
index 9dc545ebb..9b1740006 100644
--- a/pkg/errorhandling/errorhandling.go
+++ b/pkg/errorhandling/errorhandling.go
@@ -33,6 +33,9 @@ func JoinErrors(errs []error) error {
// ErrorsToString converts the slice of errors into a slice of corresponding
// error messages.
func ErrorsToStrings(errs []error) []string {
+ if len(errs) == 0 {
+ return nil
+ }
strErrs := make([]string, len(errs))
for i := range errs {
strErrs[i] = errs[i].Error()
@@ -43,6 +46,9 @@ func ErrorsToStrings(errs []error) []string {
// StringsToErrors converts a slice of error messages into a slice of
// corresponding errors.
func StringsToErrors(strErrs []string) []error {
+ if len(strErrs) == 0 {
+ return nil
+ }
errs := make([]error, len(strErrs))
for i := range strErrs {
errs[i] = errors.New(strErrs[i])
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index b31978638..0b76636de 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -9,6 +9,7 @@ import (
"strings"
"time"
+ "github.com/containers/common/libimage"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
@@ -257,12 +258,13 @@ func ListStorageContainer(rt *libpod.Runtime, ctr storage.Container, opts entiti
imageName := ""
if ctr.ImageID != "" {
- names, err := rt.ImageRuntime().ImageNames(ctr.ImageID)
+ lookupOptions := &libimage.LookupImageOptions{IgnorePlatform: true}
+ image, _, err := rt.LibimageRuntime().LookupImage(ctr.ImageID, lookupOptions)
if err != nil {
return ps, err
}
- if len(names) > 0 {
- imageName = names[0]
+ if len(image.NamesHistory()) > 0 {
+ imageName = image.NamesHistory()[0]
}
} else if buildahCtr {
imageName = "scratch"
diff --git a/pkg/specgen/config_unsupported.go b/pkg/specgen/config_unsupported.go
index 3d89e49f8..70a60ac47 100644
--- a/pkg/specgen/config_unsupported.go
+++ b/pkg/specgen/config_unsupported.go
@@ -3,11 +3,11 @@
package specgen
import (
- "github.com/containers/podman/v3/libpod/image"
+ "github.com/containers/common/libimage"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
-func (s *SpecGenerator) getSeccompConfig(configSpec *spec.Spec, img *image.Image) (*spec.LinuxSeccomp, error) {
+func (s *SpecGenerator) getSeccompConfig(configSpec *spec.Spec, img *libimage.Image) (*spec.LinuxSeccomp, error) {
return nil, errors.New("function not supported on non-linux OS's")
}
diff --git a/pkg/specgen/generate/config_linux_cgo.go b/pkg/specgen/generate/config_linux_cgo.go
index 41f03d5b6..6ffbf69c1 100644
--- a/pkg/specgen/generate/config_linux_cgo.go
+++ b/pkg/specgen/generate/config_linux_cgo.go
@@ -6,8 +6,8 @@ import (
"context"
"io/ioutil"
+ "github.com/containers/common/libimage"
goSeccomp "github.com/containers/common/pkg/seccomp"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/seccomp"
"github.com/containers/podman/v3/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -15,7 +15,7 @@ import (
"github.com/sirupsen/logrus"
)
-func getSeccompConfig(s *specgen.SpecGenerator, configSpec *spec.Spec, img *image.Image) (*spec.LinuxSeccomp, error) {
+func getSeccompConfig(s *specgen.SpecGenerator, configSpec *spec.Spec, img *libimage.Image) (*spec.LinuxSeccomp, error) {
var seccompConfig *spec.LinuxSeccomp
var err error
scp, err := seccomp.LookupPolicy(s.SeccompPolicy)
diff --git a/pkg/specgen/generate/config_linux_nocgo.go b/pkg/specgen/generate/config_linux_nocgo.go
index 0867988b6..4a1880b74 100644
--- a/pkg/specgen/generate/config_linux_nocgo.go
+++ b/pkg/specgen/generate/config_linux_nocgo.go
@@ -5,11 +5,11 @@ package generate
import (
"errors"
- "github.com/containers/podman/v3/libpod/image"
+ "github.com/containers/common/libimage"
"github.com/containers/podman/v3/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go"
)
-func getSeccompConfig(s *specgen.SpecGenerator, configSpec *spec.Spec, img *image.Image) (*spec.LinuxSeccomp, error) {
+func getSeccompConfig(s *specgen.SpecGenerator, configSpec *spec.Spec, img *libimage.Image) (*spec.LinuxSeccomp, error) {
return nil, errors.New("not implemented")
}
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 3d20ed8ff..d00e51e82 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -5,90 +5,45 @@ import (
"os"
"strings"
- "github.com/containers/image/v5/manifest"
+ "github.com/containers/common/libimage"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/image"
ann "github.com/containers/podman/v3/pkg/annotations"
envLib "github.com/containers/podman/v3/pkg/env"
"github.com/containers/podman/v3/pkg/signal"
"github.com/containers/podman/v3/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
// Fill any missing parts of the spec generator (e.g. from the image).
// Returns a set of warnings or any fatal error that occurred.
func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) ([]string, error) {
- var (
- newImage *image.Image
- err error
- )
-
// Only add image configuration if we have an image
+ var newImage *libimage.Image
+ var inspectData *libimage.ImageData
+ var err error
if s.Image != "" {
- newImage, err = r.ImageRuntime().NewFromLocal(s.Image)
+ newImage, _, err = r.LibimageRuntime().LookupImage(s.Image, nil)
if err != nil {
return nil, err
}
- _, mediaType, err := newImage.Manifest(ctx)
+ inspectData, err = newImage.Inspect(ctx, false)
if err != nil {
- if errors.Cause(err) != image.ErrImageIsBareList {
- return nil, err
- }
- // if err is not runnable image
- // use the local store image with repo@digest matches with the list, if exists
- manifestByte, manifestType, err := newImage.GetManifest(ctx, nil)
- if err != nil {
- return nil, err
- }
- list, err := manifest.ListFromBlob(manifestByte, manifestType)
- if err != nil {
- return nil, err
- }
- images, err := r.ImageRuntime().GetImages()
- if err != nil {
- return nil, err
- }
- findLocal := false
- listDigest, err := list.ChooseInstance(r.SystemContext())
- if err != nil {
- return nil, err
- }
- for _, img := range images {
- for _, imageDigest := range img.Digests() {
- if imageDigest == listDigest {
- newImage = img
- s.Image = img.ID()
- mediaType = manifestType
- findLocal = true
- logrus.Debug("image contains manifest list, using image from local storage")
- break
- }
- }
- }
- if !findLocal {
- return nil, image.ErrImageIsBareList
- }
+ return nil, err
}
- if s.HealthConfig == nil && mediaType == manifest.DockerV2Schema2MediaType {
- s.HealthConfig, err = newImage.GetHealthCheck(ctx)
- if err != nil {
- return nil, err
- }
+ if s.HealthConfig == nil {
+ // NOTE: the health check is only set for Docker images
+ // but inspect will take care of it.
+ s.HealthConfig = inspectData.HealthCheck
}
// Image stop signal
if s.StopSignal == nil {
- stopSignal, err := newImage.StopSignal(ctx)
- if err != nil {
- return nil, err
- }
- if stopSignal != "" {
- sig, err := signal.ParseSignalNameOrNumber(stopSignal)
+ if inspectData.Config.StopSignal != "" {
+ sig, err := signal.ParseSignalNameOrNumber(inspectData.Config.StopSignal)
if err != nil {
return nil, err
}
@@ -113,15 +68,10 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
var envs map[string]string
// Image Environment defaults
- if newImage != nil {
+ if inspectData != nil {
// Image envs from the image if they don't exist
// already, overriding the default environments
- imageEnvs, err := newImage.Env(ctx)
- if err != nil {
- return nil, err
- }
-
- envs, err = envLib.ParseSlice(imageEnvs)
+ envs, err = envLib.ParseSlice(inspectData.Config.Env)
if err != nil {
return nil, errors.Wrap(err, "Env fields from image failed to parse")
}
@@ -175,11 +125,7 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
}
// Add annotations from the image
- imgAnnotations, err := newImage.Annotations(ctx)
- if err != nil {
- return nil, err
- }
- for k, v := range imgAnnotations {
+ for k, v := range inspectData.Annotations {
annotations[k] = v
}
}
@@ -221,11 +167,8 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
s.SeccompProfilePath = p
}
- if len(s.User) == 0 && newImage != nil {
- s.User, err = newImage.User(ctx)
- if err != nil {
- return nil, err
- }
+ if len(s.User) == 0 && inspectData != nil {
+ s.User = inspectData.Config.User
}
if err := finishThrottleDevices(s); err != nil {
return nil, err
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 277435ef1..01f939022 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -7,9 +7,9 @@ import (
"strings"
cdi "github.com/container-orchestrated-devices/container-device-interface/pkg"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage/types"
@@ -86,11 +86,18 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand))
}
- var newImage *image.Image
+ var newImage *libimage.Image
+ var imageData *libimage.ImageData
if s.Rootfs != "" {
options = append(options, libpod.WithRootFS(s.Rootfs))
} else {
- newImage, err = rt.ImageRuntime().NewFromLocal(s.Image)
+ var resolvedImageName string
+ newImage, resolvedImageName, err = rt.LibimageRuntime().LookupImage(s.Image, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ imageData, err = newImage.Inspect(ctx, false)
if err != nil {
return nil, err
}
@@ -98,15 +105,14 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
// image. Otherwise, it must have been an ID where we're
// defaulting to the first name or an empty one if no names are
// present.
- imgName := newImage.InputName
- if s.Image == newImage.InputName && strings.HasPrefix(newImage.ID(), s.Image) {
+ if strings.HasPrefix(newImage.ID(), resolvedImageName) {
names := newImage.Names()
if len(names) > 0 {
- imgName = names[0]
+ resolvedImageName = names[0]
}
}
- options = append(options, libpod.WithRootFSFromImage(newImage.ID(), imgName, s.RawImageName))
+ options = append(options, libpod.WithRootFSFromImage(newImage.ID(), resolvedImageName, s.RawImageName))
}
if err := s.Validate(); err != nil {
return nil, errors.Wrap(err, "invalid config provided")
@@ -117,12 +123,12 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, err
}
- command, err := makeCommand(ctx, s, newImage, rtc)
+ command, err := makeCommand(ctx, s, imageData, rtc)
if err != nil {
return nil, err
}
- opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, newImage, command)
+ opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command)
if err != nil {
return nil, err
}
@@ -176,7 +182,7 @@ func extractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
return options
}
-func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) {
+func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, imageData *libimage.ImageData, command []string) ([]libpod.CtrCreateOption, error) {
var options []libpod.CtrCreateOption
var err error
@@ -202,11 +208,8 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
case "false":
break
case "", "true":
- if len(command) == 0 {
- command, err = img.Cmd(ctx)
- if err != nil {
- return nil, err
- }
+ if len(command) == 0 && imageData != nil {
+ command = imageData.Config.Cmd
}
if len(command) > 0 {
@@ -308,13 +311,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
}
// If the user did not specify a workdir on the CLI, let's extract it
// from the image.
- if s.WorkDir == "" && img != nil {
+ if s.WorkDir == "" && imageData != nil {
options = append(options, libpod.WithCreateWorkingDir())
- wd, err := img.WorkingDir(ctx)
- if err != nil {
- return nil, err
- }
- s.WorkDir = wd
+ s.WorkDir = imageData.Config.WorkingDir
}
if s.WorkDir == "" {
s.WorkDir = "/"
@@ -367,7 +366,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
options = append(options, libpod.WithPrivileged(s.Privileged))
// Get namespace related options
- namespaceOptions, err := namespaceOptions(ctx, s, rt, pod, img)
+ namespaceOptions, err := namespaceOptions(ctx, s, rt, pod, imageData)
if err != nil {
return nil, err
}
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 1347ed1e0..73c1c31ba 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -7,9 +7,9 @@ import (
"net"
"strings"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/parse"
"github.com/containers/common/pkg/secrets"
- "github.com/containers/podman/v3/libpod/image"
ann "github.com/containers/podman/v3/pkg/annotations"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
@@ -79,7 +79,7 @@ type CtrSpecGenOptions struct {
// Container as read from the pod yaml
Container v1.Container
// Image available to use (pulled or found local)
- Image *image.Image
+ Image *libimage.Image
// Volumes for all containers
Volumes map[string]*KubeVolume
// PodID of the parent pod
@@ -165,7 +165,7 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
// TODO: We don't understand why specgen does not take of this, but
// integration tests clearly pointed out that it was required.
- imageData, err := opts.Image.Inspect(ctx)
+ imageData, err := opts.Image.Inspect(ctx, false)
if err != nil {
return nil, err
}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index b52e8d100..278f35c22 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -6,10 +6,10 @@ import (
"os"
"strings"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
@@ -79,7 +79,7 @@ func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod)
// joining a pod.
// TODO: Consider grouping options that are not directly attached to a namespace
// elsewhere.
-func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.Pod, img *image.Image) ([]libpod.CtrCreateOption, error) {
+func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.Pod, imageData *libimage.ImageData) ([]libpod.CtrCreateOption, error) {
toReturn := []libpod.CtrCreateOption{}
// If pod is not nil, get infra container.
@@ -234,7 +234,7 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
}
toReturn = append(toReturn, libpod.WithNetNSFrom(netCtr))
case specgen.Slirp:
- portMappings, err := createPortMappings(ctx, s, img)
+ portMappings, err := createPortMappings(ctx, s, imageData)
if err != nil {
return nil, err
}
@@ -246,7 +246,7 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
case specgen.Private:
fallthrough
case specgen.Bridge:
- portMappings, err := createPortMappings(ctx, s, img)
+ portMappings, err := createPortMappings(ctx, s, imageData)
if err != nil {
return nil, err
}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 4eae09a5e..bf8d44ed6 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -5,10 +5,10 @@ import (
"path"
"strings"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
@@ -95,16 +95,12 @@ func addRlimits(s *specgen.SpecGenerator, g *generate.Generator) error {
}
// Produce the final command for the container.
-func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image, rtc *config.Config) ([]string, error) {
+func makeCommand(ctx context.Context, s *specgen.SpecGenerator, imageData *libimage.ImageData, rtc *config.Config) ([]string, error) {
finalCommand := []string{}
entrypoint := s.Entrypoint
- if entrypoint == nil && img != nil {
- newEntry, err := img.Entrypoint(ctx)
- if err != nil {
- return nil, err
- }
- entrypoint = newEntry
+ if entrypoint == nil && imageData != nil {
+ entrypoint = imageData.Config.Entrypoint
}
// Don't append the entrypoint if it is [""]
@@ -115,12 +111,8 @@ func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image
// Only use image command if the user did not manually set an
// entrypoint.
command := s.Command
- if len(command) == 0 && img != nil && len(s.Entrypoint) == 0 {
- newCmd, err := img.Cmd(ctx)
- if err != nil {
- return nil, err
- }
- command = newCmd
+ if len(command) == 0 && imageData != nil && len(s.Entrypoint) == 0 {
+ command = imageData.Config.Cmd
}
finalCommand = append(finalCommand, command...)
@@ -182,7 +174,7 @@ func getCGroupPermissons(unmask []string) string {
}
// SpecGenToOCI returns the base configuration for the container.
-func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *image.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string) (*spec.Spec, error) {
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string) (*spec.Spec, error) {
cgroupPerm := getCGroupPermissons(s.Unmask)
g, err := generate.New("linux")
diff --git a/pkg/specgen/generate/ports.go b/pkg/specgen/generate/ports.go
index 678e36a70..6832664a7 100644
--- a/pkg/specgen/generate/ports.go
+++ b/pkg/specgen/generate/ports.go
@@ -6,9 +6,9 @@ import (
"strconv"
"strings"
+ "github.com/containers/common/libimage"
"github.com/containers/podman/v3/utils"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
@@ -253,7 +253,7 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
}
// Make final port mappings for the container
-func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, img *image.Image) ([]ocicni.PortMapping, error) {
+func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData *libimage.ImageData) ([]ocicni.PortMapping, error) {
finalMappings, containerPortValidate, hostPortValidate, err := parsePortMapping(s.PortMappings)
if err != nil {
return nil, err
@@ -262,7 +262,7 @@ func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, img *imag
// If not publishing exposed ports, or if we are publishing and there is
// nothing to publish - then just return the port mappings we've made so
// far.
- if !s.PublishExposedPorts || (len(s.Expose) == 0 && img == nil) {
+ if !s.PublishExposedPorts || (len(s.Expose) == 0 && imageData == nil) {
return finalMappings, nil
}
@@ -273,12 +273,8 @@ func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, img *imag
for k, v := range s.Expose {
expose[k] = v
}
- if img != nil {
- inspect, err := img.InspectNoSize(ctx)
- if err != nil {
- return nil, errors.Wrapf(err, "error inspecting image to get exposed ports")
- }
- for imgExpose := range inspect.Config.ExposedPorts {
+ if imageData != nil {
+ for imgExpose := range imageData.Config.ExposedPorts {
// Expose format is portNumber[/protocol]
splitExpose := strings.SplitN(imgExpose, "/", 2)
num, err := strconv.Atoi(splitExpose[0])
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index e0e4a47a4..a12cc09e2 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -3,12 +3,12 @@ package generate
import (
"strings"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/apparmor"
"github.com/containers/common/pkg/capabilities"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
"github.com/opencontainers/runtime-tools/generate"
@@ -80,7 +80,7 @@ func setupApparmor(s *specgen.SpecGenerator, rtc *config.Config, g *generate.Gen
return nil
}
-func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *image.Image, rtc *config.Config) error {
+func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *libimage.Image, rtc *config.Config) error {
var (
caplist []string
err error
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index 8066834f7..13f336594 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -8,10 +8,10 @@ import (
"path/filepath"
"strings"
+ "github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/libpod/image"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -24,7 +24,7 @@ var (
)
// Produce final mounts and named volumes for a container
-func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) {
+func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *libimage.Image) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) {
// Get image volumes
baseMounts, baseVolumes, err := getImageVolumes(ctx, img, s)
if err != nil {
@@ -173,7 +173,7 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
}
// Get image volumes from the given image
-func getImageVolumes(ctx context.Context, img *image.Image, s *specgen.SpecGenerator) (map[string]spec.Mount, map[string]*specgen.NamedVolume, error) {
+func getImageVolumes(ctx context.Context, img *libimage.Image, s *specgen.SpecGenerator) (map[string]spec.Mount, map[string]*specgen.NamedVolume, error) {
mounts := make(map[string]spec.Mount)
volumes := make(map[string]*specgen.NamedVolume)
@@ -184,7 +184,7 @@ func getImageVolumes(ctx context.Context, img *image.Image, s *specgen.SpecGener
return mounts, volumes, nil
}
- inspect, err := img.InspectNoSize(ctx)
+ inspect, err := img.Inspect(ctx, false)
if err != nil {
return nil, nil, errors.Wrapf(err, "error inspecting image to get image volumes")
}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 622fbde99..60aa64ac1 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -554,23 +554,6 @@ func OpenExclusiveFile(path string) (*os.File, error) {
return os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
}
-type PullType = config.PullPolicy
-
-var (
- // PullImageAlways always try to pull new image when create or run
- PullImageAlways = config.PullImageAlways
- // PullImageMissing pulls image if it is not locally
- PullImageMissing = config.PullImageMissing
- // PullImageNever will never pull new image
- PullImageNever = config.PullImageNever
-)
-
-// ValidatePullType check if the pullType from CLI is valid and returns the valid enum type
-// if the value from CLI is invalid returns the error
-func ValidatePullType(pullType string) (PullType, error) {
- return config.ValidatePullPolicy(pullType)
-}
-
// ExitCode reads the error message when failing to executing container process
// and then returns 0 if no error, 126 if command does not exist, or 127 for
// all other errors