summaryrefslogtreecommitdiff
path: root/pkg/api/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api/handlers')
-rw-r--r--pkg/api/handlers/compat/containers.go127
-rw-r--r--pkg/api/handlers/compat/containers_restart.go42
-rw-r--r--pkg/api/handlers/compat/containers_stop.go44
-rw-r--r--pkg/api/handlers/compat/images_push.go64
-rw-r--r--pkg/api/handlers/compat/images_search.go84
-rw-r--r--pkg/api/handlers/libpod/containers.go23
-rw-r--r--pkg/api/handlers/libpod/images.go86
-rw-r--r--pkg/api/handlers/libpod/manifests.go12
-rw-r--r--pkg/api/handlers/utils/containers.go33
9 files changed, 255 insertions, 260 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index aa12afc82..b41987800 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -22,6 +22,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/go-connections/nat"
+ "github.com/docker/go-units"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -31,11 +32,11 @@ import (
func RemoveContainer(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- All bool `schema:"all"`
- Force bool `schema:"force"`
- Ignore bool `schema:"ignore"`
- Link bool `schema:"link"`
- Volumes bool `schema:"v"`
+ Force bool `schema:"force"`
+ Ignore bool `schema:"ignore"`
+ Link bool `schema:"link"`
+ DockerVolumes bool `schema:"v"`
+ LibpodVolumes bool `schema:"volumes"`
}{
// override any golang type defaults
}
@@ -46,10 +47,19 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
return
}
- if query.Link && !utils.IsLibpodRequest(r) {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- utils.ErrLinkNotSupport)
- return
+ options := entities.RmOptions{
+ Force: query.Force,
+ Ignore: query.Ignore,
+ }
+ if utils.IsLibpodRequest(r) {
+ options.Volumes = query.LibpodVolumes
+ } else {
+ if query.Link {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ utils.ErrLinkNotSupport)
+ return
+ }
+ options.Volumes = query.DockerVolumes
}
runtime := r.Context().Value("runtime").(*libpod.Runtime)
@@ -57,12 +67,6 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
// code.
containerEngine := abi.ContainerEngine{Libpod: runtime}
name := utils.GetName(r)
- options := entities.RmOptions{
- All: query.All,
- Force: query.Force,
- Volumes: query.Volumes,
- Ignore: query.Ignore,
- }
report, err := containerEngine.ContainerRm(r.Context(), []string{name}, options)
if err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
@@ -73,7 +77,7 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- if report[0].Err != nil {
+ if len(report) > 0 && report[0].Err != nil {
utils.InternalServerError(w, report[0].Err)
return
}
@@ -193,45 +197,48 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
return
}
- sig, err := signal.ParseSignalNameOrNumber(query.Signal)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
name := utils.GetName(r)
- con, err := runtime.LookupContainer(name)
- if err != nil {
- utils.ContainerNotFound(w, name, err)
- return
+ options := entities.KillOptions{
+ Signal: query.Signal,
}
-
- state, err := con.State()
+ report, err := containerEngine.ContainerKill(r.Context(), []string{name}, options)
if err != nil {
- utils.InternalServerError(w, err)
- return
- }
+ if errors.Cause(err) == define.ErrCtrStateInvalid ||
+ errors.Cause(err) == define.ErrCtrStopped {
+ utils.Error(w, fmt.Sprintf("Container %s is not running", name), http.StatusConflict, err)
+ return
+ }
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
- // If the Container is stopped already, send a 409
- if state == define.ContainerStateStopped || state == define.ContainerStateExited {
- utils.Error(w, fmt.Sprintf("Container %s is not running", name), http.StatusConflict, errors.New(fmt.Sprintf("Cannot kill Container %s, it is not running", name)))
+ utils.InternalServerError(w, err)
return
}
- signal := uint(sig)
-
- err = con.Kill(signal)
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "unable to kill Container %s", name))
+ if len(report) > 0 && report[0].Err != nil {
+ utils.InternalServerError(w, report[0].Err)
return
}
-
// Docker waits for the container to stop if the signal is 0 or
// SIGKILL.
- if !utils.IsLibpodRequest(r) && (signal == 0 || syscall.Signal(signal) == syscall.SIGKILL) {
- if _, err = con.Wait(); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to wait for Container %s", con.ID()))
+ if !utils.IsLibpodRequest(r) {
+ sig, err := signal.ParseSignalNameOrNumber(query.Signal)
+ if err != nil {
+ utils.InternalServerError(w, err)
return
}
+ if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
+ var opts entities.WaitOptions
+ if _, err := containerEngine.ContainerWait(r.Context(), []string{name}, opts); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
+ return
+ }
+ }
}
// Success
utils.WriteResponse(w, http.StatusNoContent, nil)
@@ -242,6 +249,10 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) {
// /{version}/containers/(name)/wait
exitCode, err := utils.WaitContainer(w, r)
if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ logrus.Warnf("container not found %q: %v", utils.GetName(r), err)
+ return
+ }
logrus.Warnf("failed to wait on container %q: %v", mux.Vars(r)["name"], err)
return
}
@@ -264,6 +275,7 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error
sizeRootFs int64
sizeRW int64
state define.ContainerStatus
+ status string
)
if state, err = l.State(); err != nil {
@@ -274,6 +286,35 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error
stateStr = "created"
}
+ if state == define.ContainerStateConfigured || state == define.ContainerStateCreated {
+ status = "Created"
+ } else if state == define.ContainerStateStopped || state == define.ContainerStateExited {
+ exitCode, _, err := l.ExitCode()
+ if err != nil {
+ return nil, err
+ }
+ finishedTime, err := l.FinishedTime()
+ if err != nil {
+ return nil, err
+ }
+ status = fmt.Sprintf("Exited (%d) %s ago", exitCode, units.HumanDuration(time.Since(finishedTime)))
+ } else if state == define.ContainerStateRunning || state == define.ContainerStatePaused {
+ startedTime, err := l.StartedTime()
+ if err != nil {
+ return nil, err
+ }
+ status = fmt.Sprintf("Up %s", units.HumanDuration(time.Since(startedTime)))
+ if state == define.ContainerStatePaused {
+ status += " (Paused)"
+ }
+ } else if state == define.ContainerStateRemoving {
+ status = "Removal In Progress"
+ } else if state == define.ContainerStateStopping {
+ status = "Stopping"
+ } else {
+ status = "Unknown"
+ }
+
if sz {
if sizeRW, err = l.RWSize(); err != nil {
return nil, err
@@ -295,7 +336,7 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error
SizeRootFs: sizeRootFs,
Labels: l.Labels(),
State: stateStr,
- Status: "",
+ Status: status,
HostConfig: struct {
NetworkMode string `json:",omitempty"`
}{
diff --git a/pkg/api/handlers/compat/containers_restart.go b/pkg/api/handlers/compat/containers_restart.go
index e8928596a..70edfcbb3 100644
--- a/pkg/api/handlers/compat/containers_restart.go
+++ b/pkg/api/handlers/compat/containers_restart.go
@@ -4,7 +4,10 @@ import (
"net/http"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -12,34 +15,49 @@ import (
func RestartContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+
// /{version}/containers/(name)/restart
query := struct {
- Timeout int `schema:"t"`
+ All bool `schema:"all"`
+ DockerTimeout uint `schema:"t"`
+ LibpodTimeout uint `schema:"timeout"`
}{
- // Override golang default values for types
+ // override any golang type defaults
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- utils.BadRequest(w, "url", r.URL.String(), errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ 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)
- con, err := runtime.LookupContainer(name)
- if err != nil {
- utils.ContainerNotFound(w, name, err)
- return
- }
- timeout := con.StopTimeout()
- if _, found := r.URL.Query()["t"]; found {
- timeout = uint(query.Timeout)
+ options := entities.RestartOptions{
+ All: query.All,
+ Timeout: &query.DockerTimeout,
+ }
+ if utils.IsLibpodRequest(r) {
+ options.Timeout = &query.LibpodTimeout
}
+ report, err := containerEngine.ContainerRestart(r.Context(), []string{name}, options)
+ if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
- if err := con.RestartWithTimeout(r.Context(), timeout); err != nil {
utils.InternalServerError(w, err)
return
}
+ if len(report) > 0 && report[0].Err != nil {
+ utils.InternalServerError(w, report[0].Err)
+ return
+ }
+
// Success
utils.WriteResponse(w, http.StatusNoContent, nil)
}
diff --git a/pkg/api/handlers/compat/containers_stop.go b/pkg/api/handlers/compat/containers_stop.go
index 8bc58cf59..000685aa0 100644
--- a/pkg/api/handlers/compat/containers_stop.go
+++ b/pkg/api/handlers/compat/containers_stop.go
@@ -6,6 +6,8 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -13,10 +15,15 @@ import (
func StopContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
// /{version}/containers/(name)/stop
query := struct {
- Timeout int `schema:"t"`
+ Ignore bool `schema:"ignore"`
+ DockerTimeout uint `schema:"t"`
+ LibpodTimeout uint `schema:"timeout"`
}{
// override any golang type defaults
}
@@ -27,31 +34,46 @@ func StopContainer(w http.ResponseWriter, r *http.Request) {
}
name := utils.GetName(r)
+
+ options := entities.StopOptions{
+ Ignore: query.Ignore,
+ }
+ if utils.IsLibpodRequest(r) {
+ if query.LibpodTimeout > 0 {
+ options.Timeout = &query.LibpodTimeout
+ }
+ } else {
+ if query.DockerTimeout > 0 {
+ options.Timeout = &query.DockerTimeout
+ }
+ }
con, err := runtime.LookupContainer(name)
if err != nil {
utils.ContainerNotFound(w, name, err)
return
}
-
state, err := con.State()
if err != nil {
- utils.InternalServerError(w, errors.Wrapf(err, "unable to get state for Container %s", name))
+ utils.InternalServerError(w, err)
return
}
- // If the Container is stopped already, send a 304
if state == define.ContainerStateStopped || state == define.ContainerStateExited {
utils.WriteResponse(w, http.StatusNotModified, nil)
return
}
+ report, err := containerEngine.ContainerStop(r.Context(), []string{name}, options)
+ if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
- var stopError error
- if query.Timeout > 0 {
- stopError = con.StopWithTimeout(uint(query.Timeout))
- } else {
- stopError = con.Stop()
+ utils.InternalServerError(w, err)
+ return
}
- if stopError != nil {
- utils.InternalServerError(w, errors.Wrapf(stopError, "failed to stop %s", name))
+
+ if len(report) > 0 && report[0].Err != nil {
+ utils.InternalServerError(w, report[0].Err)
return
}
diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go
index 0f3da53e8..c352ac6cd 100644
--- a/pkg/api/handlers/compat/images_push.go
+++ b/pkg/api/handlers/compat/images_push.go
@@ -3,13 +3,15 @@ package compat
import (
"context"
"net/http"
- "os"
"strings"
+ "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/auth"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/infra/abi"
+ "github.com/containers/storage"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -18,11 +20,20 @@ import (
func PushImage(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ imageEngine := abi.ImageEngine{Libpod: runtime}
query := struct {
- Tag string `schema:"tag"`
+ All bool `schema:"all"`
+ Compress bool `schema:"compress"`
+ Destination string `schema:"destination"`
+ Format string `schema:"format"`
+ TLSVerify bool `schema:"tlsVerify"`
+ Tag string `schema:"tag"`
}{
// This is where you can override the golang default value for one of fields
+ TLSVerify: true,
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
@@ -43,39 +54,34 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
return
}
- newImage, err := runtime.ImageRuntime().NewFromLocal(imageName)
- if err != nil {
- utils.ImageNotFound(w, imageName, errors.Wrapf(err, "failed to find image %s", imageName))
- return
- }
-
- authConf, authfile, key, err := auth.GetCredentials(r)
+ authconf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)
-
- dockerRegistryOptions := &image.DockerRegistryOptions{DockerRegistryCreds: authConf}
- if sys := runtime.SystemContext(); sys != nil {
- dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
- dockerRegistryOptions.RegistriesConfPath = sys.SystemRegistriesConfPath
+ var username, password string
+ if authconf != nil {
+ username = authconf.Username
+ password = authconf.Password
+ }
+ options := entities.ImagePushOptions{
+ All: query.All,
+ Authfile: authfile,
+ Compress: query.Compress,
+ Format: query.Format,
+ Password: password,
+ Username: username,
}
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+ if err := imageEngine.Push(context.Background(), imageName, query.Destination, options); err != nil {
+ if errors.Cause(err) != storage.ErrImageUnknown {
+ utils.ImageNotFound(w, imageName, errors.Wrapf(err, "failed to find image %s", imageName))
+ return
+ }
- err = newImage.PushImageToHeuristicDestination(
- context.Background(),
- imageName,
- "", // 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", imageName))
return
}
diff --git a/pkg/api/handlers/compat/images_search.go b/pkg/api/handlers/compat/images_search.go
index 6808cdad5..885112b31 100644
--- a/pkg/api/handlers/compat/images_search.go
+++ b/pkg/api/handlers/compat/images_search.go
@@ -1,25 +1,30 @@
package compat
import (
+ "fmt"
"net/http"
- "strconv"
"github.com/containers/image/v5/types"
- "github.com/containers/podman/v2/libpod/image"
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/auth"
- "github.com/docker/docker/api/types/registry"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
func SearchImages(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Term string `json:"term"`
Limit int `json:"limit"`
+ NoTrunc bool `json:"noTrunc"`
Filters map[string][]string `json:"filters"`
TLSVerify bool `json:"tlsVerify"`
+ ListTags bool `json:"listTags"`
}{
// This is where you can override the golang default value for one of fields
}
@@ -29,67 +34,40 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
return
}
- filter := image.SearchFilter{}
- if len(query.Filters) > 0 {
- if len(query.Filters["stars"]) > 0 {
- stars, err := strconv.Atoi(query.Filters["stars"][0])
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- filter.Stars = stars
- }
- if len(query.Filters["is-official"]) > 0 {
- isOfficial, err := strconv.ParseBool(query.Filters["is-official"][0])
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- filter.IsOfficial = types.NewOptionalBool(isOfficial)
- }
- if len(query.Filters["is-automated"]) > 0 {
- isAutomated, err := strconv.ParseBool(query.Filters["is-automated"][0])
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- filter.IsAutomated = types.NewOptionalBool(isAutomated)
- }
- }
- options := image.SearchOptions{
- Filter: filter,
- Limit: query.Limit,
- }
-
- if _, found := r.URL.Query()["tlsVerify"]; found {
- options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
- }
-
_, 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()))
return
}
defer auth.RemoveAuthfile(authfile)
- options.Authfile = authfile
- results, err := image.SearchImages(query.Term, options)
+ filters := []string{}
+ for key, val := range query.Filters {
+ filters = append(filters, fmt.Sprintf("%s=%s", key, val[0]))
+ }
+
+ options := entities.ImageSearchOptions{
+ Authfile: authfile,
+ Limit: query.Limit,
+ NoTrunc: query.NoTrunc,
+ ListTags: query.ListTags,
+ Filters: filters,
+ }
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+ ir := abi.ImageEngine{Libpod: runtime}
+ reports, err := ir.Search(r.Context(), query.Term, options)
if err != nil {
- utils.BadRequest(w, "term", query.Term, err)
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
-
- compatResults := make([]registry.SearchResult, 0, len(results))
- for _, result := range results {
- compatResult := registry.SearchResult{
- Name: result.Name,
- Description: result.Description,
- StarCount: result.Stars,
- IsAutomated: result.Automated == "[OK]",
- IsOfficial: result.Official == "[OK]",
+ if !utils.IsLibpodRequest(r) {
+ if len(reports) == 0 {
+ utils.ImageNotFound(w, query.Term, define.ErrNoSuchImage)
+ return
}
- compatResults = append(compatResults, compatResult)
}
- utils.WriteResponse(w, http.StatusOK, compatResults)
+ utils.WriteResponse(w, http.StatusOK, reports)
}
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 6b07b1cc5..f6e348cef 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -12,7 +12,6 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/abi"
- "github.com/containers/podman/v2/pkg/ps"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -63,6 +62,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
All bool `schema:"all"`
+ External bool `schema:"external"`
Filters map[string][]string `schema:"filters"`
Last int `schema:"last"` // alias for limit
Limit int `schema:"limit"`
@@ -90,17 +90,22 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
}
runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
opts := entities.ContainerListOptions{
All: query.All,
+ External: query.External,
Filters: query.Filters,
Last: limit,
- Size: query.Size,
- Sort: "",
Namespace: query.Namespace,
- Pod: true,
- Sync: query.Sync,
+ // Always return Pod, should not be part of the API.
+ // https://github.com/containers/podman/pull/7223
+ Pod: true,
+ Size: query.Size,
+ Sync: query.Sync,
}
- pss, err := ps.GetContainerLists(runtime, opts)
+ pss, err := containerEngine.ContainerList(r.Context(), opts)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -143,6 +148,12 @@ func GetContainer(w http.ResponseWriter, r *http.Request) {
func WaitContainer(w http.ResponseWriter, r *http.Request) {
exitCode, err := utils.WaitContainer(w, r)
if err != nil {
+ name := utils.GetName(r)
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+ logrus.Warnf("failed to wait on container %q: %v", name, err)
return
}
utils.WriteResponse(w, http.StatusOK, strconv.Itoa(int(exitCode)))
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 97cd5a65e..3b531652f 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -589,92 +589,6 @@ 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"`
- NoTrunc bool `json:"noTrunc"`
- Filters map[string][]string `json:"filters"`
- TLSVerify bool `json:"tlsVerify"`
- ListTags bool `json:"listTags"`
- }{
- // 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
- }
-
- filter := image.SearchFilter{}
- if len(query.Filters) > 0 {
- if len(query.Filters["stars"]) > 0 {
- stars, err := strconv.Atoi(query.Filters["stars"][0])
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- filter.Stars = stars
- }
- if len(query.Filters["is-official"]) > 0 {
- isOfficial, err := strconv.ParseBool(query.Filters["is-official"][0])
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- filter.IsOfficial = types.NewOptionalBool(isOfficial)
- }
- if len(query.Filters["is-automated"]) > 0 {
- isAutomated, err := strconv.ParseBool(query.Filters["is-automated"][0])
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- filter.IsAutomated = types.NewOptionalBool(isAutomated)
- }
- }
- options := image.SearchOptions{
- Limit: query.Limit,
- NoTrunc: query.NoTrunc,
- ListTags: query.ListTags,
- Filter: filter,
- }
-
- if _, found := r.URL.Query()["tlsVerify"]; found {
- options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
- }
-
- _, 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()))
- return
- }
- defer auth.RemoveAuthfile(authfile)
- options.Authfile = authfile
-
- 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].Description
- reports[i].Stars = searchResults[i].Stars
- reports[i].Official = searchResults[i].Official
- reports[i].Automated = searchResults[i].Automated
- reports[i].Tag = searchResults[i].Tag
- }
-
- utils.WriteResponse(w, http.StatusOK, reports)
-}
-
// ImagesBatchRemove is the endpoint for batch image removal.
func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index 35221ecf1..ded51a31f 100644
--- a/pkg/api/handlers/libpod/manifests.go
+++ b/pkg/api/handlers/libpod/manifests.go
@@ -147,7 +147,6 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) {
query := struct {
All bool `schema:"all"`
Destination string `schema:"destination"`
- Format string `schema:"format"`
TLSVerify bool `schema:"tlsVerify"`
}{
// Add defaults here once needed.
@@ -163,24 +162,21 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) {
}
source := utils.GetName(r)
- authConf, authfile, key, err := auth.GetCredentials(r)
+ 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()))
return
}
defer auth.RemoveAuthfile(authfile)
var username, password string
- if authConf != nil {
- username = authConf.Username
- password = authConf.Password
-
+ if authconf != nil {
+ username = authconf.Username
+ password = authconf.Password
}
-
options := entities.ImagePushOptions{
Authfile: authfile,
Username: username,
Password: password,
- Format: query.Format,
All: query.All,
}
if sys := runtime.SystemContext(); sys != nil {
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index 1439a3a75..fac237f87 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -6,6 +6,8 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -16,10 +18,13 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
interval time.Duration
)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- Interval string `schema:"interval"`
- Condition string `schema:"condition"`
+ Interval string `schema:"interval"`
+ Condition define.ContainerStatus `schema:"condition"`
}{
// Override golang default values for types
}
@@ -27,6 +32,10 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return 0, err
}
+ options := entities.WaitOptions{
+ Condition: define.ContainerStateStopped,
+ }
+ name := GetName(r)
if _, found := r.URL.Query()["interval"]; found {
interval, err = time.ParseDuration(query.Interval)
if err != nil {
@@ -40,19 +49,19 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
return 0, err
}
}
- condition := define.ContainerStateStopped
+ options.Interval = interval
+
if _, found := r.URL.Query()["condition"]; found {
- condition, err = define.StringToContainerStatus(query.Condition)
- if err != nil {
- InternalServerError(w, err)
- return 0, err
- }
+ options.Condition = query.Condition
}
- name := GetName(r)
- con, err := runtime.LookupContainer(name)
+
+ report, err := containerEngine.ContainerWait(r.Context(), []string{name}, options)
if err != nil {
- ContainerNotFound(w, name, err)
return 0, err
}
- return con.WaitForConditionWithInterval(interval, condition)
+ if len(report) == 0 {
+ InternalServerError(w, errors.New("No reports returned"))
+ return 0, err
+ }
+ return report[0].ExitCode, report[0].Error
}