summaryrefslogtreecommitdiff
path: root/pkg/api/handlers/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api/handlers/libpod')
-rw-r--r--pkg/api/handlers/libpod/containers.go302
-rw-r--r--pkg/api/handlers/libpod/containers_create.go11
-rw-r--r--pkg/api/handlers/libpod/images.go228
-rw-r--r--pkg/api/handlers/libpod/info.go18
-rw-r--r--pkg/api/handlers/libpod/pods.go9
-rw-r--r--pkg/api/handlers/libpod/swagger.go10
-rw-r--r--pkg/api/handlers/libpod/types.go82
-rw-r--r--pkg/api/handlers/libpod/volumes.go4
8 files changed, 379 insertions, 285 deletions
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index cdc34004f..3902bdc9b 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -1,19 +1,19 @@
package libpod
import (
+ "io/ioutil"
"net/http"
- "path/filepath"
- "sort"
+ "os"
"strconv"
- "time"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/api/handlers/compat"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/ps"
"github.com/gorilla/schema"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
func ContainerExists(w http.ResponseWriter, r *http.Request) {
@@ -32,10 +32,6 @@ func ContainerExists(w http.ResponseWriter, r *http.Request) {
}
func ListContainers(w http.ResponseWriter, r *http.Request) {
- var (
- filterFuncs []libpod.ContainerFilter
- pss []ListContainer
- )
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
All bool `schema:"all"`
@@ -54,68 +50,21 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
-
runtime := r.Context().Value("runtime").(*libpod.Runtime)
- opts := shared.PsOptions{
+ opts := entities.ContainerListOptions{
All: query.All,
+ Filters: query.Filters,
Last: query.Last,
Size: query.Size,
Sort: "",
Namespace: query.Namespace,
- NoTrunc: true,
Pod: query.Pod,
Sync: query.Sync,
}
-
- all := query.All
- if len(query.Filters) > 0 {
- for k, v := range query.Filters {
- for _, val := range v {
- generatedFunc, err := shared.GenerateContainerFilterFuncs(k, val, runtime)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- filterFuncs = append(filterFuncs, generatedFunc)
- }
- }
- }
-
- // Docker thinks that if status is given as an input, then we should override
- // the all setting and always deal with all containers.
- if len(query.Filters["status"]) > 0 {
- all = true
- }
- if !all {
- runningOnly, err := shared.GenerateContainerFilterFuncs("status", define.ContainerStateRunning.String(), runtime)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- filterFuncs = append(filterFuncs, runningOnly)
- }
-
- cons, err := runtime.GetContainers(filterFuncs...)
+ pss, err := ps.GetContainerLists(runtime, opts)
if err != nil {
utils.InternalServerError(w, err)
- }
- if query.Last > 0 {
- // Sort the containers we got
- sort.Sort(psSortCreateTime{cons})
- // we should perform the lopping before we start getting
- // the expensive information on containers
- if query.Last < len(cons) {
- cons = cons[len(cons)-query.Last:]
- }
- }
- for _, con := range cons {
- listCon, err := ListContainerBatch(runtime, con, opts)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- pss = append(pss, listCon)
-
+ return
}
utils.WriteResponse(w, http.StatusOK, pss)
}
@@ -207,121 +156,148 @@ func ShowMountedContainers(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, response)
}
-// BatchContainerOp is used in ps to reduce performance hits by "batching"
-// locks.
-func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts shared.PsOptions) (ListContainer, error) {
- var (
- conConfig *libpod.ContainerConfig
- conState define.ContainerStatus
- err error
- exitCode int32
- exited bool
- pid int
- size *shared.ContainerSize
- startedTime time.Time
- exitedTime time.Time
- cgroup, ipc, mnt, net, pidns, user, uts string
- )
-
- batchErr := ctr.Batch(func(c *libpod.Container) error {
- conConfig = c.Config()
- conState, err = c.State()
- if err != nil {
- return errors.Wrapf(err, "unable to obtain container state")
- }
+func Checkpoint(w http.ResponseWriter, r *http.Request) {
+ var targetFile string
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Keep bool `schema:"keep"`
+ LeaveRunning bool `schema:"leaveRunning"`
+ TCPEstablished bool `schema:"tcpEstablished"`
+ Export bool `schema:"export"`
+ IgnoreRootFS bool `schema:"ignoreRootFS"`
+ }{
+ // override any golang type defaults
+ }
- exitCode, exited, err = c.ExitCode()
+ 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
+ }
+ name := utils.GetName(r)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ ctr, err := runtime.LookupContainer(name)
+ if err != nil {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+ if query.Export {
+ tmpFile, err := ioutil.TempFile("", "checkpoint")
if err != nil {
- return errors.Wrapf(err, "unable to obtain container exit code")
+ utils.InternalServerError(w, err)
+ return
}
- startedTime, err = c.StartedTime()
- if err != nil {
- logrus.Errorf("error getting started time for %q: %v", c.ID(), err)
+ defer os.Remove(tmpFile.Name())
+ if err := tmpFile.Close(); err != nil {
+ utils.InternalServerError(w, err)
+ return
}
- exitedTime, err = c.FinishedTime()
+ targetFile = tmpFile.Name()
+ }
+ options := libpod.ContainerCheckpointOptions{
+ Keep: query.Keep,
+ KeepRunning: query.LeaveRunning,
+ TCPEstablished: query.TCPEstablished,
+ IgnoreRootfs: query.IgnoreRootFS,
+ }
+ if query.Export {
+ options.TargetFile = targetFile
+ }
+ err = ctr.Checkpoint(r.Context(), options)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ if query.Export {
+ f, err := os.Open(targetFile)
if err != nil {
- logrus.Errorf("error getting exited time for %q: %v", c.ID(), err)
- }
-
- if !opts.Size && !opts.Namespace {
- return nil
+ utils.InternalServerError(w, err)
+ return
}
+ defer f.Close()
+ utils.WriteResponse(w, http.StatusOK, f)
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, entities.CheckpointReport{Id: ctr.ID()})
+}
- if opts.Namespace {
- pid, err = c.PID()
- if err != nil {
- return errors.Wrapf(err, "unable to obtain container pid")
- }
- ctrPID := strconv.Itoa(pid)
- cgroup, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
- ipc, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
- mnt, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
- net, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
- pidns, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
- user, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
- uts, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
+func Restore(w http.ResponseWriter, r *http.Request) {
+ var (
+ targetFile string
+ )
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Keep bool `schema:"keep"`
+ TCPEstablished bool `schema:"tcpEstablished"`
+ Import bool `schema:"import"`
+ Name string `schema:"name"`
+ IgnoreRootFS bool `schema:"ignoreRootFS"`
+ IgnoreStaticIP bool `schema:"ignoreStaticIP"`
+ IgnoreStaticMAC bool `schema:"ignoreStaticMAC"`
+ }{
+ // override any golang type defaults
+ }
+ 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
+ }
+ name := utils.GetName(r)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ ctr, err := runtime.LookupContainer(name)
+ if err != nil {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+ if query.Import {
+ t, err := ioutil.TempFile("", "restore")
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
}
- if opts.Size {
- size = new(shared.ContainerSize)
-
- rootFsSize, err := c.RootFsSize()
- if err != nil {
- logrus.Errorf("error getting root fs size for %q: %v", c.ID(), err)
- }
-
- rwSize, err := c.RWSize()
- if err != nil {
- logrus.Errorf("error getting rw size for %q: %v", c.ID(), err)
- }
-
- size.RootFsSize = rootFsSize
- size.RwSize = rwSize
+ defer t.Close()
+ if err := compat.SaveFromBody(t, r); err != nil {
+ utils.InternalServerError(w, err)
+ return
}
- return nil
- })
-
- if batchErr != nil {
- return ListContainer{}, batchErr
+ targetFile = t.Name()
}
- ps := ListContainer{
- Command: conConfig.Command,
- Created: conConfig.CreatedTime.Unix(),
- Exited: exited,
- ExitCode: exitCode,
- ExitedAt: exitedTime.Unix(),
- ID: conConfig.ID,
- Image: conConfig.RootfsImageName,
- IsInfra: conConfig.IsInfra,
- Labels: conConfig.Labels,
- Mounts: ctr.UserVolumes(),
- Names: []string{conConfig.Name},
- Pid: pid,
- Pod: conConfig.Pod,
- Ports: conConfig.PortMappings,
- Size: size,
- StartedAt: startedTime.Unix(),
- State: conState.String(),
- }
- if opts.Pod && len(conConfig.Pod) > 0 {
- pod, err := rt.GetPod(conConfig.Pod)
- if err != nil {
- return ListContainer{}, err
- }
- ps.PodName = pod.Name()
+ options := libpod.ContainerCheckpointOptions{
+ Keep: query.Keep,
+ TCPEstablished: query.TCPEstablished,
+ IgnoreRootfs: query.IgnoreRootFS,
+ IgnoreStaticIP: query.IgnoreStaticIP,
+ IgnoreStaticMAC: query.IgnoreStaticMAC,
+ }
+ if query.Import {
+ options.TargetFile = targetFile
+ options.Name = query.Name
}
+ err = ctr.Restore(r.Context(), options)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, entities.RestoreReport{Id: ctr.ID()})
+}
- if opts.Namespace {
- ns := ListContainerNamespaces{
- Cgroup: cgroup,
- IPC: ipc,
- MNT: mnt,
- NET: net,
- PIDNS: pidns,
- User: user,
- UTS: uts,
- }
- ps.Namespaces = ns
+func InitContainer(w http.ResponseWriter, r *http.Request) {
+ name := utils.GetName(r)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ ctr, err := runtime.LookupContainer(name)
+ if err != nil {
+ utils.ContainerNotFound(w, name, err)
+ return
}
- return ps, nil
+ err = ctr.Init(r.Context())
+ if errors.Cause(err) == define.ErrCtrStateInvalid {
+ utils.Error(w, "container already initialized", http.StatusNotModified, err)
+ return
+ }
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusNoContent, "")
}
diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go
index ebca41151..f64132d55 100644
--- a/pkg/api/handlers/libpod/containers_create.go
+++ b/pkg/api/handlers/libpod/containers_create.go
@@ -4,9 +4,12 @@ import (
"encoding/json"
"net/http"
+ "github.com/containers/libpod/pkg/domain/entities"
+
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/libpod/pkg/specgen/generate"
"github.com/pkg/errors"
)
@@ -19,11 +22,15 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
- ctr, err := sg.MakeContainer(runtime)
+ if err := generate.CompleteSpec(r.Context(), runtime, &sg); err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ ctr, err := generate.MakeContainer(runtime, &sg)
if err != nil {
utils.InternalServerError(w, err)
return
}
- response := utils.ContainerCreateResponse{ID: ctr.ID()}
+ response := entities.ContainerCreateResponse{ID: ctr.ID()}
utils.WriteJSON(w, http.StatusCreated, response)
}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index d4fd77cd7..a42d06205 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -14,15 +14,16 @@ import (
"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/image/v5/types"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
image2 "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/util"
+ utils2 "github.com/containers/libpod/utils"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -162,13 +163,16 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
}
func ExportImage(w http.ResponseWriter, r *http.Request) {
+ var (
+ output string
+ )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Compress bool `schema:"compress"`
Format string `schema:"format"`
}{
- Format: "docker-archive",
+ Format: define.OCIArchive,
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
@@ -176,14 +180,27 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
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
- }
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
+ switch query.Format {
+ case define.OCIArchive, define.V2s2Archive:
+ tmpfile, err := ioutil.TempFile("", "api.tar")
+ if err != nil {
+ utils.Error(w, "unable to create tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
+ return
+ }
+ output = tmpfile.Name()
+ if err := tmpfile.Close(); err != nil {
+ utils.Error(w, "unable to close tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
+ return
+ }
+ case define.OCIManifestDir, define.V2s2ManifestDir:
+ tmpdir, err := ioutil.TempDir("", "save")
+ if err != nil {
+ utils.Error(w, "unable to create tmpdir", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempdir"))
+ return
+ }
+ output = tmpdir
+ default:
+ utils.Error(w, "unknown format", http.StatusInternalServerError, errors.Errorf("unknown format %q", query.Format))
return
}
name := utils.GetName(r)
@@ -193,17 +210,28 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
return
}
- if err := newImage.Save(r.Context(), name, query.Format, tmpfile.Name(), []string{}, false, query.Compress); err != nil {
+ if err := newImage.Save(r.Context(), name, query.Format, output, []string{}, false, query.Compress); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
return
}
- rdr, err := os.Open(tmpfile.Name())
+ defer os.RemoveAll(output)
+ // if dir format, we need to tar it
+ if query.Format == "oci-dir" || query.Format == "docker-dir" {
+ rdr, err := utils2.Tar(output)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ defer rdr.Close()
+ utils.WriteResponse(w, http.StatusOK, rdr)
+ return
+ }
+ rdr, err := os.Open(output)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to read the exported tarfile"))
return
}
defer rdr.Close()
- defer os.Remove(tmpfile.Name())
utils.WriteResponse(w, http.StatusOK, rdr)
}
@@ -331,29 +359,16 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, errors.New("reference parameter cannot be empty"))
return
}
- // Enforce the docker transport. This is just a precaution as some callers
- // might be accustomed to using the "transport:reference" notation. Using
- // another than the "docker://" transport does not really make sense for a
- // remote case. For loading tarballs, the load and import endpoints should
- // be used.
- dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
- imageRef, err := alltransports.ParseImageName(query.Reference)
- if err == nil && imageRef.Transport().Name() != docker.Transport.Name() {
+
+ imageRef, err := utils.ParseDockerReference(query.Reference)
+ if err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Errorf("reference %q must be a docker reference", query.Reference))
+ errors.Wrapf(err, "image destination %q is not a docker-transport reference", query.Reference))
return
- } else if err != nil {
- origErr := err
- imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, query.Reference))
- if err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(origErr, "reference %q must be a docker reference", query.Reference))
- return
- }
}
// Trim the docker-transport prefix.
- rawImage := strings.TrimPrefix(query.Reference, dockerPrefix)
+ rawImage := strings.TrimPrefix(query.Reference, fmt.Sprintf("%s://", docker.Transport.Name()))
// all-tags doesn't work with a tagged reference, so let's check early
namedRef, err := reference.Parse(rawImage)
@@ -385,7 +400,7 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
OSChoice: query.OverrideOS,
ArchitectureChoice: query.OverrideArch,
}
- if query.TLSVerify {
+ if _, found := r.URL.Query()["tlsVerify"]; found {
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
}
@@ -408,13 +423,19 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
}
}
+ authfile := ""
+ if sys := runtime.SystemContext(); sys != nil {
+ dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
+ authfile = sys.AuthFilePath
+ }
+
// Finally pull the images
for _, img := range imagesToPull {
newImage, err := runtime.ImageRuntime().New(
context.Background(),
img,
"",
- "",
+ authfile,
os.Stderr,
&dockerRegistryOptions,
image.SigningOptions{},
@@ -430,6 +451,94 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, res)
}
+// PushImage is the handler for the compat http endpoint for pushing images.
+func PushImage(w http.ResponseWriter, r *http.Request) {
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+
+ query := struct {
+ Credentials string `schema:"credentials"`
+ Destination string `schema:"destination"`
+ TLSVerify bool `schema:"tlsVerify"`
+ }{
+ // 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, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ source := strings.TrimSuffix(utils.GetName(r), "/push") // GetName returns the entire path
+ if _, err := utils.ParseStorageReference(source); err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "image source %q is not a containers-storage-transport reference", source))
+ return
+ }
+
+ destination := query.Destination
+ if destination == "" {
+ destination = source
+ }
+
+ if _, err := utils.ParseDockerReference(destination); err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "image destination %q is not a docker-transport reference", destination))
+ return
+ }
+
+ newImage, err := runtime.ImageRuntime().NewFromLocal(source)
+ if err != nil {
+ utils.ImageNotFound(w, source, errors.Wrapf(err, "Failed to find image %s", source))
+ return
+ }
+
+ var registryCreds *types.DockerAuthConfig
+ if len(query.Credentials) != 0 {
+ creds, err := util.ParseRegistryCreds(query.Credentials)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "error parsing credentials %q", query.Credentials))
+ return
+ }
+ registryCreds = creds
+ }
+
+ // TODO: the X-Registry-Auth header is not checked yet here nor in any other
+ // endpoint. Pushing does NOT work with authentication at the moment.
+ dockerRegistryOptions := &image.DockerRegistryOptions{
+ DockerRegistryCreds: registryCreds,
+ }
+ authfile := ""
+ if sys := runtime.SystemContext(); sys != nil {
+ dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
+ authfile = sys.AuthFilePath
+ }
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
+ err = newImage.PushImageToHeuristicDestination(
+ context.Background(),
+ destination,
+ "", // manifest type
+ authfile,
+ "", // digest file
+ "", // signature policy
+ os.Stderr,
+ false, // force compression
+ image.SigningOptions{},
+ dockerRegistryOptions,
+ nil, // additional tags
+ )
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Error pushing image %q", destination))
+ return
+ }
+
+ utils.WriteResponse(w, http.StatusOK, "")
+}
+
func CommitContainer(w http.ResponseWriter, r *http.Request) {
var (
destImage string
@@ -536,3 +645,56 @@ func UntagImage(w http.ResponseWriter, r *http.Request) {
}
utils.WriteResponse(w, http.StatusCreated, "")
}
+
+func SearchImages(w http.ResponseWriter, r *http.Request) {
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Term string `json:"term"`
+ Limit int `json:"limit"`
+ Filters []string `json:"filters"`
+ TLSVerify bool `json:"tlsVerify"`
+ }{
+ // 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, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ options := image.SearchOptions{
+ Limit: query.Limit,
+ }
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
+ if _, found := r.URL.Query()["filters"]; found {
+ filter, err := image.ParseSearchFilter(query.Filters)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse filters parameter for %s", r.URL.String()))
+ return
+ }
+ options.Filter = *filter
+ }
+
+ searchResults, err := image.SearchImages(query.Term, options)
+ if err != nil {
+ utils.BadRequest(w, "term", query.Term, err)
+ return
+ }
+ // Convert from image.SearchResults to entities.ImageSearchReport. We don't
+ // want to leak any low-level packages into the remote client, which
+ // requires converting.
+ reports := make([]entities.ImageSearchReport, len(searchResults))
+ for i := range searchResults {
+ reports[i].Index = searchResults[i].Index
+ reports[i].Name = searchResults[i].Name
+ reports[i].Description = searchResults[i].Index
+ reports[i].Stars = searchResults[i].Stars
+ reports[i].Official = searchResults[i].Official
+ reports[i].Automated = searchResults[i].Automated
+ }
+
+ utils.WriteResponse(w, http.StatusOK, reports)
+}
diff --git a/pkg/api/handlers/libpod/info.go b/pkg/api/handlers/libpod/info.go
new file mode 100644
index 000000000..cbf03aa17
--- /dev/null
+++ b/pkg/api/handlers/libpod/info.go
@@ -0,0 +1,18 @@
+package libpod
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/api/handlers/utils"
+)
+
+func GetInfo(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ info, err := runtime.Info()
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, info)
+}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index e834029b2..92556bb61 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/libpod/pkg/specgen/generate"
"github.com/containers/libpod/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -27,7 +28,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Failed to decode specgen", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen"))
return
}
- pod, err := psg.MakePod(runtime)
+ pod, err := generate.MakePod(&psg, runtime)
if err != nil {
http_code := http.StatusInternalServerError
if errors.Cause(err) == define.ErrPodExists {
@@ -73,7 +74,11 @@ func PodInspect(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
- utils.WriteResponse(w, http.StatusOK, podData)
+
+ report := entities.PodInspectReport{
+ InspectPodData: podData,
+ }
+ utils.WriteResponse(w, http.StatusOK, report)
}
func PodStop(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/api/handlers/libpod/swagger.go b/pkg/api/handlers/libpod/swagger.go
index 1fad2dd1a..ed19462c6 100644
--- a/pkg/api/handlers/libpod/swagger.go
+++ b/pkg/api/handlers/libpod/swagger.go
@@ -5,6 +5,7 @@ import (
"os"
"github.com/containers/image/v5/manifest"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
@@ -17,7 +18,7 @@ const DefaultPodmanSwaggerSpec = "/usr/share/containers/podman/swagger.yaml"
// swagger:response ListContainers
type swagInspectPodResponse struct {
// in:body
- Body []ListContainer
+ Body []entities.ListContainer
}
// Inspect Manifest
@@ -76,6 +77,13 @@ type swagRmPodResponse struct {
Body entities.PodRmReport
}
+// Info
+// swagger:response InfoResponse
+type swagInfoResponse struct {
+ // in:body
+ Body define.Info
+}
+
func ServeSwagger(w http.ResponseWriter, r *http.Request) {
path := DefaultPodmanSwaggerSpec
if p, found := os.LookupEnv("PODMAN_SWAGGER_SPEC"); found {
diff --git a/pkg/api/handlers/libpod/types.go b/pkg/api/handlers/libpod/types.go
deleted file mode 100644
index 0949b2a72..000000000
--- a/pkg/api/handlers/libpod/types.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package libpod
-
-import (
- "github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/libpod"
- "github.com/cri-o/ocicni/pkg/ocicni"
-)
-
-// Listcontainer describes a container suitable for listing
-type ListContainer struct {
- // Container command
- Command []string
- // Container creation time
- Created int64
- // If container has exited/stopped
- Exited bool
- // Time container exited
- ExitedAt int64
- // If container has exited, the return code from the command
- ExitCode int32
- // The unique identifier for the container
- ID string `json:"Id"`
- // Container image
- Image string
- // If this container is a Pod infra container
- IsInfra bool
- // Labels for container
- Labels map[string]string
- // User volume mounts
- Mounts []string
- // The names assigned to the container
- Names []string
- // Namespaces the container belongs to. Requires the
- // namespace boolean to be true
- Namespaces ListContainerNamespaces
- // The process id of the container
- Pid int
- // If the container is part of Pod, the Pod ID. Requires the pod
- // boolean to be set
- Pod string
- // If the container is part of Pod, the Pod name. Requires the pod
- // boolean to be set
- PodName string
- // Port mappings
- Ports []ocicni.PortMapping
- // Size of the container rootfs. Requires the size boolean to be true
- Size *shared.ContainerSize
- // Time when container started
- StartedAt int64
- // State of container
- State string
-}
-
-// ListContainer Namespaces contains the identifiers of the container's Linux namespaces
-type ListContainerNamespaces struct {
- // Mount namespace
- MNT string `json:"Mnt,omitempty"`
- // Cgroup namespace
- Cgroup string `json:"Cgroup,omitempty"`
- // IPC namespace
- IPC string `json:"Ipc,omitempty"`
- // Network namespace
- NET string `json:"Net,omitempty"`
- // PID namespace
- PIDNS string `json:"Pidns,omitempty"`
- // UTS namespace
- UTS string `json:"Uts,omitempty"`
- // User namespace
- User string `json:"User,omitempty"`
-}
-
-// sortContainers helps us set-up ability to sort by createTime
-type sortContainers []*libpod.Container
-
-func (a sortContainers) Len() int { return len(a) }
-func (a sortContainers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-
-type psSortCreateTime struct{ sortContainers }
-
-func (a psSortCreateTime) Less(i, j int) bool {
- return a.sortContainers[i].CreatedTime().Before(a.sortContainers[j].CreatedTime())
-}
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index 5a6fc021e..18c561a0d 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -4,12 +4,12 @@ import (
"encoding/json"
"net/http"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/domain/filters"
+ "github.com/containers/libpod/pkg/domain/infra/abi/parse"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -46,7 +46,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(input.Label))
}
if len(input.Options) > 0 {
- parsedOptions, err := shared.ParseVolumeOptions(input.Options)
+ parsedOptions, err := parse.ParseVolumeOptions(input.Options)
if err != nil {
utils.InternalServerError(w, err)
return