summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/annotations/annotations.go2
-rw-r--r--pkg/api/handlers/compat/containers.go49
-rw-r--r--pkg/api/handlers/compat/containers_archive.go97
-rw-r--r--pkg/api/handlers/compat/containers_create.go15
-rw-r--r--pkg/api/handlers/compat/containers_prune.go34
-rw-r--r--pkg/api/handlers/compat/events.go8
-rw-r--r--pkg/api/handlers/compat/images.go17
-rw-r--r--pkg/api/handlers/compat/images_search.go16
-rw-r--r--pkg/api/handlers/compat/info.go2
-rw-r--r--pkg/api/handlers/compat/networks.go6
-rw-r--r--pkg/api/handlers/compat/resize.go8
-rw-r--r--pkg/api/handlers/compat/volumes.go20
-rw-r--r--pkg/api/handlers/libpod/images.go81
-rw-r--r--pkg/api/handlers/libpod/images_pull.go4
-rw-r--r--pkg/api/handlers/libpod/system.go19
-rw-r--r--pkg/api/handlers/libpod/volumes.go28
-rw-r--r--pkg/api/handlers/utils/pods.go4
-rw-r--r--pkg/api/server/register_archive.go10
-rw-r--r--pkg/api/server/register_containers.go1
-rw-r--r--pkg/api/server/register_images.go2
-rw-r--r--pkg/api/server/server.go2
-rw-r--r--pkg/api/server/swagger.go3
-rw-r--r--pkg/autoupdate/autoupdate.go2
-rw-r--r--pkg/bindings/connection.go49
-rw-r--r--pkg/bindings/containers/archive.go92
-rw-r--r--pkg/bindings/containers/attach.go67
-rw-r--r--pkg/bindings/containers/checkpoint.go57
-rw-r--r--pkg/bindings/containers/commit.go33
-rw-r--r--pkg/bindings/containers/containers.go182
-rw-r--r--pkg/bindings/containers/create.go6
-rw-r--r--pkg/bindings/containers/diff.go6
-rw-r--r--pkg/bindings/containers/exec.go12
-rw-r--r--pkg/bindings/containers/healthcheck.go6
-rw-r--r--pkg/bindings/containers/logs.go32
-rw-r--r--pkg/bindings/containers/mount.go18
-rw-r--r--pkg/bindings/containers/types.go206
-rw-r--r--pkg/bindings/containers/types_attach_options.go136
-rw-r--r--pkg/bindings/containers/types_checkpoint_options.go168
-rw-r--r--pkg/bindings/containers/types_commit_options.go200
-rw-r--r--pkg/bindings/containers/types_create_options.go88
-rw-r--r--pkg/bindings/containers/types_diff_options.go88
-rw-r--r--pkg/bindings/containers/types_execinspect_options.go88
-rw-r--r--pkg/bindings/containers/types_execstart_options.go88
-rw-r--r--pkg/bindings/containers/types_execstartandattach_options.go186
-rw-r--r--pkg/bindings/containers/types_export_options.go88
-rw-r--r--pkg/bindings/containers/types_healthcheck_options.go88
-rw-r--r--pkg/bindings/containers/types_init_options.go88
-rw-r--r--pkg/bindings/containers/types_inspect_options.go104
-rw-r--r--pkg/bindings/containers/types_kill_options.go88
-rw-r--r--pkg/bindings/containers/types_list_options.go186
-rw-r--r--pkg/bindings/containers/types_log_options.go200
-rw-r--r--pkg/bindings/containers/types_mount_options.go88
-rw-r--r--pkg/bindings/containers/types_mountedcontainerpaths_options.go88
-rw-r--r--pkg/bindings/containers/types_pause_options.go88
-rw-r--r--pkg/bindings/containers/types_prune_options.go104
-rw-r--r--pkg/bindings/containers/types_remove_options.go120
-rw-r--r--pkg/bindings/containers/types_resizeexectty_options.go120
-rw-r--r--pkg/bindings/containers/types_resizetty_options.go120
-rw-r--r--pkg/bindings/containers/types_restart_options.go104
-rw-r--r--pkg/bindings/containers/types_restore_options.go200
-rw-r--r--pkg/bindings/containers/types_shouldrestart_options.go88
-rw-r--r--pkg/bindings/containers/types_start_options.go104
-rw-r--r--pkg/bindings/containers/types_stats_options.go104
-rw-r--r--pkg/bindings/containers/types_stop_options.go104
-rw-r--r--pkg/bindings/containers/types_top_options.go104
-rw-r--r--pkg/bindings/containers/types_unmount_options.go88
-rw-r--r--pkg/bindings/containers/types_unpause_options.go88
-rw-r--r--pkg/bindings/containers/types_wait_options.go105
-rw-r--r--pkg/bindings/generate/generate.go35
-rw-r--r--pkg/bindings/generate/types.go27
-rw-r--r--pkg/bindings/generate/types_kube_options.go104
-rw-r--r--pkg/bindings/generate/types_systemd_options.go200
-rw-r--r--pkg/bindings/generator/generator.go261
-rw-r--r--pkg/bindings/images/diff.go6
-rw-r--r--pkg/bindings/images/images.go211
-rw-r--r--pkg/bindings/images/pull.go26
-rw-r--r--pkg/bindings/images/rm.go45
-rw-r--r--pkg/bindings/images/types.go193
-rw-r--r--pkg/bindings/images/types_diff_options.go88
-rw-r--r--pkg/bindings/images/types_export_options.go120
-rw-r--r--pkg/bindings/images/types_get_options.go104
-rw-r--r--pkg/bindings/images/types_history_options.go88
-rw-r--r--pkg/bindings/images/types_import_options.go152
-rw-r--r--pkg/bindings/images/types_list_options.go120
-rw-r--r--pkg/bindings/images/types_load_options.go104
-rw-r--r--pkg/bindings/images/types_prune_options.go120
-rw-r--r--pkg/bindings/images/types_pull_options.go281
-rw-r--r--pkg/bindings/images/types_push_options.go280
-rw-r--r--pkg/bindings/images/types_remove_options.go120
-rw-r--r--pkg/bindings/images/types_search_options.go184
-rw-r--r--pkg/bindings/images/types_tag_options.go88
-rw-r--r--pkg/bindings/images/types_tree_options.go104
-rw-r--r--pkg/bindings/images/types_untag_options.go88
-rw-r--r--pkg/bindings/manifests/manifests.go52
-rw-r--r--pkg/bindings/manifests/types.go36
-rw-r--r--pkg/bindings/manifests/types_add_options.go216
-rw-r--r--pkg/bindings/manifests/types_create_options.go104
-rw-r--r--pkg/bindings/manifests/types_inspect_options.go88
-rw-r--r--pkg/bindings/manifests/types_push_options.go104
-rw-r--r--pkg/bindings/manifests/types_remove_options.go88
-rw-r--r--pkg/bindings/network/network.go80
-rw-r--r--pkg/bindings/network/types.go70
-rw-r--r--pkg/bindings/network/types_connect_options.go104
-rw-r--r--pkg/bindings/network/types_create_options.go265
-rw-r--r--pkg/bindings/network/types_disconnect_options.go104
-rw-r--r--pkg/bindings/network/types_inspect_options.go88
-rw-r--r--pkg/bindings/network/types_list_options.go104
-rw-r--r--pkg/bindings/network/types_remove_options.go104
-rw-r--r--pkg/bindings/play/play.go24
-rw-r--r--pkg/bindings/play/types.go32
-rw-r--r--pkg/bindings/play/types_kube_options.go280
-rw-r--r--pkg/bindings/pods/pods.go113
-rw-r--r--pkg/bindings/pods/types.go72
-rw-r--r--pkg/bindings/pods/types_create_options.go88
-rw-r--r--pkg/bindings/pods/types_inspect_options.go88
-rw-r--r--pkg/bindings/pods/types_kill_options.go104
-rw-r--r--pkg/bindings/pods/types_list_options.go104
-rw-r--r--pkg/bindings/pods/types_pause_options.go88
-rw-r--r--pkg/bindings/pods/types_prune_options.go88
-rw-r--r--pkg/bindings/pods/types_remove_options.go104
-rw-r--r--pkg/bindings/pods/types_restart_options.go88
-rw-r--r--pkg/bindings/pods/types_start_options.go88
-rw-r--r--pkg/bindings/pods/types_stats_options.go104
-rw-r--r--pkg/bindings/pods/types_stop_options.go104
-rw-r--r--pkg/bindings/pods/types_top_options.go104
-rw-r--r--pkg/bindings/pods/types_unpause_options.go88
-rw-r--r--pkg/bindings/system/info.go6
-rw-r--r--pkg/bindings/system/system.go53
-rw-r--r--pkg/bindings/system/types.go34
-rw-r--r--pkg/bindings/system/types_disk_options.go88
-rw-r--r--pkg/bindings/system/types_events_options.go152
-rw-r--r--pkg/bindings/system/types_info_options.go88
-rw-r--r--pkg/bindings/system/types_prune_options.go136
-rw-r--r--pkg/bindings/system/types_version_options.go88
-rw-r--r--pkg/bindings/test/attach_test.go17
-rw-r--r--pkg/bindings/test/auth_test.go42
-rw-r--r--pkg/bindings/test/common_test.go4
-rw-r--r--pkg/bindings/test/containers_test.go132
-rw-r--r--pkg/bindings/test/create_test.go2
-rw-r--r--pkg/bindings/test/exec_test.go4
-rw-r--r--pkg/bindings/test/images_test.go106
-rw-r--r--pkg/bindings/test/info_test.go12
-rw-r--r--pkg/bindings/test/manifests_test.go33
-rw-r--r--pkg/bindings/test/pods_test.go81
-rw-r--r--pkg/bindings/test/system_test.go106
-rw-r--r--pkg/bindings/test/volumes_test.go81
-rw-r--r--pkg/bindings/volumes/types.go32
-rw-r--r--pkg/bindings/volumes/types_create_options.go88
-rw-r--r--pkg/bindings/volumes/types_inspect_options.go88
-rw-r--r--pkg/bindings/volumes/types_list_options.go104
-rw-r--r--pkg/bindings/volumes/types_prune_options.go104
-rw-r--r--pkg/bindings/volumes/types_remove_options.go104
-rw-r--r--pkg/bindings/volumes/volumes.go45
-rw-r--r--pkg/cgroups/cgroups.go2
-rw-r--r--pkg/copy/copy.go220
-rw-r--r--pkg/copy/fileinfo.go57
-rw-r--r--pkg/copy/item.go588
-rw-r--r--pkg/domain/entities/container_ps.go2
-rw-r--r--pkg/domain/entities/containers.go25
-rw-r--r--pkg/domain/entities/engine_container.go12
-rw-r--r--pkg/domain/entities/engine_image.go5
-rw-r--r--pkg/domain/entities/images.go8
-rw-r--r--pkg/domain/entities/reports/prune.go40
-rw-r--r--pkg/domain/entities/system.go15
-rw-r--r--pkg/domain/entities/volumes.go8
-rw-r--r--pkg/domain/filters/containers.go238
-rw-r--r--pkg/domain/filters/helpers.go20
-rw-r--r--pkg/domain/filters/pods.go139
-rw-r--r--pkg/domain/filters/volumes.go3
-rw-r--r--pkg/domain/infra/abi/archive.go172
-rw-r--r--pkg/domain/infra/abi/containers.go34
-rw-r--r--pkg/domain/infra/abi/containers_stat.go251
-rw-r--r--pkg/domain/infra/abi/cp.go70
-rw-r--r--pkg/domain/infra/abi/images.go85
-rw-r--r--pkg/domain/infra/abi/manifest.go17
-rw-r--r--pkg/domain/infra/abi/parse/parse.go6
-rw-r--r--pkg/domain/infra/abi/play.go18
-rw-r--r--pkg/domain/infra/abi/pods.go4
-rw-r--r--pkg/domain/infra/abi/system.go49
-rw-r--r--pkg/domain/infra/abi/volumes.go22
-rw-r--r--pkg/domain/infra/runtime_abi.go4
-rw-r--r--pkg/domain/infra/runtime_tunnel.go28
-rw-r--r--pkg/domain/infra/tunnel/containers.go301
-rw-r--r--pkg/domain/infra/tunnel/events.go4
-rw-r--r--pkg/domain/infra/tunnel/generate.go14
-rw-r--r--pkg/domain/infra/tunnel/healthcheck.go2
-rw-r--r--pkg/domain/infra/tunnel/helpers.go9
-rw-r--r--pkg/domain/infra/tunnel/images.go175
-rw-r--r--pkg/domain/infra/tunnel/manifest.go29
-rw-r--r--pkg/domain/infra/tunnel/network.go34
-rw-r--r--pkg/domain/infra/tunnel/play.go15
-rw-r--r--pkg/domain/infra/tunnel/pods.go75
-rw-r--r--pkg/domain/infra/tunnel/runtime.go6
-rw-r--r--pkg/domain/infra/tunnel/system.go11
-rw-r--r--pkg/domain/infra/tunnel/volumes.go20
-rw-r--r--pkg/errorhandling/errorhandling.go7
-rw-r--r--pkg/hooks/README.md2
-rw-r--r--pkg/hooks/exec/exec.go2
-rw-r--r--pkg/hooks/hooks.go2
-rw-r--r--pkg/netns/netns_linux.go2
-rw-r--r--pkg/ps/ps.go43
-rw-r--r--pkg/rootless/rootless_linux.go2
-rw-r--r--pkg/seccomp/seccomp.go2
-rw-r--r--pkg/signal/signal_linux.go1
-rw-r--r--pkg/signal/signal_linux_mipsx.go106
-rw-r--r--pkg/specgen/generate/container.go2
-rw-r--r--pkg/specgen/generate/kube/kube.go105
-rw-r--r--pkg/specgen/generate/oci.go2
-rw-r--r--pkg/specgen/generate/security.go6
-rw-r--r--pkg/specgen/generate/storage.go2
-rw-r--r--pkg/specgen/pod_validate.go2
-rw-r--r--pkg/specgen/specgen.go4
-rw-r--r--pkg/systemd/generate/common.go5
-rw-r--r--pkg/systemd/generate/containers.go10
-rw-r--r--pkg/systemd/generate/containers_test.go43
-rw-r--r--pkg/systemd/generate/pods.go8
-rw-r--r--pkg/systemd/generate/pods_test.go15
-rw-r--r--pkg/terminal/util.go9
-rw-r--r--pkg/util/utils_linux.go17
-rw-r--r--pkg/util/utils_supported.go2
-rw-r--r--pkg/util/utils_unsupported.go5
221 files changed, 14083 insertions, 2404 deletions
diff --git a/pkg/annotations/annotations.go b/pkg/annotations/annotations.go
index 19b1029d1..8badab20d 100644
--- a/pkg/annotations/annotations.go
+++ b/pkg/annotations/annotations.go
@@ -94,7 +94,7 @@ const (
// StdinOnce is the stdin_once annotation
StdinOnce = "io.kubernetes.cri-o.StdinOnce"
- // Volumes is the volumes annotatoin
+ // Volumes is the volumes annotation
Volumes = "io.kubernetes.cri-o.Volumes"
// HostNetwork indicates whether the host network namespace is used or not
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 7a3e5dd84..0f89c859e 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "sort"
"strconv"
"strings"
"syscall"
@@ -13,6 +14,8 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
+ "github.com/containers/podman/v2/pkg/domain/filters"
+ "github.com/containers/podman/v2/pkg/ps"
"github.com/containers/podman/v2/pkg/signal"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
@@ -78,10 +81,6 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
}
func ListContainers(w http.ResponseWriter, r *http.Request) {
- var (
- containers []*libpod.Container
- err error
- )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
@@ -97,22 +96,48 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- if query.All {
- containers, err = runtime.GetAllContainers()
- } else {
- containers, err = runtime.GetRunningContainers()
+
+ filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters))
+ all := query.All || query.Limit > 0
+ if len(query.Filters) > 0 {
+ for k, v := range query.Filters {
+ generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, 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 := filters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ filterFuncs = append(filterFuncs, runningOnly)
+ }
+
+ containers, err := runtime.GetContainers(filterFuncs...)
if err != nil {
utils.InternalServerError(w, err)
return
}
if _, found := r.URL.Query()["limit"]; found && query.Limit > 0 {
- last := query.Limit
- if len(containers) > last {
- containers = containers[len(containers)-last:]
+ // Sort the libpod containers
+ sort.Sort(ps.SortCreateTime{SortContainers: containers})
+ // we should perform the lopping before we start getting
+ // the expensive information on containers
+ if len(containers) > query.Limit {
+ containers = containers[:query.Limit]
}
}
- // TODO filters still need to be applied
var list = make([]*handlers.Container, len(containers))
for i, ctnr := range containers {
api, err := LibpodToContainer(ctnr, query.Size)
diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go
index d8197415c..083c72ce8 100644
--- a/pkg/api/handlers/compat/containers_archive.go
+++ b/pkg/api/handlers/compat/containers_archive.go
@@ -3,11 +3,13 @@ package compat
import (
"fmt"
"net/http"
+ "os"
"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/copy"
+ "github.com/containers/podman/v2/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -44,58 +46,47 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De
}
containerName := utils.GetName(r)
-
- ctr, err := runtime.LookupContainer(containerName)
- if errors.Cause(err) == define.ErrNoSuchCtr {
- utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrap(err, "the container doesn't exists"))
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+ statReport, err := containerEngine.ContainerStat(r.Context(), containerName, query.Path)
+
+ // NOTE
+ // The statReport may actually be set even in case of an error. That's
+ // the case when we're looking at a symlink pointing to nirvana. In
+ // such cases, we really need the FileInfo but we also need the error.
+ if statReport != nil {
+ statHeader, err := copy.EncodeFileInfo(&statReport.FileInfo)
+ if err != nil {
+ utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ return
+ }
+ w.Header().Add(copy.XDockerContainerPathStatHeader, statHeader)
+ }
+
+ if errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == copy.ENOENT {
+ // 404 is returned for an absent container and path. The
+ // clients must deal with it accordingly.
+ utils.Error(w, "Not found.", http.StatusNotFound, err)
return
} else if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- source, err := copy.CopyItemForContainer(ctr, query.Path, true, true)
- defer source.CleanUp()
- if err != nil {
- utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
- return
- }
-
- // NOTE: Docker always sets the header.
- info, err := source.Stat()
- if err != nil {
- utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
- return
- }
- statHeader, err := copy.EncodeFileInfo(info)
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
- w.Header().Add(copy.XDockerContainerPathStatHeader, statHeader)
-
// Our work is done when the user is interested in the header only.
if r.Method == http.MethodHead {
w.WriteHeader(http.StatusOK)
return
}
- // Alright, the users wants data from the container.
- destination, err := copy.CopyItemForWriter(w)
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
-
- copier, err := copy.GetCopier(&source, &destination, false)
+ copyFunc, err := containerEngine.ContainerCopyToArchive(r.Context(), containerName, query.Path, w)
if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
+ w.Header().Set("Content-Type", "application/x-tar")
w.WriteHeader(http.StatusOK)
- if err := copier.Copy(); err != nil {
- logrus.Errorf("Error during copy: %v", err)
- return
+ if err := copyFunc(); err != nil {
+ logrus.Error(err.Error())
}
}
@@ -113,36 +104,22 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder,
return
}
- ctrName := utils.GetName(r)
-
- ctr, err := runtime.LookupContainer(ctrName)
- if err != nil {
- utils.Error(w, "Not found", http.StatusNotFound, errors.Wrapf(err, "the %s container doesn't exists", ctrName))
- return
- }
+ containerName := utils.GetName(r)
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
- destination, err := copy.CopyItemForContainer(ctr, query.Path, true, false)
- defer destination.CleanUp()
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ copyFunc, err := containerEngine.ContainerCopyFromArchive(r.Context(), containerName, query.Path, r.Body)
+ if errors.Cause(err) == define.ErrNoSuchCtr || os.IsNotExist(err) {
+ // 404 is returned for an absent container and path. The
+ // clients must deal with it accordingly.
+ utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrap(err, "the container doesn't exists"))
return
- }
-
- source, err := copy.CopyItemForReader(r.Body)
- defer source.CleanUp()
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ } else if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- copier, err := copy.GetCopier(&source, &destination, false)
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
w.WriteHeader(http.StatusOK)
- if err := copier.Copy(); err != nil {
- logrus.Errorf("Error during copy: %v", err)
- return
+ if err := copyFunc(); err != nil {
+ logrus.Error(err.Error())
}
}
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 409a74de2..6e85872b2 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -66,7 +66,20 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "make cli opts()"))
return
}
- sg := specgen.NewSpecGenerator(newImage.ID(), cliOpts.RootFS)
+
+ 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)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
+ return
+ }
+ // maybe the InputName has no tag, so use full name to display
+ imgNameOrID = imageRef.DockerReference().String()
+ }
+
+ sg := specgen.NewSpecGenerator(imgNameOrID, cliOpts.RootFS)
if err := common.FillOutSpecGen(sg, cliOpts, args); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "fill out specgen"))
return
diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go
index 2cfeebcce..b3d26b8f4 100644
--- a/pkg/api/handlers/compat/containers_prune.go
+++ b/pkg/api/handlers/compat/containers_prune.go
@@ -4,19 +4,14 @@ import (
"net/http"
"github.com/containers/podman/v2/libpod"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
- "github.com/containers/podman/v2/pkg/domain/entities"
- "github.com/docker/docker/api/types"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
+ "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
func PruneContainers(w http.ResponseWriter, r *http.Request) {
- var (
- delContainers []string
- space int64
- )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
@@ -29,7 +24,7 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
}
filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters))
for k, v := range query.Filters {
- generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, runtime)
+ generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -49,36 +44,21 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
return
}
- prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+ report, err := runtime.PruneContainers(filterFuncs)
if err != nil {
utils.InternalServerError(w, err)
return
}
- for ctrID, size := range prunedContainers {
- if pruneErrors[ctrID] == nil {
- space += size
- delContainers = append(delContainers, ctrID)
- }
- }
- report := types.ContainersPruneReport{
- ContainersDeleted: delContainers,
- SpaceReclaimed: uint64(space),
- }
utils.WriteResponse(w, http.StatusOK, report)
}
func PruneContainersHelper(w http.ResponseWriter, r *http.Request, filterFuncs []libpod.ContainerFilter) (
- *entities.ContainerPruneReport, error) {
+ []*reports.PruneReport, error) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
- prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+ reports, err := runtime.PruneContainers(filterFuncs)
if err != nil {
utils.InternalServerError(w, err)
return nil, err
}
-
- report := &entities.ContainerPruneReport{
- Err: pruneErrors,
- ID: prunedContainers,
- }
- return report, nil
+ return reports, nil
}
diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go
index f74491a8f..82a74e419 100644
--- a/pkg/api/handlers/compat/events.go
+++ b/pkg/api/handlers/compat/events.go
@@ -33,6 +33,8 @@ func filtersFromRequest(r *http.Request) ([]string, error) {
if _, found := r.URL.Query()["filters"]; found {
raw = []byte(r.Form.Get("filters"))
+ } else if _, found := r.URL.Query()["Filters"]; found {
+ raw = []byte(r.Form.Get("Filters"))
} else {
return []string{}, nil
}
@@ -73,7 +75,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
)
// NOTE: the "filters" parameter is extracted separately for backwards
- // compat via `fitlerFromRequest()`.
+ // compat via `filterFromRequest()`.
query := struct {
Since string `schema:"since"`
Until string `schema:"until"`
@@ -95,7 +97,6 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "failed to parse parameters", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
-
eventChannel := make(chan *events.Event)
errorChannel := make(chan error)
@@ -110,6 +111,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
Until: query.Until,
}
errorChannel <- runtime.Events(r.Context(), readOpts)
+
}()
var flush = func() {}
@@ -130,8 +132,8 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
if err != nil {
// FIXME StatusOK already sent above cannot send 500 here
utils.InternalServerError(w, err)
- return
}
+ return
case evt := <-eventChannel:
if evt == nil {
continue
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index a51dd8ed3..9d7503aba 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -22,6 +22,7 @@ import (
"github.com/gorilla/schema"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// mergeNameAndTagOrDigest creates an image reference as string from the
@@ -98,21 +99,23 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
filters = append(filters, fmt.Sprintf("%s=%s", k, val))
}
}
- pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
if err != nil {
utils.InternalServerError(w, err)
return
}
- for _, p := range pruneCids {
+ reclaimedSpace := uint64(0)
+ for _, p := range imagePruneReports {
idr = append(idr, types.ImageDeleteResponseItem{
- Deleted: p,
+ Deleted: p.Id,
})
+ reclaimedSpace = reclaimedSpace + p.Size
}
// FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
ipr := types.ImagesPruneReport{
ImagesDeleted: idr,
- SpaceReclaimed: 1, // TODO we cannot supply this right now
+ SpaceReclaimed: reclaimedSpace,
}
utils.WriteResponse(w, http.StatusOK, handlers.ImagesPruneReport{ImagesPruneReport: ipr})
}
@@ -386,6 +389,12 @@ func LoadImages(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile"))
return
}
+ defer func() {
+ err := os.Remove(f.Name())
+ if err != nil {
+ logrus.Errorf("Failed to remove temporary file: %v.", err)
+ }
+ }()
if err := SaveFromBody(f, r); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file"))
return
diff --git a/pkg/api/handlers/compat/images_search.go b/pkg/api/handlers/compat/images_search.go
index b3ceae3ee..6808cdad5 100644
--- a/pkg/api/handlers/compat/images_search.go
+++ b/pkg/api/handlers/compat/images_search.go
@@ -8,6 +8,7 @@ import (
"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/docker/docker/api/types/registry"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -77,5 +78,18 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
utils.BadRequest(w, "term", query.Term, err)
return
}
- utils.WriteResponse(w, http.StatusOK, results)
+
+ 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]",
+ }
+ compatResults = append(compatResults, compatResult)
+ }
+
+ utils.WriteResponse(w, http.StatusOK, compatResults)
}
diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go
index 4b3a390f1..5adbeb031 100644
--- a/pkg/api/handlers/compat/info.go
+++ b/pkg/api/handlers/compat/info.go
@@ -48,7 +48,7 @@ func GetInfo(w http.ResponseWriter, r *http.Request) {
stateInfo := getContainersState(runtime)
sysInfo := sysinfo.New(true)
- // FIXME: Need to expose if runtime supports Checkpoint'ing
+ // FIXME: Need to expose if runtime supports Checkpointing
// liveRestoreEnabled := criu.CheckForCriu() && configInfo.RuntimeSupportsCheckpoint()
info := &handlers.Info{Info: docker.Info{
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index fe13971b0..f0b922885 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -131,7 +131,7 @@ func getNetworkResourceByNameOrID(nameOrID string, runtime *libpod.Runtime, filt
Name: conf.Name,
ID: network.GetNetworkID(conf.Name),
Created: time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)), // nolint: unconvert
- Scope: "",
+ Scope: "local",
Driver: network.DefaultNetworkDriver,
EnableIPv6: false,
IPAM: dockerNetwork.IPAM{
@@ -197,7 +197,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
}
var reports []*types.NetworkResource
- logrus.Errorf("netNames: %q", strings.Join(netNames, ", "))
+ logrus.Debugf("netNames: %q", strings.Join(netNames, ", "))
for _, name := range netNames {
report, err := getNetworkResourceByNameOrID(name, runtime, query.Filters)
if err != nil {
@@ -239,7 +239,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
Internal: networkCreate.Internal,
Labels: networkCreate.Labels,
}
- if networkCreate.IPAM != nil && networkCreate.IPAM.Config != nil {
+ if networkCreate.IPAM != nil && len(networkCreate.IPAM.Config) > 0 {
if len(networkCreate.IPAM.Config) > 1 {
utils.InternalServerError(w, errors.New("compat network create can only support one IPAM config"))
return
diff --git a/pkg/api/handlers/compat/resize.go b/pkg/api/handlers/compat/resize.go
index bdc051d73..cc8c6ef0a 100644
--- a/pkg/api/handlers/compat/resize.go
+++ b/pkg/api/handlers/compat/resize.go
@@ -20,8 +20,8 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
// /containers/{id}/resize
query := struct {
- height uint16 `schema:"h"`
- width uint16 `schema:"w"`
+ Height uint16 `schema:"h"`
+ Width uint16 `schema:"w"`
}{
// override any golang type defaults
}
@@ -33,8 +33,8 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
}
sz := remotecommand.TerminalSize{
- Width: query.width,
- Height: query.height,
+ Width: query.Width,
+ Height: query.Height,
}
var status int
diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go
index 71b848932..1188d8f84 100644
--- a/pkg/api/handlers/compat/volumes.go
+++ b/pkg/api/handlers/compat/volumes.go
@@ -3,6 +3,7 @@ package compat
import (
"encoding/json"
"net/http"
+ "net/url"
"time"
"github.com/containers/podman/v2/libpod"
@@ -207,7 +208,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
* using the volume at the same time".
*
* With this in mind, we only consider the `force` query parameter when we
- * hunt for specified volume by name, using it to seletively return a 204
+ * hunt for specified volume by name, using it to selectively return a 204
* or blow up depending on `force` being truthy or falsey/unset
* respectively.
*/
@@ -230,7 +231,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
utils.VolumeNotFound(w, name, err)
} else {
// Volume does not exist and `force` is truthy - this emulates what
- // Docker would do when told to `force` removal of a nonextant
+ // Docker would do when told to `force` removal of a nonexistent
// volume
utils.WriteResponse(w, http.StatusNoContent, nil)
}
@@ -254,22 +255,23 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- // TODO: We have no ability to pass pruning filters to `PruneVolumes()` so
- // we'll explicitly reject the request if we see any
- if len(query.Filters) > 0 {
- utils.InternalServerError(w, errors.New("filters for pruning volumes is not implemented"))
+
+ f := (url.Values)(query.Filters)
+ filterFuncs, err := filters.GenerateVolumeFilters(f)
+ if err != nil {
+ utils.Error(w, "Something when wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse filters for %s", f.Encode()))
return
}
- pruned, err := runtime.PruneVolumes(r.Context())
+ pruned, err := runtime.PruneVolumes(r.Context(), filterFuncs)
if err != nil {
utils.InternalServerError(w, err)
return
}
prunedIds := make([]string, 0, len(pruned))
- for k := range pruned {
+ for _, v := range pruned {
// XXX: This drops any pruning per-volume error messages on the floor
- prunedIds = append(prunedIds, k)
+ prunedIds = append(prunedIds, v.Id)
}
pruneResponse := docker_api_types.VolumesPruneReport{
VolumesDeleted: prunedIds,
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 6145207ca..979a8adc4 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -51,7 +51,7 @@ func ImageExists(w http.ResponseWriter, r *http.Request) {
return
}
if !report.Value {
- utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(nil, "failed to find image %s", name))
+ utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Errorf("failed to find image %s", name))
return
}
utils.WriteResponse(w, http.StatusNoContent, "")
@@ -156,12 +156,12 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
}
}
- cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- utils.WriteResponse(w, http.StatusOK, cids)
+ utils.WriteResponse(w, http.StatusOK, imagePruneReports)
}
func ExportImage(w http.ResponseWriter, r *http.Request) {
@@ -265,8 +265,14 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
// Format is mandatory! Currently, we only support multi-image docker
// archives.
+ if len(query.References) > 1 && query.Format != define.V2s2Archive {
+ utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("multi-image archives must use format of %s", define.V2s2Archive))
+ return
+
+ }
+
switch query.Format {
- case define.V2s2Archive:
+ case define.V2s2Archive, define.OCIArchive:
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"))
@@ -277,6 +283,13 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
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 tmpdir"))
+ return
+ }
+ output = tmpdir
default:
utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("unsupported format %q", query.Format))
return
@@ -287,7 +300,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
opts := entities.ImageSaveOptions{
Compress: query.Compress,
Format: query.Format,
- MultiImageArchive: true,
+ MultiImageArchive: len(query.References) > 1,
Output: output,
RemoveSignatures: true,
}
@@ -414,7 +427,6 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
}{
// 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
@@ -607,12 +619,12 @@ func UntagImage(w http.ResponseWriter, r *http.Request) {
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 []string `json:"filters"`
- TLSVerify bool `json:"tlsVerify"`
- ListTags bool `json:"listTags"`
+ 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
}
@@ -622,24 +634,44 @@ 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{
Limit: query.Limit,
NoTrunc: query.NoTrunc,
ListTags: query.ListTags,
+ Filter: filter,
}
+
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
- }
-
_, 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()))
@@ -678,10 +710,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
All bool `schema:"all"`
Force bool `schema:"force"`
Images []string `schema:"images"`
- }{
- All: false,
- Force: false,
- }
+ }{}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
@@ -690,10 +719,8 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
}
opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force}
-
imageEngine := abi.ImageEngine{Libpod: runtime}
rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts)
-
strErrs := errorhandling.ErrorsToStrings(rmErrors)
report := handlers.LibpodImagesRemoveReport{ImageRemoveReport: *rmReport, Errors: strErrs}
utils.WriteResponse(w, http.StatusOK, report)
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
index 5e2727e95..bacba006d 100644
--- a/pkg/api/handlers/libpod/images_pull.go
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -115,10 +115,10 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
}
}
- writer := channel.NewWriter(make(chan []byte, 1))
+ writer := channel.NewWriter(make(chan []byte))
defer writer.Close()
- stderr := channel.NewWriter(make(chan []byte, 1))
+ stderr := channel.NewWriter(make(chan []byte))
defer stderr.Close()
images := make([]string, 0, len(imagesToPull))
diff --git a/pkg/api/handlers/libpod/system.go b/pkg/api/handlers/libpod/system.go
index b157dfc7b..130e563ae 100644
--- a/pkg/api/handlers/libpod/system.go
+++ b/pkg/api/handlers/libpod/system.go
@@ -38,35 +38,28 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
systemPruneReport.PodPruneReport = podPruneReport
// We could parallelize this, should we?
- containerPruneReport, err := compat.PruneContainersHelper(w, r, nil)
+ containerPruneReports, err := compat.PruneContainersHelper(w, r, nil)
if err != nil {
utils.InternalServerError(w, err)
return
}
- systemPruneReport.ContainerPruneReport = containerPruneReport
+ systemPruneReport.ContainerPruneReports = containerPruneReports
- results, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
if err != nil {
utils.InternalServerError(w, err)
return
}
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
-
- systemPruneReport.ImagePruneReport = &report
+ systemPruneReport.ImagePruneReports = imagePruneReports
if query.Volumes {
- volumePruneReport, err := pruneVolumesHelper(r)
+ volumePruneReports, err := pruneVolumesHelper(r)
if err != nil {
utils.InternalServerError(w, err)
return
}
- systemPruneReport.VolumePruneReport = volumePruneReport
+ systemPruneReport.VolumePruneReports = volumePruneReports
}
utils.WriteResponse(w, http.StatusOK, systemPruneReport)
}
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index b0d40fd8b..6f9537515 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -3,11 +3,13 @@ package libpod
import (
"encoding/json"
"net/http"
+ "net/url"
"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/entities/reports"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
"github.com/gorilla/schema"
@@ -177,20 +179,30 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, reports)
}
-func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) {
+func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
+ decoder = r.Context().Value("decoder").(*schema.Decoder)
)
- pruned, err := runtime.PruneVolumes(r.Context())
+ query := struct {
+ Filters map[string][]string `schema:"filters"`
+ }{
+ // override any golang type defaults
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ return nil, err
+ }
+
+ f := (url.Values)(query.Filters)
+ filterFuncs, err := filters.GenerateVolumeFilters(f)
if err != nil {
return nil, err
}
- reports := make([]*entities.VolumePruneReport, 0, len(pruned))
- for k, v := range pruned {
- reports = append(reports, &entities.VolumePruneReport{
- Err: v,
- Id: k,
- })
+
+ reports, err := runtime.PruneVolumes(r.Context(), filterFuncs)
+ if err != nil {
+ return nil, err
}
return reports, nil
}
diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go
index 7506dbfd1..0fe3a308b 100644
--- a/pkg/api/handlers/utils/pods.go
+++ b/pkg/api/handlers/utils/pods.go
@@ -4,8 +4,8 @@ import (
"net/http"
"github.com/containers/podman/v2/libpod"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/domain/entities"
+ dfilters "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/gorilla/schema"
)
@@ -31,7 +31,7 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport
filters := make([]libpod.PodFilter, 0, len(query.Filters))
for k, v := range query.Filters {
- f, err := lpfilters.GeneratePodFilterFunc(k, v)
+ f, err := dfilters.GeneratePodFilterFunc(k, v)
if err != nil {
return nil, err
}
diff --git a/pkg/api/server/register_archive.go b/pkg/api/server/register_archive.go
index b2d2543c4..b20d89cc2 100644
--- a/pkg/api/server/register_archive.go
+++ b/pkg/api/server/register_archive.go
@@ -4,11 +4,10 @@ import (
"net/http"
"github.com/containers/podman/v2/pkg/api/handlers/compat"
- "github.com/containers/podman/v2/pkg/api/handlers/libpod"
"github.com/gorilla/mux"
)
-func (s *APIServer) registerAchiveHandlers(r *mux.Router) error {
+func (s *APIServer) registerArchiveHandlers(r *mux.Router) error {
// swagger:operation PUT /containers/{name}/archive compat putArchive
// ---
// summary: Put files into a container
@@ -92,7 +91,7 @@ func (s *APIServer) registerAchiveHandlers(r *mux.Router) error {
Libpod
*/
- // swagger:operation POST /libpod/containers/{name}/copy libpod libpodPutArchive
+ // swagger:operation POST /libpod/containers/{name}/archive libpod libpodPutArchive
// ---
// summary: Copy files into a container
// description: Copy a tar archive of files into a container
@@ -133,7 +132,7 @@ func (s *APIServer) registerAchiveHandlers(r *mux.Router) error {
// 500:
// $ref: "#/responses/InternalError"
- // swagger:operation GET /libpod/containers/{name}/copy libpod libpodGetArchive
+ // swagger:operation GET /libpod/containers/{name}/archive libpod libpodGetArchive
// ---
// summary: Copy files from a container
// description: Copy a tar archive of files from a container
@@ -164,8 +163,7 @@ func (s *APIServer) registerAchiveHandlers(r *mux.Router) error {
// $ref: "#/responses/NoSuchContainer"
// 500:
// $ref: "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name}/copy"), s.APIHandler(libpod.Archive)).Methods(http.MethodGet, http.MethodPost)
- r.HandleFunc(VersionedPath("/libpod/containers/{name}/archive"), s.APIHandler(libpod.Archive)).Methods(http.MethodGet, http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/archive"), s.APIHandler(compat.Archive)).Methods(http.MethodGet, http.MethodPut, http.MethodHead)
return nil
}
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index 870c6a90c..b80dea545 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -690,6 +690,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// - `label`=(`key` or `"key=value"`) of an container label
// - `name=<name>` a container's name
// - `network`=(`<network id>` or `<network name>`)
+ // - `pod`=(`<pod id>` or `<pod name>`)
// - `publish`=(`<port>[/<proto>]` or `<startport-endport>/[<proto>]`)
// - `since`=(`<container id>` or `<container name>`)
// - `status`=(`created`, `restarting`, `running`, `removing`, `paused`, `exited` or `dead`)
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index c2423218a..7e6de8783 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -666,7 +666,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// - in: query
// name: destination
// type: string
- // description: Allows for pushing the image to a different destintation than the image refers to.
+ // description: Allows for pushing the image to a different destination than the image refers to.
// - in: query
// name: tlsVerify
// description: Require TLS verification.
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 09b6079e4..046f6561c 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -108,7 +108,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
for _, fn := range []func(*mux.Router) error{
server.registerAuthHandlers,
- server.registerAchiveHandlers,
+ server.registerArchiveHandlers,
server.registerContainersHandlers,
server.registerDistributionHandlers,
server.registerEventsHandlers,
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
index 6d349bb7d..45253e01a 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -4,6 +4,7 @@ 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/entities/reports"
)
// No such image
@@ -170,7 +171,7 @@ type ok struct {
// swagger:response VolumePruneResponse
type swagVolumePruneResponse struct {
// in:body
- Body []entities.VolumePruneReport
+ Body []reports.PruneReport
}
// Volume create response
diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go
index 44709f291..77851f534 100644
--- a/pkg/autoupdate/autoupdate.go
+++ b/pkg/autoupdate/autoupdate.go
@@ -44,7 +44,7 @@ var supportedPolicies = map[string]Policy{
"image": PolicyNewImage,
}
-// LookupPolicy looksup the corresponding Policy for the specified
+// LookupPolicy looks up the corresponding Policy for the specified
// string. If none is found, an errors is returned including the list of
// supported policies.
//
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index f2cb3147c..7b26037eb 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -182,30 +182,65 @@ func pingNewConnection(ctx context.Context) error {
func sshClient(_url *url.URL, secure bool, passPhrase string, identity string) (Connection, error) {
// if you modify the authmethods or their conditionals, you will also need to make similar
// changes in the client (currently cmd/podman/system/connection/add getUDS).
- authMethods := []ssh.AuthMethod{}
+
+ var signers []ssh.Signer // order Signers are appended to this list determines which key is presented to server
+
if len(identity) > 0 {
- auth, err := terminal.PublicKey(identity, []byte(passPhrase))
+ s, err := terminal.PublicKey(identity, []byte(passPhrase))
if err != nil {
return Connection{}, errors.Wrapf(err, "failed to parse identity %q", identity)
}
- logrus.Debugf("public key signer enabled for identity %q", identity)
- authMethods = append(authMethods, auth)
+
+ signers = append(signers, s)
+ logrus.Debugf("SSH Ident Key %q %s %s", identity, ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
}
if sock, found := os.LookupEnv("SSH_AUTH_SOCK"); found {
- logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer enabled", sock)
+ logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer(s) enabled", sock)
c, err := net.Dial("unix", sock)
if err != nil {
return Connection{}, err
}
- a := agent.NewClient(c)
- authMethods = append(authMethods, ssh.PublicKeysCallback(a.Signers))
+
+ agentSigners, err := agent.NewClient(c).Signers()
+ if err != nil {
+ return Connection{}, err
+ }
+ signers = append(signers, agentSigners...)
+
+ if logrus.IsLevelEnabled(logrus.DebugLevel) {
+ for _, s := range agentSigners {
+ logrus.Debugf("SSH Agent Key %s %s", ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
+ }
+ }
+ }
+
+ var authMethods []ssh.AuthMethod
+ if len(signers) > 0 {
+ var dedup = make(map[string]ssh.Signer)
+ // Dedup signers based on fingerprint, ssh-agent keys override CONTAINER_SSHKEY
+ for _, s := range signers {
+ fp := ssh.FingerprintSHA256(s.PublicKey())
+ if _, found := dedup[fp]; found {
+ logrus.Debugf("Dedup SSH Key %s %s", ssh.FingerprintSHA256(s.PublicKey()), s.PublicKey().Type())
+ }
+ dedup[fp] = s
+ }
+
+ var uniq []ssh.Signer
+ for _, s := range dedup {
+ uniq = append(uniq, s)
+ }
+ authMethods = append(authMethods, ssh.PublicKeysCallback(func() ([]ssh.Signer, error) {
+ return uniq, nil
+ }))
}
if pw, found := _url.User.Password(); found {
authMethods = append(authMethods, ssh.Password(pw))
}
+
if len(authMethods) == 0 {
callback := func() (string, error) {
pass, err := terminal.ReadPassword("Login password:")
diff --git a/pkg/bindings/containers/archive.go b/pkg/bindings/containers/archive.go
new file mode 100644
index 000000000..d1bbc0b95
--- /dev/null
+++ b/pkg/bindings/containers/archive.go
@@ -0,0 +1,92 @@
+package containers
+
+import (
+ "context"
+ "io"
+ "net/http"
+ "net/url"
+
+ "github.com/containers/podman/v2/pkg/bindings"
+ "github.com/containers/podman/v2/pkg/copy"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/pkg/errors"
+)
+
+// Stat checks if the specified path is on the container. Note that the stat
+// report may be set even in case of an error. This happens when the path
+// resolves to symlink pointing to a non-existent path.
+func Stat(ctx context.Context, nameOrID string, path string) (*entities.ContainerStatReport, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("path", path)
+
+ response, err := conn.DoRequest(nil, http.MethodHead, "/containers/%s/archive", params, nil, nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ var finalErr error
+ if response.StatusCode == http.StatusNotFound {
+ finalErr = copy.ENOENT
+ } else if response.StatusCode != http.StatusOK {
+ finalErr = errors.New(response.Status)
+ }
+
+ var statReport *entities.ContainerStatReport
+
+ fileInfo, err := copy.ExtractFileInfoFromHeader(&response.Header)
+ if err != nil && finalErr == nil {
+ return nil, err
+ }
+
+ if fileInfo != nil {
+ statReport = &entities.ContainerStatReport{FileInfo: *fileInfo}
+ }
+
+ return statReport, finalErr
+}
+
+func CopyFromArchive(ctx context.Context, nameOrID string, path string, reader io.Reader) (entities.ContainerCopyFunc, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("path", path)
+
+ return func() error {
+ response, err := conn.DoRequest(reader, http.MethodPut, "/containers/%s/archive", params, nil, nameOrID)
+ if err != nil {
+ return err
+ }
+ if response.StatusCode != http.StatusOK {
+ return errors.New(response.Status)
+ }
+ return response.Process(nil)
+ }, nil
+}
+
+func CopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (entities.ContainerCopyFunc, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("path", path)
+
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/archive", params, nil, nameOrID)
+ if err != nil {
+ return nil, err
+ }
+ if response.StatusCode != http.StatusOK {
+ return nil, response.Process(nil)
+ }
+
+ return func() error {
+ _, err := io.Copy(writer, response.Body)
+ return err
+ }, nil
+}
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index 91b155fc4..69ae7a32f 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -26,7 +26,10 @@ import (
)
// Attach attaches to a running container
-func Attach(ctx context.Context, nameOrID string, detachKeys *string, logs, stream *bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool) error {
+func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool, options *AttachOptions) error {
+ if options == nil {
+ options = new(AttachOptions)
+ }
isSet := struct {
stdin bool
stdout bool
@@ -55,27 +58,24 @@ func Attach(ctx context.Context, nameOrID string, detachKeys *string, logs, stre
}
// Do we need to wire in stdin?
- ctnr, err := Inspect(ctx, nameOrID, bindings.PFalse)
+ ctnr, err := Inspect(ctx, nameOrID, new(InspectOptions).WithSize(false))
if err != nil {
return err
}
- params := url.Values{}
+ params, err := options.ToParams()
+ if err != nil {
+ return err
+ }
detachKeysInBytes := []byte{}
- if detachKeys != nil {
- params.Add("detachKeys", *detachKeys)
+ if options.Changed("DetachKeys") {
+ params.Add("detachKeys", options.GetDetachKeys())
- detachKeysInBytes, err = term.ToBytes(*detachKeys)
+ detachKeysInBytes, err = term.ToBytes(options.GetDetachKeys())
if err != nil {
return errors.Wrapf(err, "invalid detach keys")
}
}
- if logs != nil {
- params.Add("logs", fmt.Sprintf("%t", *logs))
- }
- if stream != nil {
- params.Add("stream", fmt.Sprintf("%t", *stream))
- }
if isSet.stdin {
params.Add("stdin", "true")
}
@@ -278,13 +278,19 @@ func DemuxFrame(r io.Reader, buffer []byte, length int) (frame []byte, err error
}
// ResizeContainerTTY sets container's TTY height and width in characters
-func ResizeContainerTTY(ctx context.Context, nameOrID string, height *int, width *int) error {
- return resizeTTY(ctx, bindings.JoinURL("containers", nameOrID, "resize"), height, width)
+func ResizeContainerTTY(ctx context.Context, nameOrID string, options *ResizeTTYOptions) error {
+ if options == nil {
+ options = new(ResizeTTYOptions)
+ }
+ return resizeTTY(ctx, bindings.JoinURL("containers", nameOrID, "resize"), options.Height, options.Width)
}
// ResizeExecTTY sets session's TTY height and width in characters
-func ResizeExecTTY(ctx context.Context, nameOrID string, height *int, width *int) error {
- return resizeTTY(ctx, bindings.JoinURL("exec", nameOrID, "resize"), height, width)
+func ResizeExecTTY(ctx context.Context, nameOrID string, options *ResizeExecTTYOptions) error {
+ if options == nil {
+ options = new(ResizeExecTTYOptions)
+ }
+ return resizeTTY(ctx, bindings.JoinURL("exec", nameOrID, "resize"), options.Height, options.Width)
}
// resizeTTY set size of TTY of container
@@ -337,9 +343,9 @@ func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, i
var resizeErr error
if isExec {
- resizeErr = ResizeExecTTY(ctx, id, &h, &w)
+ resizeErr = ResizeExecTTY(ctx, id, new(ResizeExecTTYOptions).WithHeight(h).WithWidth(w))
} else {
- resizeErr = ResizeContainerTTY(ctx, id, &h, &w)
+ resizeErr = ResizeContainerTTY(ctx, id, new(ResizeTTYOptions).WithHeight(h).WithWidth(w))
}
if resizeErr != nil {
logrus.Warnf("failed to resize TTY: %v", err)
@@ -361,7 +367,10 @@ func setRawTerminal(file *os.File) (*terminal.State, error) {
}
// ExecStartAndAttach starts and attaches to a given exec session.
-func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.AttachStreams) error {
+func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStartAndAttachOptions) error {
+ if options == nil {
+ options = new(ExecStartAndAttachOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -450,10 +459,10 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.A
go attachHandleResize(ctx, winCtx, winChange, true, sessionID, terminalFile)
}
- if streams.AttachInput {
+ if options.GetAttachInput() {
go func() {
logrus.Debugf("Copying STDIN to socket")
- _, err := utils.CopyDetachable(socket, streams.InputStream, []byte{})
+ _, err := utils.CopyDetachable(socket, options.InputStream, []byte{})
if err != nil {
logrus.Error("failed to write input to service: " + err.Error())
}
@@ -463,11 +472,11 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.A
buffer := make([]byte, 1024)
if isTerm {
logrus.Debugf("Handling terminal attach to exec")
- if !streams.AttachOutput {
+ if !options.GetAttachOutput() {
return fmt.Errorf("exec session %s has a terminal and must have STDOUT enabled", sessionID)
}
// If not multiplex'ed, read from server and write to stdout
- _, err := utils.CopyDetachable(streams.OutputStream, socket, []byte{})
+ _, err := utils.CopyDetachable(options.GetOutputStream(), socket, []byte{})
if err != nil {
return err
}
@@ -489,22 +498,22 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.A
switch {
case fd == 0:
- if streams.AttachInput {
+ if options.GetAttachInput() {
// Write STDIN to STDOUT (echoing characters
// typed by another attach session)
- if _, err := streams.OutputStream.Write(frame[0:l]); err != nil {
+ if _, err := options.GetOutputStream().Write(frame[0:l]); err != nil {
return err
}
}
case fd == 1:
- if streams.AttachOutput {
- if _, err := streams.OutputStream.Write(frame[0:l]); err != nil {
+ if options.GetAttachOutput() {
+ if _, err := options.GetOutputStream().Write(frame[0:l]); err != nil {
return err
}
}
case fd == 2:
- if streams.AttachError {
- if _, err := streams.ErrorStream.Write(frame[0:l]); err != nil {
+ if options.GetAttachError() {
+ if _, err := options.GetErrorStream().Write(frame[0:l]); err != nil {
return err
}
}
diff --git a/pkg/bindings/containers/checkpoint.go b/pkg/bindings/containers/checkpoint.go
index f466f8a34..c250558a6 100644
--- a/pkg/bindings/containers/checkpoint.go
+++ b/pkg/bindings/containers/checkpoint.go
@@ -3,8 +3,6 @@ package containers
import (
"context"
"net/http"
- "net/url"
- "strconv"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -12,27 +10,18 @@ import (
// Checkpoint checkpoints the given container (identified by nameOrID). All additional
// options are options and allow for more fine grained control of the checkpoint process.
-func Checkpoint(ctx context.Context, nameOrID string, keep, leaveRunning, tcpEstablished, ignoreRootFS *bool, export *string) (*entities.CheckpointReport, error) {
+func Checkpoint(ctx context.Context, nameOrID string, options *CheckpointOptions) (*entities.CheckpointReport, error) {
var report entities.CheckpointReport
+ if options == nil {
+ options = new(CheckpointOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if keep != nil {
- params.Set("keep", strconv.FormatBool(*keep))
- }
- if leaveRunning != nil {
- params.Set("leaveRunning", strconv.FormatBool(*leaveRunning))
- }
- if tcpEstablished != nil {
- params.Set("TCPestablished", strconv.FormatBool(*tcpEstablished))
- }
- if ignoreRootFS != nil {
- params.Set("ignoreRootFS", strconv.FormatBool(*ignoreRootFS))
- }
- if export != nil {
- params.Set("export", *export)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrID)
if err != nil {
@@ -43,33 +32,23 @@ func Checkpoint(ctx context.Context, nameOrID string, keep, leaveRunning, tcpEst
// Restore restores a checkpointed container to running. The container is identified by the nameOrID option. All
// additional options are optional and allow finer control of the restore process.
-func Restore(ctx context.Context, nameOrID string, keep, tcpEstablished, ignoreRootFS, ignoreStaticIP, ignoreStaticMAC *bool, name, importArchive *string) (*entities.RestoreReport, error) {
+func Restore(ctx context.Context, nameOrID string, options *RestoreOptions) (*entities.RestoreReport, error) {
var report entities.RestoreReport
+ if options == nil {
+ options = new(RestoreOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if keep != nil {
- params.Set("keep", strconv.FormatBool(*keep))
- }
- if tcpEstablished != nil {
- params.Set("TCPestablished", strconv.FormatBool(*tcpEstablished))
- }
- if ignoreRootFS != nil {
- params.Set("ignoreRootFS", strconv.FormatBool(*ignoreRootFS))
- }
- if ignoreStaticIP != nil {
- params.Set("ignoreStaticIP", strconv.FormatBool(*ignoreStaticIP))
- }
- if ignoreStaticMAC != nil {
- params.Set("ignoreStaticMAC", strconv.FormatBool(*ignoreStaticMAC))
- }
- if name != nil {
- params.Set("name", *name)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
- if importArchive != nil {
- params.Set("import", *importArchive)
+ // The import key is a reserved golang term
+ params.Del("ImportArchive")
+ if i := options.GetImportAchive(); options.Changed("ImportArchive") {
+ params.Set("import", i)
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restore", params, nil, nameOrID)
if err != nil {
diff --git a/pkg/bindings/containers/commit.go b/pkg/bindings/containers/commit.go
index 9ab4456a3..6205c75bd 100644
--- a/pkg/bindings/containers/commit.go
+++ b/pkg/bindings/containers/commit.go
@@ -3,8 +3,6 @@ package containers
import (
"context"
"net/http"
- "net/url"
- "strconv"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
@@ -12,35 +10,20 @@ import (
// Commit creates a container image from a container. The container is defined by nameOrID. Use
// the CommitOptions for finer grain control on characteristics of the resulting image.
-func Commit(ctx context.Context, nameOrID string, options CommitOptions) (handlers.IDResponse, error) {
+func Commit(ctx context.Context, nameOrID string, options *CommitOptions) (handlers.IDResponse, error) {
+ if options == nil {
+ options = new(CommitOptions)
+ }
id := handlers.IDResponse{}
conn, err := bindings.GetClient(ctx)
if err != nil {
return id, err
}
- params := url.Values{}
- params.Set("container", nameOrID)
- if options.Author != nil {
- params.Set("author", *options.Author)
- }
- for _, change := range options.Changes {
- params.Set("changes", change)
- }
- if options.Comment != nil {
- params.Set("comment", *options.Comment)
- }
- if options.Format != nil {
- params.Set("format", *options.Format)
- }
- if options.Pause != nil {
- params.Set("pause", strconv.FormatBool(*options.Pause))
- }
- if options.Repo != nil {
- params.Set("repo", *options.Repo)
- }
- if options.Tag != nil {
- params.Set("tag", *options.Tag)
+ params, err := options.ToParams()
+ if err != nil {
+ return handlers.IDResponse{}, err
}
+ params.Set("container", nameOrID)
response, err := conn.DoRequest(nil, http.MethodPost, "/commit", params, nil)
if err != nil {
return id, err
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 4331ae6c2..1081a0e61 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -25,34 +26,18 @@ var (
// the most recent number of containers. The pod and size booleans indicate that pod information and rootfs
// size information should also be included. Finally, the sync bool synchronizes the OCI runtime and
// container state.
-func List(ctx context.Context, filters map[string][]string, all *bool, last *int, namespace, size, sync *bool) ([]entities.ListContainer, error) { // nolint:typecheck
+func List(ctx context.Context, options *ListOptions) ([]entities.ListContainer, error) { // nolint:typecheck
+ if options == nil {
+ options = new(ListOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
var containers []entities.ListContainer
- params := url.Values{}
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
- }
- if last != nil {
- params.Set("limit", strconv.Itoa(*last))
- }
- if size != nil {
- params.Set("size", strconv.FormatBool(*size))
- }
- if sync != nil {
- params.Set("sync", strconv.FormatBool(*sync))
- }
- if namespace != nil {
- params.Set("namespace", strconv.FormatBool(*namespace))
- }
- if filters != nil {
- filterString, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", filterString)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/json", params, nil)
if err != nil {
@@ -65,19 +50,18 @@ func List(ctx context.Context, filters map[string][]string, all *bool, last *int
// used for more granular selection of containers. The main error returned indicates if there were runtime
// errors like finding containers. Errors specific to the removal of a container are in the PruneContainerResponse
// structure.
-func Prune(ctx context.Context, filters map[string][]string) (*entities.ContainerPruneReport, error) {
- var reports *entities.ContainerPruneReport
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
+ if options == nil {
+ options = new(PruneOptions)
+ }
+ var reports []*reports.PruneReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if filters != nil {
- filterString, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", filterString)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/prune", params, nil)
if err != nil {
@@ -89,17 +73,20 @@ func Prune(ctx context.Context, filters map[string][]string) (*entities.Containe
// Remove removes a container from local storage. The force bool designates
// that the container should be removed forcibly (example, even it is running). The volumes
// bool dictates that a container's volumes should also be removed.
-func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error {
+ if options == nil {
+ options = new(RemoveOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
params := url.Values{}
- if force != nil {
- params.Set("force", strconv.FormatBool(*force))
+ if v := options.GetVolumes(); options.Changed("Volumes") {
+ params.Set("v", strconv.FormatBool(v))
}
- if volumes != nil {
- params.Set("v", strconv.FormatBool(*volumes))
+ if force := options.GetForce(); options.Changed("Force") {
+ params.Set("force", strconv.FormatBool(force))
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID)
if err != nil {
@@ -112,14 +99,17 @@ func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error {
// or a partial/full ID. The size bool determines whether the size of the container's root filesystem
// should be calculated. Calculating the size of a container requires extra work from the filesystem and
// is therefore slower.
-func Inspect(ctx context.Context, nameOrID string, size *bool) (*define.InspectContainerData, error) {
+func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*define.InspectContainerData, error) {
+ if options == nil {
+ options = new(InspectOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if size != nil {
- params.Set("size", strconv.FormatBool(*size))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/json", params, nil, nameOrID)
if err != nil {
@@ -132,12 +122,18 @@ func Inspect(ctx context.Context, nameOrID string, size *bool) (*define.InspectC
// Kill sends a given signal to a given container. The signal should be the string
// representation of a signal like 'SIGKILL'. The nameOrID can be a container name
// or a partial/full ID
-func Kill(ctx context.Context, nameOrID string, sig string) error {
+func Kill(ctx context.Context, nameOrID string, sig string, options *KillOptions) error {
+ if options == nil {
+ options = new(KillOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
+ params, err := options.ToParams()
+ if err != nil {
+ return err
+ }
params.Set("signal", sig)
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nil, nameOrID)
if err != nil {
@@ -149,7 +145,11 @@ func Kill(ctx context.Context, nameOrID string, sig string) error {
// Pause pauses a given container. The nameOrID can be a container name
// or a partial/full ID.
-func Pause(ctx context.Context, nameOrID string) error {
+func Pause(ctx context.Context, nameOrID string, options *PauseOptions) error {
+ if options == nil {
+ options = new(PauseOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -164,14 +164,17 @@ func Pause(ctx context.Context, nameOrID string) error {
// Restart restarts a running container. The nameOrID can be a container name
// or a partial/full ID. The optional timeout specifies the number of seconds to wait
// for the running container to stop before killing it.
-func Restart(ctx context.Context, nameOrID string, timeout *int) error {
+func Restart(ctx context.Context, nameOrID string, options *RestartOptions) error {
+ if options == nil {
+ options = new(RestartOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
params := url.Values{}
- if timeout != nil {
- params.Set("t", strconv.Itoa(*timeout))
+ if options.Changed("Timeout") {
+ params.Set("t", strconv.Itoa(options.GetTimeout()))
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nil, nameOrID)
if err != nil {
@@ -183,15 +186,18 @@ func Restart(ctx context.Context, nameOrID string, timeout *int) error {
// Start starts a non-running container.The nameOrID can be a container name
// or a partial/full ID. The optional parameter for detach keys are to override the default
// detach key sequence.
-func Start(ctx context.Context, nameOrID string, detachKeys *string) error {
+func Start(ctx context.Context, nameOrID string, options *StartOptions) error {
+ if options == nil {
+ options = new(StartOptions)
+ }
logrus.Infof("Going to start container %q", nameOrID)
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
- if detachKeys != nil {
- params.Set("detachKeys", *detachKeys)
+ params, err := options.ToParams()
+ if err != nil {
+ return err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/start", params, nil, nameOrID)
if err != nil {
@@ -200,14 +206,18 @@ func Start(ctx context.Context, nameOrID string, detachKeys *string) error {
return response.Process(nil)
}
-func Stats(ctx context.Context, containers []string, stream *bool) (chan entities.ContainerStatsReport, error) {
+func Stats(ctx context.Context, containers []string, options *StatsOptions) (chan entities.ContainerStatsReport, error) {
+ if options == nil {
+ options = new(StatsOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if stream != nil {
- params.Set("stream", strconv.FormatBool(*stream))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
for _, c := range containers {
params.Add("containers", c)
@@ -225,8 +235,8 @@ func Stats(ctx context.Context, containers []string, stream *bool) (chan entitie
dec := json.NewDecoder(response.Body)
doStream := true
- if stream != nil {
- doStream = *stream
+ if options.Changed("Stream") {
+ doStream = options.GetStream()
}
streamLabel: // label to flatten the scope
@@ -253,16 +263,18 @@ func Stats(ctx context.Context, containers []string, stream *bool) (chan entitie
// Top gathers statistics about the running processes in a container. The nameOrID can be a container name
// or a partial/full ID. The descriptors allow for specifying which data to collect from the process.
-func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string, error) {
+func Top(ctx context.Context, nameOrID string, options *TopOptions) ([]string, error) {
+ if options == nil {
+ options = new(TopOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
-
- if len(descriptors) > 0 {
- // flatten the slice into one string
- params.Set("ps_args", strings.Join(descriptors, ","))
+ if options.Changed("Descriptors") {
+ ps_args := strings.Join(options.GetDescriptors(), ",")
+ params.Add("ps_args", ps_args)
}
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/top", params, nil, nameOrID)
if err != nil {
@@ -287,7 +299,11 @@ func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string,
// Unpause resumes the given paused container. The nameOrID can be a container name
// or a partial/full ID.
-func Unpause(ctx context.Context, nameOrID string) error {
+func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) error {
+ if options == nil {
+ options = new(UnpauseOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -302,15 +318,18 @@ func Unpause(ctx context.Context, nameOrID string) error {
// Wait blocks until the given container reaches a condition. If not provided, the condition will
// default to stopped. If the condition is stopped, an exit code for the container will be provided. The
// nameOrID can be a container name or a partial/full ID.
-func Wait(ctx context.Context, nameOrID string, condition *define.ContainerStatus) (int32, error) { // nolint
+func Wait(ctx context.Context, nameOrID string, options *WaitOptions) (int32, error) { // nolint
+ if options == nil {
+ options = new(WaitOptions)
+ }
var exitCode int32
conn, err := bindings.GetClient(ctx)
if err != nil {
return exitCode, err
}
params := url.Values{}
- if condition != nil {
- params.Set("condition", condition.String())
+ if options.Changed("Condition") {
+ params.Set("condition", options.GetCondition().String())
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nil, nameOrID)
if err != nil {
@@ -338,14 +357,17 @@ func Exists(ctx context.Context, nameOrID string, external bool) (bool, error) {
// Stop stops a running container. The timeout is optional. The nameOrID can be a container name
// or a partial/full ID
-func Stop(ctx context.Context, nameOrID string, timeout *uint) error {
- params := url.Values{}
- conn, err := bindings.GetClient(ctx)
+func Stop(ctx context.Context, nameOrID string, options *StopOptions) error {
+ if options == nil {
+ options = new(StopOptions)
+ }
+ params, err := options.ToParams()
if err != nil {
return err
}
- if timeout != nil {
- params.Set("t", strconv.Itoa(int(*timeout)))
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/stop", params, nil, nameOrID)
if err != nil {
@@ -356,7 +378,11 @@ func Stop(ctx context.Context, nameOrID string, timeout *uint) error {
// Export creates a tarball of the given name or ID of a container. It
// requires an io.Writer be provided to write the tarball.
-func Export(ctx context.Context, nameOrID string, w io.Writer) error {
+func Export(ctx context.Context, nameOrID string, w io.Writer, options *ExportOptions) error {
+ if options == nil {
+ options = new(ExportOptions)
+ }
+ _ = options
params := url.Values{}
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -376,7 +402,11 @@ func Export(ctx context.Context, nameOrID string, w io.Writer) error {
// ContainerInit takes a created container and executes all of the
// preparations to run the container except it will not start
// or attach to the container
-func ContainerInit(ctx context.Context, nameOrID string) error {
+func ContainerInit(ctx context.Context, nameOrID string, options *InitOptions) error {
+ if options == nil {
+ options = new(InitOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -391,7 +421,11 @@ func ContainerInit(ctx context.Context, nameOrID string) error {
return response.Process(nil)
}
-func ShouldRestart(ctx context.Context, nameOrID string) (bool, error) {
+func ShouldRestart(ctx context.Context, nameOrID string, options *ShouldRestartOptions) (bool, error) {
+ if options == nil {
+ options = new(ShouldRestartOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return false, err
diff --git a/pkg/bindings/containers/create.go b/pkg/bindings/containers/create.go
index 5c29ec577..177cf2e9c 100644
--- a/pkg/bindings/containers/create.go
+++ b/pkg/bindings/containers/create.go
@@ -11,8 +11,12 @@ import (
jsoniter "github.com/json-iterator/go"
)
-func CreateWithSpec(ctx context.Context, s *specgen.SpecGenerator) (entities.ContainerCreateResponse, error) {
+func CreateWithSpec(ctx context.Context, s *specgen.SpecGenerator, options *CreateOptions) (entities.ContainerCreateResponse, error) {
var ccr entities.ContainerCreateResponse
+ if options == nil {
+ options = new(CreateOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return ccr, err
diff --git a/pkg/bindings/containers/diff.go b/pkg/bindings/containers/diff.go
index 1478bd940..015172360 100644
--- a/pkg/bindings/containers/diff.go
+++ b/pkg/bindings/containers/diff.go
@@ -9,7 +9,11 @@ import (
)
// Diff provides the changes between two container layers
-func Diff(ctx context.Context, nameOrID string) ([]archive.Change, error) {
+func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive.Change, error) {
+ if options == nil {
+ options = new(DiffOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/containers/exec.go b/pkg/bindings/containers/exec.go
index e080077c8..98ca975a0 100644
--- a/pkg/bindings/containers/exec.go
+++ b/pkg/bindings/containers/exec.go
@@ -50,7 +50,11 @@ func ExecCreate(ctx context.Context, nameOrID string, config *handlers.ExecCreat
// ExecInspect inspects an existing exec session, returning detailed information
// about it.
-func ExecInspect(ctx context.Context, sessionID string) (*define.InspectExecSession, error) {
+func ExecInspect(ctx context.Context, sessionID string, options *ExecInspectOptions) (*define.InspectExecSession, error) {
+ if options == nil {
+ options = new(ExecInspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -72,7 +76,11 @@ func ExecInspect(ctx context.Context, sessionID string) (*define.InspectExecSess
}
// ExecStart starts (but does not attach to) a given exec session.
-func ExecStart(ctx context.Context, sessionID string) error {
+func ExecStart(ctx context.Context, sessionID string, options *ExecStartOptions) error {
+ if options == nil {
+ options = new(ExecStartOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
diff --git a/pkg/bindings/containers/healthcheck.go b/pkg/bindings/containers/healthcheck.go
index 9de6ffbe0..44b27629b 100644
--- a/pkg/bindings/containers/healthcheck.go
+++ b/pkg/bindings/containers/healthcheck.go
@@ -10,7 +10,11 @@ import (
// RunHealthCheck executes the container's healthcheck and returns the health status of the
// container.
-func RunHealthCheck(ctx context.Context, nameOrID string) (*define.HealthCheckResults, error) {
+func RunHealthCheck(ctx context.Context, nameOrID string, options *HealthCheckOptions) (*define.HealthCheckResults, error) {
+ if options == nil {
+ options = new(HealthCheckOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go
index a73517bac..04307d880 100644
--- a/pkg/bindings/containers/logs.go
+++ b/pkg/bindings/containers/logs.go
@@ -5,7 +5,6 @@ import (
"fmt"
"io"
"net/http"
- "net/url"
"strconv"
"github.com/containers/podman/v2/pkg/bindings"
@@ -14,35 +13,20 @@ import (
// Logs obtains a container's logs given the options provided. The logs are then sent to the
// stdout|stderr channels as strings.
-func Logs(ctx context.Context, nameOrID string, opts LogOptions, stdoutChan, stderrChan chan string) error {
+func Logs(ctx context.Context, nameOrID string, options *LogOptions, stdoutChan, stderrChan chan string) error {
+ if options == nil {
+ options = new(LogOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
- if opts.Follow != nil {
- params.Set("follow", strconv.FormatBool(*opts.Follow))
- }
- if opts.Since != nil {
- params.Set("since", *opts.Since)
- }
- if opts.Stderr != nil {
- params.Set("stderr", strconv.FormatBool(*opts.Stderr))
- }
- if opts.Stdout != nil {
- params.Set("stdout", strconv.FormatBool(*opts.Stdout))
- }
- if opts.Tail != nil {
- params.Set("tail", *opts.Tail)
- }
- if opts.Timestamps != nil {
- params.Set("timestamps", strconv.FormatBool(*opts.Timestamps))
- }
- if opts.Until != nil {
- params.Set("until", *opts.Until)
+ params, err := options.ToParams()
+ if err != nil {
+ return err
}
// The API requires either stdout|stderr be used. If neither are specified, we specify stdout
- if opts.Stdout == nil && opts.Stderr == nil {
+ if options.Stdout == nil && options.Stderr == nil {
params.Set("stdout", strconv.FormatBool(true))
}
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/logs", params, nil, nameOrID)
diff --git a/pkg/bindings/containers/mount.go b/pkg/bindings/containers/mount.go
index 4c2e0c188..4fd9f89bc 100644
--- a/pkg/bindings/containers/mount.go
+++ b/pkg/bindings/containers/mount.go
@@ -9,7 +9,11 @@ import (
// Mount mounts an existing container to the filesystem. It returns the path
// of the mounted container in string format.
-func Mount(ctx context.Context, nameOrID string) (string, error) {
+func Mount(ctx context.Context, nameOrID string, options *MountOptions) (string, error) {
+ if options == nil {
+ options = new(MountOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
@@ -26,7 +30,11 @@ func Mount(ctx context.Context, nameOrID string) (string, error) {
// Unmount unmounts a container from the filesystem. The container must not be running
// or the unmount will fail.
-func Unmount(ctx context.Context, nameOrID string) error {
+func Unmount(ctx context.Context, nameOrID string, options *UnmountOptions) error {
+ if options == nil {
+ options = new(UnmountOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -39,7 +47,11 @@ func Unmount(ctx context.Context, nameOrID string) error {
}
// GetMountedContainerPaths returns a map of mounted containers and their mount locations.
-func GetMountedContainerPaths(ctx context.Context) (map[string]string, error) {
+func GetMountedContainerPaths(ctx context.Context, options *MountedContainerPathsOptions) (map[string]string, error) {
+ if options == nil {
+ options = new(MountedContainerPathsOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index f288c2944..24402e982 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -1,5 +1,13 @@
package containers
+import (
+ "bufio"
+ "io"
+
+ "github.com/containers/podman/v2/libpod/define"
+)
+
+//go:generate go run ../generator/generator.go LogOptions
// LogOptions describe finer control of log content or
// how the content is formatted.
type LogOptions struct {
@@ -12,6 +20,7 @@ type LogOptions struct {
Until *string
}
+//go:generate go run ../generator/generator.go CommitOptions
// CommitOptions describe details about the resulting committed
// image as defined by repo and tag. None of these options
// are required.
@@ -24,3 +33,200 @@ type CommitOptions struct {
Repo *string
Tag *string
}
+
+//go:generate go run ../generator/generator.go AttachOptions
+// AttachOptions are optional options for attaching to containers
+type AttachOptions struct {
+ DetachKeys *string
+ Logs *bool
+ Stream *bool
+}
+
+//go:generate go run ../generator/generator.go CheckpointOptions
+// CheckpointOptions are optional options for checkpointing containers
+type CheckpointOptions struct {
+ Export *string
+ IgnoreRootfs *bool
+ Keep *bool
+ LeaveRunning *bool
+ TCPEstablished *bool
+}
+
+//go:generate go run ../generator/generator.go RestoreOptions
+// RestoreOptions are optional options for restoring containers
+type RestoreOptions struct {
+ IgnoreRootfs *bool
+ IgnoreStaticIP *bool
+ IgnoreStaticMAC *bool
+ ImportAchive *string
+ Keep *bool
+ Name *string
+ TCPEstablished *bool
+}
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating containers
+type CreateOptions struct{}
+
+//go:generate go run ../generator/generator.go DiffOptions
+// DiffOptions are optional options for creating containers
+type DiffOptions struct{}
+
+//go:generate go run ../generator/generator.go ExecInspectOptions
+// ExecInspectOptions are optional options for inspecting
+// exec sessions
+type ExecInspectOptions struct{}
+
+//go:generate go run ../generator/generator.go ExecStartOptions
+// ExecStartOptions are optional options for starting
+// exec sessions
+type ExecStartOptions struct{}
+
+//go:generate go run ../generator/generator.go HealthCheckOptions
+// HealthCheckOptions are optional options for checking
+// the health of a container
+type HealthCheckOptions struct{}
+
+//go:generate go run ../generator/generator.go MountOptions
+// MountOptions are optional options for mounting
+// containers
+type MountOptions struct{}
+
+//go:generate go run ../generator/generator.go UnmountOptions
+// UnmountOptions are optional options for unmounting
+// containers
+type UnmountOptions struct{}
+
+//go:generate go run ../generator/generator.go MountedContainerPathsOptions
+// MountedContainerPathsOptions are optional options for getting
+// container mount paths
+type MountedContainerPathsOptions struct{}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing containers
+type ListOptions struct {
+ All *bool
+ Filters map[string][]string
+ Last *int
+ Namespace *bool
+ Size *bool
+ Sync *bool
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning containers
+type PruneOptions struct {
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for removing containers
+type RemoveOptions struct {
+ Force *bool
+ Volumes *bool
+}
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting containers
+type InspectOptions struct {
+ Size *bool
+}
+
+//go:generate go run ../generator/generator.go KillOptions
+// KillOptions are optional options for killing containers
+type KillOptions struct {
+}
+
+//go:generate go run ../generator/generator.go PauseOptions
+// PauseOptions are optional options for pausing containers
+type PauseOptions struct{}
+
+//go:generate go run ../generator/generator.go RestartOptions
+// RestartOptions are optional options for restarting containers
+type RestartOptions struct {
+ Timeout *int
+}
+
+//go:generate go run ../generator/generator.go StartOptions
+// StartOptions are optional options for starting containers
+type StartOptions struct {
+ DetachKeys *string
+}
+
+//go:generate go run ../generator/generator.go StatsOptions
+// StatsOptions are optional options for getting stats on containers
+type StatsOptions struct {
+ Stream *bool
+}
+
+//go:generate go run ../generator/generator.go TopOptions
+// TopOptions are optional options for getting running
+// processes in containers
+type TopOptions struct {
+ Descriptors *[]string
+}
+
+//go:generate go run ../generator/generator.go UnpauseOptions
+// UnpauseOptions are optional options for unpausing containers
+type UnpauseOptions struct{}
+
+//go:generate go run ../generator/generator.go WaitOptions
+// WaitOptions are optional options for waiting on containers
+type WaitOptions struct {
+ Condition *define.ContainerStatus
+}
+
+//go:generate go run ../generator/generator.go StopOptions
+// StopOptions are optional options for stopping containers
+type StopOptions struct {
+ Timeout *uint
+}
+
+//go:generate go run ../generator/generator.go ExportOptions
+// ExportOptions are optional options for exporting containers
+type ExportOptions struct{}
+
+//go:generate go run ../generator/generator.go InitOptions
+// InitOptions are optional options for initing containers
+type InitOptions struct{}
+
+//go:generate go run ../generator/generator.go ShouldRestartOptions
+// ShouldRestartOptions
+type ShouldRestartOptions struct{}
+
+//go:generate go run ../generator/generator.go ResizeTTYOptions
+// ResizeTTYOptions are optional options for resizing
+// container TTYs
+type ResizeTTYOptions struct {
+ Height *int
+ Width *int
+}
+
+//go:generate go run ../generator/generator.go ResizeExecTTYOptions
+// ResizeExecTTYOptions are optional options for resizing
+// container ExecTTYs
+type ResizeExecTTYOptions struct {
+ Height *int
+ Width *int
+}
+
+//go:generate go run ../generator/generator.go ExecStartAndAttachOptions
+// ExecStartAndAttachOptions are optional options for resizing
+// container ExecTTYs
+type ExecStartAndAttachOptions struct {
+ // OutputStream will be attached to container's STDOUT
+ OutputStream *io.WriteCloser
+ // ErrorStream will be attached to container's STDERR
+ ErrorStream *io.WriteCloser
+ // InputStream will be attached to container's STDIN
+ InputStream *bufio.Reader
+ // AttachOutput is whether to attach to STDOUT
+ // If false, stdout will not be attached
+ AttachOutput *bool
+ // AttachError is whether to attach to STDERR
+ // If false, stdout will not be attached
+ AttachError *bool
+ // AttachInput is whether to attach to STDIN
+ // If false, stdout will not be attached
+ AttachInput *bool
+}
diff --git a/pkg/bindings/containers/types_attach_options.go b/pkg/bindings/containers/types_attach_options.go
new file mode 100644
index 000000000..4ffb8ab17
--- /dev/null
+++ b/pkg/bindings/containers/types_attach_options.go
@@ -0,0 +1,136 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.566804404 -0600 CST m=+0.000258831
+*/
+
+// Changed
+func (o *AttachOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *AttachOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDetachKeys
+func (o *AttachOptions) WithDetachKeys(value string) *AttachOptions {
+ v := &value
+ o.DetachKeys = v
+ return o
+}
+
+// GetDetachKeys
+func (o *AttachOptions) GetDetachKeys() string {
+ var detachKeys string
+ if o.DetachKeys == nil {
+ return detachKeys
+ }
+ return *o.DetachKeys
+}
+
+// WithLogs
+func (o *AttachOptions) WithLogs(value bool) *AttachOptions {
+ v := &value
+ o.Logs = v
+ return o
+}
+
+// GetLogs
+func (o *AttachOptions) GetLogs() bool {
+ var logs bool
+ if o.Logs == nil {
+ return logs
+ }
+ return *o.Logs
+}
+
+// WithStream
+func (o *AttachOptions) WithStream(value bool) *AttachOptions {
+ v := &value
+ o.Stream = v
+ return o
+}
+
+// GetStream
+func (o *AttachOptions) GetStream() bool {
+ var stream bool
+ if o.Stream == nil {
+ return stream
+ }
+ return *o.Stream
+}
diff --git a/pkg/bindings/containers/types_checkpoint_options.go b/pkg/bindings/containers/types_checkpoint_options.go
new file mode 100644
index 000000000..d03dc8231
--- /dev/null
+++ b/pkg/bindings/containers/types_checkpoint_options.go
@@ -0,0 +1,168 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.714853285 -0600 CST m=+0.000319103
+*/
+
+// Changed
+func (o *CheckpointOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CheckpointOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithExport
+func (o *CheckpointOptions) WithExport(value string) *CheckpointOptions {
+ v := &value
+ o.Export = v
+ return o
+}
+
+// GetExport
+func (o *CheckpointOptions) GetExport() string {
+ var export string
+ if o.Export == nil {
+ return export
+ }
+ return *o.Export
+}
+
+// WithIgnoreRootfs
+func (o *CheckpointOptions) WithIgnoreRootfs(value bool) *CheckpointOptions {
+ v := &value
+ o.IgnoreRootfs = v
+ return o
+}
+
+// GetIgnoreRootfs
+func (o *CheckpointOptions) GetIgnoreRootfs() bool {
+ var ignoreRootfs bool
+ if o.IgnoreRootfs == nil {
+ return ignoreRootfs
+ }
+ return *o.IgnoreRootfs
+}
+
+// WithKeep
+func (o *CheckpointOptions) WithKeep(value bool) *CheckpointOptions {
+ v := &value
+ o.Keep = v
+ return o
+}
+
+// GetKeep
+func (o *CheckpointOptions) GetKeep() bool {
+ var keep bool
+ if o.Keep == nil {
+ return keep
+ }
+ return *o.Keep
+}
+
+// WithLeaveRunning
+func (o *CheckpointOptions) WithLeaveRunning(value bool) *CheckpointOptions {
+ v := &value
+ o.LeaveRunning = v
+ return o
+}
+
+// GetLeaveRunning
+func (o *CheckpointOptions) GetLeaveRunning() bool {
+ var leaveRunning bool
+ if o.LeaveRunning == nil {
+ return leaveRunning
+ }
+ return *o.LeaveRunning
+}
+
+// WithTCPEstablished
+func (o *CheckpointOptions) WithTCPEstablished(value bool) *CheckpointOptions {
+ v := &value
+ o.TCPEstablished = v
+ return o
+}
+
+// GetTCPEstablished
+func (o *CheckpointOptions) GetTCPEstablished() bool {
+ var tCPEstablished bool
+ if o.TCPEstablished == nil {
+ return tCPEstablished
+ }
+ return *o.TCPEstablished
+}
diff --git a/pkg/bindings/containers/types_commit_options.go b/pkg/bindings/containers/types_commit_options.go
new file mode 100644
index 000000000..a8b215141
--- /dev/null
+++ b/pkg/bindings/containers/types_commit_options.go
@@ -0,0 +1,200 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.420656951 -0600 CST m=+0.000259662
+*/
+
+// Changed
+func (o *CommitOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CommitOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAuthor
+func (o *CommitOptions) WithAuthor(value string) *CommitOptions {
+ v := &value
+ o.Author = v
+ return o
+}
+
+// GetAuthor
+func (o *CommitOptions) GetAuthor() string {
+ var author string
+ if o.Author == nil {
+ return author
+ }
+ return *o.Author
+}
+
+// WithChanges
+func (o *CommitOptions) WithChanges(value []string) *CommitOptions {
+ v := value
+ o.Changes = v
+ return o
+}
+
+// GetChanges
+func (o *CommitOptions) GetChanges() []string {
+ var changes []string
+ if o.Changes == nil {
+ return changes
+ }
+ return o.Changes
+}
+
+// WithComment
+func (o *CommitOptions) WithComment(value string) *CommitOptions {
+ v := &value
+ o.Comment = v
+ return o
+}
+
+// GetComment
+func (o *CommitOptions) GetComment() string {
+ var comment string
+ if o.Comment == nil {
+ return comment
+ }
+ return *o.Comment
+}
+
+// WithFormat
+func (o *CommitOptions) WithFormat(value string) *CommitOptions {
+ v := &value
+ o.Format = v
+ return o
+}
+
+// GetFormat
+func (o *CommitOptions) GetFormat() string {
+ var format string
+ if o.Format == nil {
+ return format
+ }
+ return *o.Format
+}
+
+// WithPause
+func (o *CommitOptions) WithPause(value bool) *CommitOptions {
+ v := &value
+ o.Pause = v
+ return o
+}
+
+// GetPause
+func (o *CommitOptions) GetPause() bool {
+ var pause bool
+ if o.Pause == nil {
+ return pause
+ }
+ return *o.Pause
+}
+
+// WithRepo
+func (o *CommitOptions) WithRepo(value string) *CommitOptions {
+ v := &value
+ o.Repo = v
+ return o
+}
+
+// GetRepo
+func (o *CommitOptions) GetRepo() string {
+ var repo string
+ if o.Repo == nil {
+ return repo
+ }
+ return *o.Repo
+}
+
+// WithTag
+func (o *CommitOptions) WithTag(value string) *CommitOptions {
+ v := &value
+ o.Tag = v
+ return o
+}
+
+// GetTag
+func (o *CommitOptions) GetTag() string {
+ var tag string
+ if o.Tag == nil {
+ return tag
+ }
+ return *o.Tag
+}
diff --git a/pkg/bindings/containers/types_create_options.go b/pkg/bindings/containers/types_create_options.go
new file mode 100644
index 000000000..4dbce0203
--- /dev/null
+++ b/pkg/bindings/containers/types_create_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.011789618 -0600 CST m=+0.000259413
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_diff_options.go b/pkg/bindings/containers/types_diff_options.go
new file mode 100644
index 000000000..be3bbf554
--- /dev/null
+++ b/pkg/bindings/containers/types_diff_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.159128927 -0600 CST m=+0.000255635
+*/
+
+// Changed
+func (o *DiffOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *DiffOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_execinspect_options.go b/pkg/bindings/containers/types_execinspect_options.go
new file mode 100644
index 000000000..3c4c870be
--- /dev/null
+++ b/pkg/bindings/containers/types_execinspect_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.303239014 -0600 CST m=+0.000256861
+*/
+
+// Changed
+func (o *ExecInspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExecInspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_execstart_options.go b/pkg/bindings/containers/types_execstart_options.go
new file mode 100644
index 000000000..66fdc82cb
--- /dev/null
+++ b/pkg/bindings/containers/types_execstart_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.447714428 -0600 CST m=+0.000257278
+*/
+
+// Changed
+func (o *ExecStartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExecStartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_execstartandattach_options.go b/pkg/bindings/containers/types_execstartandattach_options.go
new file mode 100644
index 000000000..43900d29d
--- /dev/null
+++ b/pkg/bindings/containers/types_execstartandattach_options.go
@@ -0,0 +1,186 @@
+package containers
+
+import (
+ "bufio"
+ "io"
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.827903078 -0600 CST m=+0.000269906
+*/
+
+// Changed
+func (o *ExecStartAndAttachOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExecStartAndAttachOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithOutputStream
+func (o *ExecStartAndAttachOptions) WithOutputStream(value io.WriteCloser) *ExecStartAndAttachOptions {
+ v := &value
+ o.OutputStream = v
+ return o
+}
+
+// GetOutputStream
+func (o *ExecStartAndAttachOptions) GetOutputStream() io.WriteCloser {
+ var outputStream io.WriteCloser
+ if o.OutputStream == nil {
+ return outputStream
+ }
+ return *o.OutputStream
+}
+
+// WithErrorStream
+func (o *ExecStartAndAttachOptions) WithErrorStream(value io.WriteCloser) *ExecStartAndAttachOptions {
+ v := &value
+ o.ErrorStream = v
+ return o
+}
+
+// GetErrorStream
+func (o *ExecStartAndAttachOptions) GetErrorStream() io.WriteCloser {
+ var errorStream io.WriteCloser
+ if o.ErrorStream == nil {
+ return errorStream
+ }
+ return *o.ErrorStream
+}
+
+// WithInputStream
+func (o *ExecStartAndAttachOptions) WithInputStream(value bufio.Reader) *ExecStartAndAttachOptions {
+ v := &value
+ o.InputStream = v
+ return o
+}
+
+// GetInputStream
+func (o *ExecStartAndAttachOptions) GetInputStream() bufio.Reader {
+ var inputStream bufio.Reader
+ if o.InputStream == nil {
+ return inputStream
+ }
+ return *o.InputStream
+}
+
+// WithAttachOutput
+func (o *ExecStartAndAttachOptions) WithAttachOutput(value bool) *ExecStartAndAttachOptions {
+ v := &value
+ o.AttachOutput = v
+ return o
+}
+
+// GetAttachOutput
+func (o *ExecStartAndAttachOptions) GetAttachOutput() bool {
+ var attachOutput bool
+ if o.AttachOutput == nil {
+ return attachOutput
+ }
+ return *o.AttachOutput
+}
+
+// WithAttachError
+func (o *ExecStartAndAttachOptions) WithAttachError(value bool) *ExecStartAndAttachOptions {
+ v := &value
+ o.AttachError = v
+ return o
+}
+
+// GetAttachError
+func (o *ExecStartAndAttachOptions) GetAttachError() bool {
+ var attachError bool
+ if o.AttachError == nil {
+ return attachError
+ }
+ return *o.AttachError
+}
+
+// WithAttachInput
+func (o *ExecStartAndAttachOptions) WithAttachInput(value bool) *ExecStartAndAttachOptions {
+ v := &value
+ o.AttachInput = v
+ return o
+}
+
+// GetAttachInput
+func (o *ExecStartAndAttachOptions) GetAttachInput() bool {
+ var attachInput bool
+ if o.AttachInput == nil {
+ return attachInput
+ }
+ return *o.AttachInput
+}
diff --git a/pkg/bindings/containers/types_export_options.go b/pkg/bindings/containers/types_export_options.go
new file mode 100644
index 000000000..e325bd2cd
--- /dev/null
+++ b/pkg/bindings/containers/types_export_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.101679998 -0600 CST m=+0.000261669
+*/
+
+// Changed
+func (o *ExportOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExportOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_healthcheck_options.go b/pkg/bindings/containers/types_healthcheck_options.go
new file mode 100644
index 000000000..8c4300366
--- /dev/null
+++ b/pkg/bindings/containers/types_healthcheck_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.593883686 -0600 CST m=+0.000289845
+*/
+
+// Changed
+func (o *HealthCheckOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *HealthCheckOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_init_options.go b/pkg/bindings/containers/types_init_options.go
new file mode 100644
index 000000000..655362f62
--- /dev/null
+++ b/pkg/bindings/containers/types_init_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.245077233 -0600 CST m=+0.000255461
+*/
+
+// Changed
+func (o *InitOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InitOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_inspect_options.go b/pkg/bindings/containers/types_inspect_options.go
new file mode 100644
index 000000000..884f5524d
--- /dev/null
+++ b/pkg/bindings/containers/types_inspect_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.635987603 -0600 CST m=+0.000260270
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithSize
+func (o *InspectOptions) WithSize(value bool) *InspectOptions {
+ v := &value
+ o.Size = v
+ return o
+}
+
+// GetSize
+func (o *InspectOptions) GetSize() bool {
+ var size bool
+ if o.Size == nil {
+ return size
+ }
+ return *o.Size
+}
diff --git a/pkg/bindings/containers/types_kill_options.go b/pkg/bindings/containers/types_kill_options.go
new file mode 100644
index 000000000..3d6fa6224
--- /dev/null
+++ b/pkg/bindings/containers/types_kill_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.781581076 -0600 CST m=+0.000259040
+*/
+
+// Changed
+func (o *KillOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *KillOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_list_options.go b/pkg/bindings/containers/types_list_options.go
new file mode 100644
index 000000000..dd74d37b7
--- /dev/null
+++ b/pkg/bindings/containers/types_list_options.go
@@ -0,0 +1,186 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+ "strings"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.199081744 -0600 CST m=+0.000270626
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ fieldName = strings.ToLower(fieldName)
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *ListOptions) WithAll(value bool) *ListOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *ListOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
+
+// WithLast
+func (o *ListOptions) WithLast(value int) *ListOptions {
+ v := &value
+ o.Last = v
+ return o
+}
+
+// GetLast
+func (o *ListOptions) GetLast() int {
+ var last int
+ if o.Last == nil {
+ return last
+ }
+ return *o.Last
+}
+
+// WithNamespace
+func (o *ListOptions) WithNamespace(value bool) *ListOptions {
+ v := &value
+ o.Namespace = v
+ return o
+}
+
+// GetNamespace
+func (o *ListOptions) GetNamespace() bool {
+ var namespace bool
+ if o.Namespace == nil {
+ return namespace
+ }
+ return *o.Namespace
+}
+
+// WithSize
+func (o *ListOptions) WithSize(value bool) *ListOptions {
+ v := &value
+ o.Size = v
+ return o
+}
+
+// GetSize
+func (o *ListOptions) GetSize() bool {
+ var size bool
+ if o.Size == nil {
+ return size
+ }
+ return *o.Size
+}
+
+// WithSync
+func (o *ListOptions) WithSync(value bool) *ListOptions {
+ v := &value
+ o.Sync = v
+ return o
+}
+
+// GetSync
+func (o *ListOptions) GetSync() bool {
+ var sync bool
+ if o.Sync == nil {
+ return sync
+ }
+ return *o.Sync
+}
diff --git a/pkg/bindings/containers/types_log_options.go b/pkg/bindings/containers/types_log_options.go
new file mode 100644
index 000000000..a6958242f
--- /dev/null
+++ b/pkg/bindings/containers/types_log_options.go
@@ -0,0 +1,200 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.273264471 -0600 CST m=+0.000274536
+*/
+
+// Changed
+func (o *LogOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *LogOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFollow
+func (o *LogOptions) WithFollow(value bool) *LogOptions {
+ v := &value
+ o.Follow = v
+ return o
+}
+
+// GetFollow
+func (o *LogOptions) GetFollow() bool {
+ var follow bool
+ if o.Follow == nil {
+ return follow
+ }
+ return *o.Follow
+}
+
+// WithSince
+func (o *LogOptions) WithSince(value string) *LogOptions {
+ v := &value
+ o.Since = v
+ return o
+}
+
+// GetSince
+func (o *LogOptions) GetSince() string {
+ var since string
+ if o.Since == nil {
+ return since
+ }
+ return *o.Since
+}
+
+// WithStderr
+func (o *LogOptions) WithStderr(value bool) *LogOptions {
+ v := &value
+ o.Stderr = v
+ return o
+}
+
+// GetStderr
+func (o *LogOptions) GetStderr() bool {
+ var stderr bool
+ if o.Stderr == nil {
+ return stderr
+ }
+ return *o.Stderr
+}
+
+// WithStdout
+func (o *LogOptions) WithStdout(value bool) *LogOptions {
+ v := &value
+ o.Stdout = v
+ return o
+}
+
+// GetStdout
+func (o *LogOptions) GetStdout() bool {
+ var stdout bool
+ if o.Stdout == nil {
+ return stdout
+ }
+ return *o.Stdout
+}
+
+// WithTail
+func (o *LogOptions) WithTail(value string) *LogOptions {
+ v := &value
+ o.Tail = v
+ return o
+}
+
+// GetTail
+func (o *LogOptions) GetTail() string {
+ var tail string
+ if o.Tail == nil {
+ return tail
+ }
+ return *o.Tail
+}
+
+// WithTimestamps
+func (o *LogOptions) WithTimestamps(value bool) *LogOptions {
+ v := &value
+ o.Timestamps = v
+ return o
+}
+
+// GetTimestamps
+func (o *LogOptions) GetTimestamps() bool {
+ var timestamps bool
+ if o.Timestamps == nil {
+ return timestamps
+ }
+ return *o.Timestamps
+}
+
+// WithUntil
+func (o *LogOptions) WithUntil(value string) *LogOptions {
+ v := &value
+ o.Until = v
+ return o
+}
+
+// GetUntil
+func (o *LogOptions) GetUntil() string {
+ var until string
+ if o.Until == nil {
+ return until
+ }
+ return *o.Until
+}
diff --git a/pkg/bindings/containers/types_mount_options.go b/pkg/bindings/containers/types_mount_options.go
new file mode 100644
index 000000000..c0e253094
--- /dev/null
+++ b/pkg/bindings/containers/types_mount_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.740822464 -0600 CST m=+0.000250074
+*/
+
+// Changed
+func (o *MountOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *MountOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_mountedcontainerpaths_options.go b/pkg/bindings/containers/types_mountedcontainerpaths_options.go
new file mode 100644
index 000000000..e368ff131
--- /dev/null
+++ b/pkg/bindings/containers/types_mountedcontainerpaths_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.048233253 -0600 CST m=+0.000307223
+*/
+
+// Changed
+func (o *MountedContainerPathsOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *MountedContainerPathsOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_pause_options.go b/pkg/bindings/containers/types_pause_options.go
new file mode 100644
index 000000000..26ad86793
--- /dev/null
+++ b/pkg/bindings/containers/types_pause_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.929891294 -0600 CST m=+0.000261081
+*/
+
+// Changed
+func (o *PauseOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PauseOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_prune_options.go b/pkg/bindings/containers/types_prune_options.go
new file mode 100644
index 000000000..e3c0f4de7
--- /dev/null
+++ b/pkg/bindings/containers/types_prune_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.344278799 -0600 CST m=+0.000263499
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *PruneOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/containers/types_remove_options.go b/pkg/bindings/containers/types_remove_options.go
new file mode 100644
index 000000000..6f59f0ed5
--- /dev/null
+++ b/pkg/bindings/containers/types_remove_options.go
@@ -0,0 +1,120 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:20.489968735 -0600 CST m=+0.000264450
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
+
+// WithVolumes
+func (o *RemoveOptions) WithVolumes(value bool) *RemoveOptions {
+ v := &value
+ o.Volumes = v
+ return o
+}
+
+// GetVolumes
+func (o *RemoveOptions) GetVolumes() bool {
+ var volumes bool
+ if o.Volumes == nil {
+ return volumes
+ }
+ return *o.Volumes
+}
diff --git a/pkg/bindings/containers/types_resizeexectty_options.go b/pkg/bindings/containers/types_resizeexectty_options.go
new file mode 100644
index 000000000..33bb4e78b
--- /dev/null
+++ b/pkg/bindings/containers/types_resizeexectty_options.go
@@ -0,0 +1,120 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.680735758 -0600 CST m=+0.000267081
+*/
+
+// Changed
+func (o *ResizeExecTTYOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ResizeExecTTYOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithHeight
+func (o *ResizeExecTTYOptions) WithHeight(value int) *ResizeExecTTYOptions {
+ v := &value
+ o.Height = v
+ return o
+}
+
+// GetHeight
+func (o *ResizeExecTTYOptions) GetHeight() int {
+ var height int
+ if o.Height == nil {
+ return height
+ }
+ return *o.Height
+}
+
+// WithWidth
+func (o *ResizeExecTTYOptions) WithWidth(value int) *ResizeExecTTYOptions {
+ v := &value
+ o.Width = v
+ return o
+}
+
+// GetWidth
+func (o *ResizeExecTTYOptions) GetWidth() int {
+ var width int
+ if o.Width == nil {
+ return width
+ }
+ return *o.Width
+}
diff --git a/pkg/bindings/containers/types_resizetty_options.go b/pkg/bindings/containers/types_resizetty_options.go
new file mode 100644
index 000000000..29ec54988
--- /dev/null
+++ b/pkg/bindings/containers/types_resizetty_options.go
@@ -0,0 +1,120 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.535788375 -0600 CST m=+0.000266528
+*/
+
+// Changed
+func (o *ResizeTTYOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ResizeTTYOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithHeight
+func (o *ResizeTTYOptions) WithHeight(value int) *ResizeTTYOptions {
+ v := &value
+ o.Height = v
+ return o
+}
+
+// GetHeight
+func (o *ResizeTTYOptions) GetHeight() int {
+ var height int
+ if o.Height == nil {
+ return height
+ }
+ return *o.Height
+}
+
+// WithWidth
+func (o *ResizeTTYOptions) WithWidth(value int) *ResizeTTYOptions {
+ v := &value
+ o.Width = v
+ return o
+}
+
+// GetWidth
+func (o *ResizeTTYOptions) GetWidth() int {
+ var width int
+ if o.Width == nil {
+ return width
+ }
+ return *o.Width
+}
diff --git a/pkg/bindings/containers/types_restart_options.go b/pkg/bindings/containers/types_restart_options.go
new file mode 100644
index 000000000..13ac099b1
--- /dev/null
+++ b/pkg/bindings/containers/types_restart_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.076709643 -0600 CST m=+0.000303354
+*/
+
+// Changed
+func (o *RestartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RestartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithTimeout
+func (o *RestartOptions) WithTimeout(value int) *RestartOptions {
+ v := &value
+ o.Timeout = v
+ return o
+}
+
+// GetTimeout
+func (o *RestartOptions) GetTimeout() int {
+ var timeout int
+ if o.Timeout == nil {
+ return timeout
+ }
+ return *o.Timeout
+}
diff --git a/pkg/bindings/containers/types_restore_options.go b/pkg/bindings/containers/types_restore_options.go
new file mode 100644
index 000000000..be6e94736
--- /dev/null
+++ b/pkg/bindings/containers/types_restore_options.go
@@ -0,0 +1,200 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:18.861536405 -0600 CST m=+0.000300026
+*/
+
+// Changed
+func (o *RestoreOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RestoreOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithIgnoreRootfs
+func (o *RestoreOptions) WithIgnoreRootfs(value bool) *RestoreOptions {
+ v := &value
+ o.IgnoreRootfs = v
+ return o
+}
+
+// GetIgnoreRootfs
+func (o *RestoreOptions) GetIgnoreRootfs() bool {
+ var ignoreRootfs bool
+ if o.IgnoreRootfs == nil {
+ return ignoreRootfs
+ }
+ return *o.IgnoreRootfs
+}
+
+// WithIgnoreStaticIP
+func (o *RestoreOptions) WithIgnoreStaticIP(value bool) *RestoreOptions {
+ v := &value
+ o.IgnoreStaticIP = v
+ return o
+}
+
+// GetIgnoreStaticIP
+func (o *RestoreOptions) GetIgnoreStaticIP() bool {
+ var ignoreStaticIP bool
+ if o.IgnoreStaticIP == nil {
+ return ignoreStaticIP
+ }
+ return *o.IgnoreStaticIP
+}
+
+// WithIgnoreStaticMAC
+func (o *RestoreOptions) WithIgnoreStaticMAC(value bool) *RestoreOptions {
+ v := &value
+ o.IgnoreStaticMAC = v
+ return o
+}
+
+// GetIgnoreStaticMAC
+func (o *RestoreOptions) GetIgnoreStaticMAC() bool {
+ var ignoreStaticMAC bool
+ if o.IgnoreStaticMAC == nil {
+ return ignoreStaticMAC
+ }
+ return *o.IgnoreStaticMAC
+}
+
+// WithImportAchive
+func (o *RestoreOptions) WithImportAchive(value string) *RestoreOptions {
+ v := &value
+ o.ImportAchive = v
+ return o
+}
+
+// GetImportAchive
+func (o *RestoreOptions) GetImportAchive() string {
+ var importAchive string
+ if o.ImportAchive == nil {
+ return importAchive
+ }
+ return *o.ImportAchive
+}
+
+// WithKeep
+func (o *RestoreOptions) WithKeep(value bool) *RestoreOptions {
+ v := &value
+ o.Keep = v
+ return o
+}
+
+// GetKeep
+func (o *RestoreOptions) GetKeep() bool {
+ var keep bool
+ if o.Keep == nil {
+ return keep
+ }
+ return *o.Keep
+}
+
+// WithName
+func (o *RestoreOptions) WithName(value string) *RestoreOptions {
+ v := &value
+ o.Name = v
+ return o
+}
+
+// GetName
+func (o *RestoreOptions) GetName() string {
+ var name string
+ if o.Name == nil {
+ return name
+ }
+ return *o.Name
+}
+
+// WithTCPEstablished
+func (o *RestoreOptions) WithTCPEstablished(value bool) *RestoreOptions {
+ v := &value
+ o.TCPEstablished = v
+ return o
+}
+
+// GetTCPEstablished
+func (o *RestoreOptions) GetTCPEstablished() bool {
+ var tCPEstablished bool
+ if o.TCPEstablished == nil {
+ return tCPEstablished
+ }
+ return *o.TCPEstablished
+}
diff --git a/pkg/bindings/containers/types_shouldrestart_options.go b/pkg/bindings/containers/types_shouldrestart_options.go
new file mode 100644
index 000000000..c833d0d8b
--- /dev/null
+++ b/pkg/bindings/containers/types_shouldrestart_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:22.388596051 -0600 CST m=+0.000253693
+*/
+
+// Changed
+func (o *ShouldRestartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ShouldRestartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_start_options.go b/pkg/bindings/containers/types_start_options.go
new file mode 100644
index 000000000..5918af89b
--- /dev/null
+++ b/pkg/bindings/containers/types_start_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.221364502 -0600 CST m=+0.000276575
+*/
+
+// Changed
+func (o *StartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDetachKeys
+func (o *StartOptions) WithDetachKeys(value string) *StartOptions {
+ v := &value
+ o.DetachKeys = v
+ return o
+}
+
+// GetDetachKeys
+func (o *StartOptions) GetDetachKeys() string {
+ var detachKeys string
+ if o.DetachKeys == nil {
+ return detachKeys
+ }
+ return *o.DetachKeys
+}
diff --git a/pkg/bindings/containers/types_stats_options.go b/pkg/bindings/containers/types_stats_options.go
new file mode 100644
index 000000000..f821ea1cd
--- /dev/null
+++ b/pkg/bindings/containers/types_stats_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.370213399 -0600 CST m=+0.000264334
+*/
+
+// Changed
+func (o *StatsOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StatsOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithStream
+func (o *StatsOptions) WithStream(value bool) *StatsOptions {
+ v := &value
+ o.Stream = v
+ return o
+}
+
+// GetStream
+func (o *StatsOptions) GetStream() bool {
+ var stream bool
+ if o.Stream == nil {
+ return stream
+ }
+ return *o.Stream
+}
diff --git a/pkg/bindings/containers/types_stop_options.go b/pkg/bindings/containers/types_stop_options.go
new file mode 100644
index 000000000..14d7633a0
--- /dev/null
+++ b/pkg/bindings/containers/types_stop_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.95469621 -0600 CST m=+0.000261399
+*/
+
+// Changed
+func (o *StopOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StopOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithTimeout
+func (o *StopOptions) WithTimeout(value uint) *StopOptions {
+ v := &value
+ o.Timeout = v
+ return o
+}
+
+// GetTimeout
+func (o *StopOptions) GetTimeout() uint {
+ var timeout uint
+ if o.Timeout == nil {
+ return timeout
+ }
+ return *o.Timeout
+}
diff --git a/pkg/bindings/containers/types_top_options.go b/pkg/bindings/containers/types_top_options.go
new file mode 100644
index 000000000..95a1ee686
--- /dev/null
+++ b/pkg/bindings/containers/types_top_options.go
@@ -0,0 +1,104 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.515867629 -0600 CST m=+0.000257106
+*/
+
+// Changed
+func (o *TopOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *TopOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDescriptors
+func (o *TopOptions) WithDescriptors(value []string) *TopOptions {
+ v := &value
+ o.Descriptors = v
+ return o
+}
+
+// GetDescriptors
+func (o *TopOptions) GetDescriptors() []string {
+ var descriptors []string
+ if o.Descriptors == nil {
+ return descriptors
+ }
+ return *o.Descriptors
+}
diff --git a/pkg/bindings/containers/types_unmount_options.go b/pkg/bindings/containers/types_unmount_options.go
new file mode 100644
index 000000000..a29bd8216
--- /dev/null
+++ b/pkg/bindings/containers/types_unmount_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:19.891657824 -0600 CST m=+0.000326668
+*/
+
+// Changed
+func (o *UnmountOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *UnmountOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_unpause_options.go b/pkg/bindings/containers/types_unpause_options.go
new file mode 100644
index 000000000..44c077df2
--- /dev/null
+++ b/pkg/bindings/containers/types_unpause_options.go
@@ -0,0 +1,88 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.661356277 -0600 CST m=+0.000262608
+*/
+
+// Changed
+func (o *UnpauseOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *UnpauseOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/containers/types_wait_options.go b/pkg/bindings/containers/types_wait_options.go
new file mode 100644
index 000000000..18d36c377
--- /dev/null
+++ b/pkg/bindings/containers/types_wait_options.go
@@ -0,0 +1,105 @@
+package containers
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ "github.com/containers/podman/v2/libpod/define"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 13:33:21.809397978 -0600 CST m=+0.000267049
+*/
+
+// Changed
+func (o *WaitOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *WaitOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithCondition
+func (o *WaitOptions) WithCondition(value define.ContainerStatus) *WaitOptions {
+ v := &value
+ o.Condition = v
+ return o
+}
+
+// GetCondition
+func (o *WaitOptions) GetCondition() define.ContainerStatus {
+ var condition define.ContainerStatus
+ if o.Condition == nil {
+ return condition
+ }
+ return *o.Condition
+}
diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go
index 8d0146ec1..29eb39557 100644
--- a/pkg/bindings/generate/generate.go
+++ b/pkg/bindings/generate/generate.go
@@ -4,31 +4,23 @@ import (
"context"
"errors"
"net/http"
- "net/url"
- "strconv"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
)
-func Systemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
+func Systemd(ctx context.Context, nameOrID string, options *SystemdOptions) (*entities.GenerateSystemdReport, error) {
+ if options == nil {
+ options = new(SystemdOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
-
- params.Set("useName", strconv.FormatBool(options.Name))
- params.Set("new", strconv.FormatBool(options.New))
- if options.RestartPolicy != "" {
- params.Set("restartPolicy", options.RestartPolicy)
- }
- if options.StopTimeout != nil {
- params.Set("stopTimeout", strconv.FormatUint(uint64(*options.StopTimeout), 10))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
- params.Set("containerPrefix", options.ContainerPrefix)
- params.Set("podPrefix", options.PodPrefix)
- params.Set("separator", options.Separator)
response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/systemd", params, nil, nameOrID)
if err != nil {
@@ -38,7 +30,10 @@ func Systemd(ctx context.Context, nameOrID string, options entities.GenerateSyst
return report, response.Process(&report.Units)
}
-func Kube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+func Kube(ctx context.Context, nameOrIDs []string, options *KubeOptions) (*entities.GenerateKubeReport, error) {
+ if options == nil {
+ options = new(KubeOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -46,12 +41,14 @@ func Kube(ctx context.Context, nameOrIDs []string, options entities.GenerateKube
if len(nameOrIDs) < 1 {
return nil, errors.New("must provide the name or ID of one container or pod")
}
- params := url.Values{}
+
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
for _, name := range nameOrIDs {
params.Add("names", name)
}
- params.Set("service", strconv.FormatBool(options.Service))
-
response, err := conn.DoRequest(nil, http.MethodGet, "/generate/kube", params, nil)
if err != nil {
return nil, err
diff --git a/pkg/bindings/generate/types.go b/pkg/bindings/generate/types.go
new file mode 100644
index 000000000..4e9d7a0ff
--- /dev/null
+++ b/pkg/bindings/generate/types.go
@@ -0,0 +1,27 @@
+package generate
+
+//go:generate go run ../generator/generator.go KubeOptions
+// KubeOptions are optional options for generating kube YAML files
+type KubeOptions struct {
+ // Service - generate YAML for a Kubernetes _service_ object.
+ Service *bool
+}
+
+//go:generate go run ../generator/generator.go SystemdOptions
+// SystemdOptions are optional options for generating systemd files
+type SystemdOptions struct {
+ // Name - use container/pod name instead of its ID.
+ UseName *bool
+ // New - create a new container instead of starting a new one.
+ New *bool
+ // RestartPolicy - systemd restart policy.
+ RestartPolicy *string
+ // StopTimeout - time when stopping the container.
+ StopTimeout *uint
+ // ContainerPrefix - systemd unit name prefix for containers
+ ContainerPrefix *string
+ // PodPrefix - systemd unit name prefix for pods
+ PodPrefix *string
+ // Separator - systemd unit name separator between name/id and prefix
+ Separator *string
+}
diff --git a/pkg/bindings/generate/types_kube_options.go b/pkg/bindings/generate/types_kube_options.go
new file mode 100644
index 000000000..68488aaee
--- /dev/null
+++ b/pkg/bindings/generate/types_kube_options.go
@@ -0,0 +1,104 @@
+package generate
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:20.522950566 -0600 CST m=+0.000154384
+*/
+
+// Changed
+func (o *KubeOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *KubeOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithService
+func (o *KubeOptions) WithService(value bool) *KubeOptions {
+ v := &value
+ o.Service = v
+ return o
+}
+
+// GetService
+func (o *KubeOptions) GetService() bool {
+ var service bool
+ if o.Service == nil {
+ return service
+ }
+ return *o.Service
+}
diff --git a/pkg/bindings/generate/types_systemd_options.go b/pkg/bindings/generate/types_systemd_options.go
new file mode 100644
index 000000000..0e8a46aa0
--- /dev/null
+++ b/pkg/bindings/generate/types_systemd_options.go
@@ -0,0 +1,200 @@
+package generate
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:20.661450253 -0600 CST m=+0.000135779
+*/
+
+// Changed
+func (o *SystemdOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *SystemdOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithUseName
+func (o *SystemdOptions) WithUseName(value bool) *SystemdOptions {
+ v := &value
+ o.UseName = v
+ return o
+}
+
+// GetUseName
+func (o *SystemdOptions) GetUseName() bool {
+ var useName bool
+ if o.UseName == nil {
+ return useName
+ }
+ return *o.UseName
+}
+
+// WithNew
+func (o *SystemdOptions) WithNew(value bool) *SystemdOptions {
+ v := &value
+ o.New = v
+ return o
+}
+
+// GetNew
+func (o *SystemdOptions) GetNew() bool {
+ var new bool
+ if o.New == nil {
+ return new
+ }
+ return *o.New
+}
+
+// WithRestartPolicy
+func (o *SystemdOptions) WithRestartPolicy(value string) *SystemdOptions {
+ v := &value
+ o.RestartPolicy = v
+ return o
+}
+
+// GetRestartPolicy
+func (o *SystemdOptions) GetRestartPolicy() string {
+ var restartPolicy string
+ if o.RestartPolicy == nil {
+ return restartPolicy
+ }
+ return *o.RestartPolicy
+}
+
+// WithStopTimeout
+func (o *SystemdOptions) WithStopTimeout(value uint) *SystemdOptions {
+ v := &value
+ o.StopTimeout = v
+ return o
+}
+
+// GetStopTimeout
+func (o *SystemdOptions) GetStopTimeout() uint {
+ var stopTimeout uint
+ if o.StopTimeout == nil {
+ return stopTimeout
+ }
+ return *o.StopTimeout
+}
+
+// WithContainerPrefix
+func (o *SystemdOptions) WithContainerPrefix(value string) *SystemdOptions {
+ v := &value
+ o.ContainerPrefix = v
+ return o
+}
+
+// GetContainerPrefix
+func (o *SystemdOptions) GetContainerPrefix() string {
+ var containerPrefix string
+ if o.ContainerPrefix == nil {
+ return containerPrefix
+ }
+ return *o.ContainerPrefix
+}
+
+// WithPodPrefix
+func (o *SystemdOptions) WithPodPrefix(value string) *SystemdOptions {
+ v := &value
+ o.PodPrefix = v
+ return o
+}
+
+// GetPodPrefix
+func (o *SystemdOptions) GetPodPrefix() string {
+ var podPrefix string
+ if o.PodPrefix == nil {
+ return podPrefix
+ }
+ return *o.PodPrefix
+}
+
+// WithSeparator
+func (o *SystemdOptions) WithSeparator(value string) *SystemdOptions {
+ v := &value
+ o.Separator = v
+ return o
+}
+
+// GetSeparator
+func (o *SystemdOptions) GetSeparator() string {
+ var separator string
+ if o.Separator == nil {
+ return separator
+ }
+ return *o.Separator
+}
diff --git a/pkg/bindings/generator/generator.go b/pkg/bindings/generator/generator.go
new file mode 100644
index 000000000..8c79aebae
--- /dev/null
+++ b/pkg/bindings/generator/generator.go
@@ -0,0 +1,261 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strings"
+ "text/template"
+ "time"
+)
+
+var bodyTmpl = `package {{.PackageName}}
+
+import (
+{{range $import := .Imports}} {{$import}}
+{{end}}
+
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created {{.Date}}
+*/
+
+// Changed
+func (o *{{.StructName}}) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *{{.StructName}}) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+`
+
+var fieldTmpl = `
+// With{{.Name}}
+func(o *{{.StructName}}) With{{.Name}}(value {{.Type}}) *{{.StructName}} {
+ v := {{.TypedValue}}
+ o.{{.Name}} = v
+ return o
+}
+
+// Get{{.Name}}
+func(o *{{.StructName}}) Get{{.Name}}() {{.Type}} {
+ var {{.ZeroName}} {{.Type}}
+ if o.{{.Name}} == nil {
+ return {{.ZeroName}}
+ }
+ return {{.TypedName}}
+}
+`
+
+type fieldStruct struct {
+ Name string
+ StructName string
+ Type string
+ TypedName string
+ TypedValue string
+ ZeroName string
+}
+
+func main() {
+ var (
+ closed bool
+ fieldStructs []fieldStruct
+ )
+ srcFile := os.Getenv("GOFILE")
+ pkg := os.Getenv("GOPACKAGE")
+ inputStructName := os.Args[1]
+ b, err := ioutil.ReadFile(srcFile)
+ if err != nil {
+ panic(err)
+ }
+ fset := token.NewFileSet() // positions are relative to fset
+ f, err := parser.ParseFile(fset, "", b, parser.ParseComments)
+ if err != nil {
+ panic(err)
+ }
+ // always add reflect
+ imports := []string{"\"reflect\""}
+ for _, imp := range f.Imports {
+ imports = append(imports, imp.Path.Value)
+ }
+
+ out, err := os.Create(strings.TrimRight(srcFile, ".go") + "_" + strings.Replace(strings.ToLower(inputStructName), "options", "_options", 1) + ".go")
+ if err != nil {
+ panic(err)
+ }
+ defer func() {
+ if !closed {
+ out.Close()
+ }
+ }()
+ bodyStruct := struct {
+ PackageName string
+ Imports []string
+ Date string
+ StructName string
+ }{
+ PackageName: pkg,
+ Imports: imports,
+ Date: time.Now().String(),
+ StructName: inputStructName,
+ }
+
+ body := template.Must(template.New("body").Parse(bodyTmpl))
+ fields := template.Must(template.New("fields").Parse(fieldTmpl))
+ ast.Inspect(f, func(n ast.Node) bool {
+ ref, refOK := n.(*ast.TypeSpec)
+ if refOK {
+ if ref.Name.Name == inputStructName {
+ x := ref.Type.(*ast.StructType)
+ for _, field := range x.Fields.List {
+ var (
+ name, zeroName, typedName, typedValue string
+ )
+ if len(field.Names) > 0 {
+ name = field.Names[0].Name
+ if len(name) < 1 {
+ panic(errors.New("bad name"))
+ }
+ }
+ for k, v := range name {
+ zeroName = strings.ToLower(string(v)) + name[k+1:]
+ break
+ }
+ //sub := "*"
+ typeExpr := field.Type
+ switch field.Type.(type) {
+ case *ast.MapType, *ast.StructType, *ast.ArrayType:
+ typedName = "o." + name
+ typedValue = "value"
+ default:
+ typedName = "*o." + name
+ typedValue = "&value"
+ }
+ start := typeExpr.Pos() - 1
+ end := typeExpr.End() - 1
+ fieldType := strings.Replace(string(b[start:end]), "*", "", 1)
+ fStruct := fieldStruct{
+ Name: name,
+ StructName: inputStructName,
+ Type: fieldType,
+ TypedName: typedName,
+ TypedValue: typedValue,
+ ZeroName: zeroName,
+ }
+ fieldStructs = append(fieldStructs, fStruct)
+ } // for
+
+ // create the body
+ if err := body.Execute(out, bodyStruct); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ // create with func from the struct fields
+ for _, fs := range fieldStructs {
+ if err := fields.Execute(out, fs); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ }
+
+ // close out file
+ if err := out.Close(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ closed = true
+
+ // go fmt file
+ gofmt := exec.Command("gofmt", "-w", "-s", out.Name())
+ gofmt.Stderr = os.Stdout
+ if err := gofmt.Run(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ // go import file
+ goimport := exec.Command("goimports", "-w", out.Name())
+ goimport.Stderr = os.Stdout
+ if err := goimport.Run(); err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ }
+
+ }
+ return true
+ })
+}
diff --git a/pkg/bindings/images/diff.go b/pkg/bindings/images/diff.go
index 10d50b0fd..8802c15e2 100644
--- a/pkg/bindings/images/diff.go
+++ b/pkg/bindings/images/diff.go
@@ -9,7 +9,11 @@ import (
)
// Diff provides the changes between two container layers
-func Diff(ctx context.Context, nameOrID string) ([]archive.Change, error) {
+func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive.Change, error) {
+ if options == nil {
+ options = new(DiffOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 2d3035d8d..ecdd1f553 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -8,11 +8,11 @@ import (
"net/url"
"strconv"
- "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
@@ -32,22 +32,18 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// List returns a list of images in local storage. The all boolean and filters parameters are optional
// ways to alter the image query.
-func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entities.ImageSummary, error) {
+func List(ctx context.Context, options *ListOptions) ([]*entities.ImageSummary, error) {
+ if options == nil {
+ options = new(ListOptions)
+ }
var imageSummary []*entities.ImageSummary
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
- }
- if filters != nil {
- strFilters, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", strFilters)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil)
if err != nil {
@@ -58,14 +54,17 @@ func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entit
// Get performs an image inspect. To have the on-disk size of the image calculated, you can
// use the optional size parameter.
-func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.ImageInspectReport, error) {
+func GetImage(ctx context.Context, nameOrID string, options *GetOptions) (*entities.ImageInspectReport, error) {
+ if options == nil {
+ options = new(GetOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if size != nil {
- params.Set("size", strconv.FormatBool(*size))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
inspectedData := entities.ImageInspectReport{}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nil, nameOrID)
@@ -76,15 +75,18 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image
}
// Tree retrieves a "tree" based representation of the given image
-func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.ImageTreeReport, error) {
+func Tree(ctx context.Context, nameOrID string, options *TreeOptions) (*entities.ImageTreeReport, error) {
+ if options == nil {
+ options = new(TreeOptions)
+ }
var report entities.ImageTreeReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if whatRequires != nil {
- params.Set("size", strconv.FormatBool(*whatRequires))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrID)
if err != nil {
@@ -94,7 +96,11 @@ func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.I
}
// History returns the parent layers of an image.
-func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, error) {
+func History(ctx context.Context, nameOrID string, options *HistoryOptions) ([]*handlers.HistoryResponse, error) {
+ if options == nil {
+ options = new(HistoryOptions)
+ }
+ _ = options
var history []*handlers.HistoryResponse
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -107,15 +113,18 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse,
return history, response.Process(&history)
}
-func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadReport, error) {
+func Load(ctx context.Context, r io.Reader, options *LoadOptions) (*entities.ImageLoadReport, error) {
+ if options == nil {
+ options = new(LoadOptions)
+ }
var report entities.ImageLoadReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if name != nil {
- params.Set("reference", *name)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil)
if err != nil {
@@ -124,49 +133,24 @@ func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadRe
return &report, response.Process(&report)
}
-func MultiExport(ctx context.Context, namesOrIds []string, w io.Writer, format *string, compress *bool) error {
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return err
- }
- params := url.Values{}
- if format != nil {
- params.Set("format", *format)
- }
- if compress != nil {
- params.Set("compress", strconv.FormatBool(*compress))
- }
- for _, ref := range namesOrIds {
- params.Add("references", ref)
+// Export saves images from local storage as a tarball or image archive. The optional format
+// parameter is used to change the format of the output.
+func Export(ctx context.Context, nameOrIDs []string, w io.Writer, options *ExportOptions) error {
+ if options == nil {
+ options = new(ExportOptions)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
-
- if response.StatusCode/100 == 2 || response.StatusCode/100 == 3 {
- _, err = io.Copy(w, response.Body)
- return err
- }
- return response.Process(nil)
-
-}
-
-// Export saves an image from local storage as a tarball or image archive. The optional format
-// parameter is used to change the format of the output.
-func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, compress *bool) error {
- conn, err := bindings.GetClient(ctx)
+ params, err := options.ToParams()
if err != nil {
return err
}
- params := url.Values{}
- if format != nil {
- params.Set("format", *format)
- }
- if compress != nil {
- params.Set("compress", strconv.FormatBool(*compress))
+ for _, ref := range nameOrIDs {
+ params.Add("references", ref)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil)
if err != nil {
return err
}
@@ -180,34 +164,35 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, c
// Prune removes unused images from local storage. The optional filters can be used to further
// define which images should be pruned.
-func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]string, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
var (
- deleted []string
+ deleted []*reports.PruneReport
)
+ if options == nil {
+ options = new(PruneOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
- }
- if filters != nil {
- stringFilter, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", stringFilter)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil)
if err != nil {
return deleted, err
}
- return deleted, response.Process(&deleted)
+ err = response.Process(&deleted)
+ return deleted, err
}
// Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
-func Tag(ctx context.Context, nameOrID, tag, repo string) error {
+func Tag(ctx context.Context, nameOrID, tag, repo string, options *TagOptions) error {
+ if options == nil {
+ options = new(TagOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -223,7 +208,11 @@ func Tag(ctx context.Context, nameOrID, tag, repo string) error {
}
// Untag removes a name from locally-stored image. Both the tag and repo parameters are required.
-func Untag(ctx context.Context, nameOrID, tag, repo string) error {
+func Untag(ctx context.Context, nameOrID, tag, repo string, options *UntagOptions) error {
+ if options == nil {
+ options = new(UntagOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@@ -241,27 +230,21 @@ func Untag(ctx context.Context, nameOrID, tag, repo string) error {
// Imports adds the given image to the local image store. This can be done by file and the given reader
// or via the url parameter. Additional metadata can be associated with the image by using the changes and
// message parameters. The image can also be tagged given a reference. One of url OR r must be provided.
-func Import(ctx context.Context, changes []string, message, reference, u *string, r io.Reader) (*entities.ImageImportReport, error) {
+func Import(ctx context.Context, r io.Reader, options *ImportOptions) (*entities.ImageImportReport, error) {
+ if options == nil {
+ options = new(ImportOptions)
+ }
var report entities.ImageImportReport
- if r != nil && u != nil {
+ if r != nil && options.URL != nil {
return nil, errors.New("url and r parameters cannot be used together")
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- for _, change := range changes {
- params.Add("changes", change)
- }
- if message != nil {
- params.Set("message", *message)
- }
- if reference != nil {
- params.Set("reference", *reference)
- }
- if u != nil {
- params.Set("url", *u)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil)
if err != nil {
@@ -275,25 +258,31 @@ func Import(ctx context.Context, changes []string, message, reference, u *string
// The destination must be a reference to a registry (i.e., of docker transport
// or be normalized to one). Other transports are rejected as they do not make
// sense in a remote context.
-func Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
+func Push(ctx context.Context, source string, destination string, options *PushOptions) error {
+ if options == nil {
+ options = new(PushOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
-
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return err
}
- params := url.Values{}
- params.Set("destination", destination)
- if options.SkipTLSVerify != types.OptionalBoolUndefined {
- // Note: we have to verify if skipped is false.
- verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
- params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
+ params, err := options.ToParams()
+ if err != nil {
+ return err
+ }
+ //SkipTLSVerify is special. We need to delete the param added by
+ //toparams and change the key and flip the bool
+ if options.SkipTLSVerify != nil {
+ params.Del("SkipTLSVerify")
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
+ params.Set("destination", destination)
path := fmt.Sprintf("/images/%s/push", source)
response, err := conn.DoRequest(nil, http.MethodPost, path, params, header)
@@ -305,28 +294,28 @@ func Push(ctx context.Context, source string, destination string, options entiti
}
// Search is the binding for libpod's v2 endpoints for Search images.
-func Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
+func Search(ctx context.Context, term string, options *SearchOptions) ([]entities.ImageSearchReport, error) {
+ if options == nil {
+ options = new(SearchOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- params.Set("term", term)
- params.Set("limit", strconv.Itoa(opts.Limit))
- params.Set("noTrunc", strconv.FormatBool(opts.NoTrunc))
- params.Set("listTags", strconv.FormatBool(opts.ListTags))
- for _, f := range opts.Filters {
- params.Set("filters", f)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
+ params.Set("term", term)
- if opts.SkipTLSVerify != types.OptionalBoolUndefined {
- // Note: we have to verify if skipped is false.
- verifyTLS := bool(opts.SkipTLSVerify == types.OptionalBoolFalse)
- params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
+ // Note: we have to verify if skipped is false.
+ if options.SkipTLSVerify != nil {
+ params.Del("SkipTLSVerify")
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, auth.XRegistryAuthHeader, opts.Authfile, "", "")
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), "", "")
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go
index c827b3283..5669c704e 100644
--- a/pkg/bindings/images/pull.go
+++ b/pkg/bindings/images/pull.go
@@ -8,11 +8,9 @@ import (
"io"
"io/ioutil"
"net/http"
- "net/url"
"os"
"strconv"
- "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -23,26 +21,28 @@ import (
// `rawImage` must be a reference to a registry (i.e., of docker transport or be
// normalized to one). Other transports are rejected as they do not make sense
// in a remote context. Progress reported on stderr
-func Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) ([]string, error) {
+func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string, error) {
+ if options == nil {
+ options = new(PullOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
params.Set("reference", rawImage)
- params.Set("overrideArch", options.OverrideArch)
- params.Set("overrideOS", options.OverrideOS)
- params.Set("overrideVariant", options.OverrideVariant)
- if options.SkipTLSVerify != types.OptionalBoolUndefined {
+ if options.SkipTLSVerify != nil {
+ params.Del("SkipTLSVerify")
// Note: we have to verify if skipped is false.
- verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
- params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
+ params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
- params.Set("allTags", strconv.FormatBool(options.AllTags))
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return nil, err
}
@@ -59,7 +59,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
// Historically pull writes status to stderr
stderr := io.Writer(os.Stderr)
- if options.Quiet {
+ if options.GetQuiet() {
stderr = ioutil.Discard
}
diff --git a/pkg/bindings/images/rm.go b/pkg/bindings/images/rm.go
index 9685b75e4..e652e66aa 100644
--- a/pkg/bindings/images/rm.go
+++ b/pkg/bindings/images/rm.go
@@ -3,8 +3,6 @@ package images
import (
"context"
"net/http"
- "net/url"
- "strconv"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
@@ -12,8 +10,12 @@ import (
"github.com/containers/podman/v2/pkg/errorhandling"
)
-// BachtRemove removes a batch of images from the local storage.
-func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) {
+// Remove removes one or more images from the local storage. Use optional force option to remove an
+// image, even if it's used by containers.
+func Remove(ctx context.Context, images []string, options *RemoveOptions) (*entities.ImageRemoveReport, []error) {
+ if options == nil {
+ options = new(RemoveOptions)
+ }
// FIXME - bindings tests are missing for this endpoint. Once the CI is
// re-enabled for bindings, we need to add them. At the time of writing,
// the tests don't compile.
@@ -23,13 +25,13 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
return nil, []error{err}
}
- params := url.Values{}
- params.Set("all", strconv.FormatBool(opts.All))
- params.Set("force", strconv.FormatBool(opts.Force))
- for _, i := range images {
- params.Add("images", i)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, nil
+ }
+ for _, image := range images {
+ params.Add("images", image)
}
-
response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params, nil)
if err != nil {
return nil, []error{err}
@@ -40,26 +42,3 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
return &report.ImageRemoveReport, errorhandling.StringsToErrors(report.Errors)
}
-
-// Remove removes an image from the local storage. Use force to remove an
-// image, even if it's used by containers.
-func Remove(ctx context.Context, nameOrID string, force bool) (*entities.ImageRemoveReport, error) {
- var report handlers.LibpodImagesRemoveReport
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
-
- params := url.Values{}
- params.Set("force", strconv.FormatBool(force))
- response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nil, nameOrID)
- if err != nil {
- return nil, err
- }
- if err := response.Process(&report); err != nil {
- return nil, err
- }
-
- errs := errorhandling.StringsToErrors(report.Errors)
- return &report.ImageRemoveReport, errorhandling.JoinErrors(errs)
-}
diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go
new file mode 100644
index 000000000..3adb4356b
--- /dev/null
+++ b/pkg/bindings/images/types.go
@@ -0,0 +1,193 @@
+package images
+
+import (
+ "github.com/containers/buildah/imagebuildah"
+ "github.com/containers/common/pkg/config"
+)
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for image removal
+type RemoveOptions struct {
+ // All removes all images
+ All *bool
+ // Forces removes all containers based on the image
+ Force *bool
+}
+
+//go:generate go run ../generator/generator.go DiffOptions
+// DiffOptions are optional options image diffs
+type DiffOptions struct {
+}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing images
+type ListOptions struct {
+ // All lists all image in the image store including dangling images
+ All *bool
+ // filters that can be used to get a more specific list of images
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go GetOptions
+// GetOptions are optional options for inspecting an image
+type GetOptions struct {
+ // Size computes the amount of storage the image consumes
+ Size *bool
+}
+
+//go:generate go run ../generator/generator.go TreeOptions
+// TreeOptions are optional options for a tree-based representation
+// of the image
+type TreeOptions struct {
+ // WhatRequires ...
+ WhatRequires *bool
+}
+
+//go:generate go run ../generator/generator.go HistoryOptions
+// HistoryOptions are optional options image history
+type HistoryOptions struct {
+}
+
+//go:generate go run ../generator/generator.go LoadOptions
+// LoadOptions are optional options for loading an image
+type LoadOptions struct {
+ // Reference is the name of the loaded image
+ Reference *string
+}
+
+//go:generate go run ../generator/generator.go ExportOptions
+// ExportOptions are optional options for exporting images
+type ExportOptions struct {
+ // Compress the image
+ Compress *bool
+ // Format of the output
+ Format *string
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning images
+type PruneOptions struct {
+ // Prune all images
+ All *bool
+ // Filters to apply when pruning images
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go TagOptions
+// TagOptions are optional options for tagging images
+type TagOptions struct {
+}
+
+//go:generate go run ../generator/generator.go UntagOptions
+// UntagOptions are optional options for untagging images
+type UntagOptions struct {
+}
+
+//go:generate go run ../generator/generator.go ImportOptions
+// ImportOptions are optional options for importing images
+type ImportOptions struct {
+ // Changes to be applied to the image
+ Changes *[]string
+ // Message to be applied to the image
+ Message *string
+ // Reference is a tag to be applied to the image
+ Reference *string
+ // Url to option image to import. Cannot be used with the reader
+ URL *string
+}
+
+//go:generate go run ../generator/generator.go PushOptions
+// PushOptions are optional options for importing images
+type PushOptions struct {
+ // Authfile is the path to the authentication file. Ignored for remote
+ // calls.
+ Authfile *string
+ // CertDir is the path to certificate directories. Ignored for remote
+ // calls.
+ CertDir *string
+ // Compress tarball image layers when pushing to a directory using the 'dir'
+ // transport. Default is same compression type as source. Ignored for remote
+ // calls.
+ Compress *bool
+ // Username for authenticating against the registry.
+ Username *string
+ // Password for authenticating against the registry.
+ Password *string
+ // DigestFile, after copying the image, write the digest of the resulting
+ // image to the file. Ignored for remote calls.
+ DigestFile *string
+ // Format is the Manifest type (oci, v2s1, or v2s2) to use when pushing an
+ // image using the 'dir' transport. Default is manifest type of source.
+ // Ignored for remote calls.
+ Format *string
+ // Quiet can be specified to suppress pull progress when pulling. Ignored
+ // for remote calls.
+ Quiet *bool
+ // RemoveSignatures, discard any pre-existing signatures in the image.
+ // Ignored for remote calls.
+ RemoveSignatures *bool
+ // SignaturePolicy to use when pulling. Ignored for remote calls.
+ SignaturePolicy *string
+ // SignBy adds a signature at the destination using the specified key.
+ // Ignored for remote calls.
+ SignBy *string
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify *bool
+}
+
+//go:generate go run ../generator/generator.go SearchOptions
+// SearchOptions are optional options for searching images on registries
+type SearchOptions struct {
+ // Authfile is the path to the authentication file. Ignored for remote
+ // calls.
+ Authfile *string
+ // Filters for the search results.
+ Filters map[string][]string
+ // Limit the number of results.
+ Limit *int
+ // NoTrunc will not truncate the output.
+ NoTrunc *bool
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify *bool
+ // ListTags search the available tags of the repository
+ ListTags *bool
+}
+
+//go:generate go run ../generator/generator.go PullOptions
+// PullOptions are optional options for pulling images
+type PullOptions struct {
+ // AllTags can be specified to pull all tags of an image. Note
+ // that this only works if the image does not include a tag.
+ AllTags *bool
+ // Authfile is the path to the authentication file. Ignored for remote
+ // calls.
+ Authfile *string
+ // CertDir is the path to certificate directories. Ignored for remote
+ // calls.
+ CertDir *string
+ // Username for authenticating against the registry.
+ Username *string
+ // Password for authenticating against the registry.
+ Password *string
+ // OverrideArch will overwrite the local architecture for image pulls.
+ OverrideArch *string
+ // OverrideOS will overwrite the local operating system (OS) for image
+ // pulls.
+ OverrideOS *string
+ // OverrideVariant will overwrite the local variant for image pulls.
+ OverrideVariant *string
+ // Quiet can be specified to suppress pull progress when pulling. Ignored
+ // for remote calls.
+ Quiet *bool
+ // SignaturePolicy to use when pulling. Ignored for remote calls.
+ SignaturePolicy *string
+ // SkipTLSVerify to skip HTTPS and certificate verification.
+ SkipTLSVerify *bool
+ // PullPolicy whether to pull new image
+ PullPolicy *config.PullPolicy
+}
+
+//BuildOptions are optional options for building images
+type BuildOptions struct {
+ imagebuildah.BuildOptions
+}
diff --git a/pkg/bindings/images/types_diff_options.go b/pkg/bindings/images/types_diff_options.go
new file mode 100644
index 000000000..d27c8945e
--- /dev/null
+++ b/pkg/bindings/images/types_diff_options.go
@@ -0,0 +1,88 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.320022698 -0600 CST m=+0.000277796
+*/
+
+// Changed
+func (o *DiffOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *DiffOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/images/types_export_options.go b/pkg/bindings/images/types_export_options.go
new file mode 100644
index 000000000..078b27fc0
--- /dev/null
+++ b/pkg/bindings/images/types_export_options.go
@@ -0,0 +1,120 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.173810543 -0600 CST m=+0.000239871
+*/
+
+// Changed
+func (o *ExportOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ExportOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithCompress
+func (o *ExportOptions) WithCompress(value bool) *ExportOptions {
+ v := &value
+ o.Compress = v
+ return o
+}
+
+// GetCompress
+func (o *ExportOptions) GetCompress() bool {
+ var compress bool
+ if o.Compress == nil {
+ return compress
+ }
+ return *o.Compress
+}
+
+// WithFormat
+func (o *ExportOptions) WithFormat(value string) *ExportOptions {
+ v := &value
+ o.Format = v
+ return o
+}
+
+// GetFormat
+func (o *ExportOptions) GetFormat() string {
+ var format string
+ if o.Format == nil {
+ return format
+ }
+ return *o.Format
+}
diff --git a/pkg/bindings/images/types_get_options.go b/pkg/bindings/images/types_get_options.go
new file mode 100644
index 000000000..1161657f7
--- /dev/null
+++ b/pkg/bindings/images/types_get_options.go
@@ -0,0 +1,104 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.609005517 -0600 CST m=+0.000241828
+*/
+
+// Changed
+func (o *GetOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *GetOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithSize
+func (o *GetOptions) WithSize(value bool) *GetOptions {
+ v := &value
+ o.Size = v
+ return o
+}
+
+// GetSize
+func (o *GetOptions) GetSize() bool {
+ var size bool
+ if o.Size == nil {
+ return size
+ }
+ return *o.Size
+}
diff --git a/pkg/bindings/images/types_history_options.go b/pkg/bindings/images/types_history_options.go
new file mode 100644
index 000000000..6f9854e03
--- /dev/null
+++ b/pkg/bindings/images/types_history_options.go
@@ -0,0 +1,88 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.890854681 -0600 CST m=+0.000243668
+*/
+
+// Changed
+func (o *HistoryOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *HistoryOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/images/types_import_options.go b/pkg/bindings/images/types_import_options.go
new file mode 100644
index 000000000..f5e6c8f7e
--- /dev/null
+++ b/pkg/bindings/images/types_import_options.go
@@ -0,0 +1,152 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.740585278 -0600 CST m=+0.000340441
+*/
+
+// Changed
+func (o *ImportOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ImportOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithChanges
+func (o *ImportOptions) WithChanges(value []string) *ImportOptions {
+ v := &value
+ o.Changes = v
+ return o
+}
+
+// GetChanges
+func (o *ImportOptions) GetChanges() []string {
+ var changes []string
+ if o.Changes == nil {
+ return changes
+ }
+ return *o.Changes
+}
+
+// WithMessage
+func (o *ImportOptions) WithMessage(value string) *ImportOptions {
+ v := &value
+ o.Message = v
+ return o
+}
+
+// GetMessage
+func (o *ImportOptions) GetMessage() string {
+ var message string
+ if o.Message == nil {
+ return message
+ }
+ return *o.Message
+}
+
+// WithReference
+func (o *ImportOptions) WithReference(value string) *ImportOptions {
+ v := &value
+ o.Reference = v
+ return o
+}
+
+// GetReference
+func (o *ImportOptions) GetReference() string {
+ var reference string
+ if o.Reference == nil {
+ return reference
+ }
+ return *o.Reference
+}
+
+// WithURL
+func (o *ImportOptions) WithURL(value string) *ImportOptions {
+ v := &value
+ o.URL = v
+ return o
+}
+
+// GetURL
+func (o *ImportOptions) GetURL() string {
+ var uRL string
+ if o.URL == nil {
+ return uRL
+ }
+ return *o.URL
+}
diff --git a/pkg/bindings/images/types_list_options.go b/pkg/bindings/images/types_list_options.go
new file mode 100644
index 000000000..209d72e34
--- /dev/null
+++ b/pkg/bindings/images/types_list_options.go
@@ -0,0 +1,120 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.462967928 -0600 CST m=+0.000289760
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *ListOptions) WithAll(value bool) *ListOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *ListOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/images/types_load_options.go b/pkg/bindings/images/types_load_options.go
new file mode 100644
index 000000000..6bba573d4
--- /dev/null
+++ b/pkg/bindings/images/types_load_options.go
@@ -0,0 +1,104 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.031848205 -0600 CST m=+0.000279409
+*/
+
+// Changed
+func (o *LoadOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *LoadOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithReference
+func (o *LoadOptions) WithReference(value string) *LoadOptions {
+ v := &value
+ o.Reference = v
+ return o
+}
+
+// GetReference
+func (o *LoadOptions) GetReference() string {
+ var reference string
+ if o.Reference == nil {
+ return reference
+ }
+ return *o.Reference
+}
diff --git a/pkg/bindings/images/types_prune_options.go b/pkg/bindings/images/types_prune_options.go
new file mode 100644
index 000000000..c29fdae12
--- /dev/null
+++ b/pkg/bindings/images/types_prune_options.go
@@ -0,0 +1,120 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.316938584 -0600 CST m=+0.000239843
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *PruneOptions) WithAll(value bool) *PruneOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *PruneOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithFilters
+func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *PruneOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/images/types_pull_options.go b/pkg/bindings/images/types_pull_options.go
new file mode 100644
index 000000000..07f3e079d
--- /dev/null
+++ b/pkg/bindings/images/types_pull_options.go
@@ -0,0 +1,281 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ "github.com/containers/common/pkg/config"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:28.164648348 -0600 CST m=+0.000243264
+*/
+
+// Changed
+func (o *PullOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PullOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAllTags
+func (o *PullOptions) WithAllTags(value bool) *PullOptions {
+ v := &value
+ o.AllTags = v
+ return o
+}
+
+// GetAllTags
+func (o *PullOptions) GetAllTags() bool {
+ var allTags bool
+ if o.AllTags == nil {
+ return allTags
+ }
+ return *o.AllTags
+}
+
+// WithAuthfile
+func (o *PullOptions) WithAuthfile(value string) *PullOptions {
+ v := &value
+ o.Authfile = v
+ return o
+}
+
+// GetAuthfile
+func (o *PullOptions) GetAuthfile() string {
+ var authfile string
+ if o.Authfile == nil {
+ return authfile
+ }
+ return *o.Authfile
+}
+
+// WithCertDir
+func (o *PullOptions) WithCertDir(value string) *PullOptions {
+ v := &value
+ o.CertDir = v
+ return o
+}
+
+// GetCertDir
+func (o *PullOptions) GetCertDir() string {
+ var certDir string
+ if o.CertDir == nil {
+ return certDir
+ }
+ return *o.CertDir
+}
+
+// WithUsername
+func (o *PullOptions) WithUsername(value string) *PullOptions {
+ v := &value
+ o.Username = v
+ return o
+}
+
+// GetUsername
+func (o *PullOptions) GetUsername() string {
+ var username string
+ if o.Username == nil {
+ return username
+ }
+ return *o.Username
+}
+
+// WithPassword
+func (o *PullOptions) WithPassword(value string) *PullOptions {
+ v := &value
+ o.Password = v
+ return o
+}
+
+// GetPassword
+func (o *PullOptions) GetPassword() string {
+ var password string
+ if o.Password == nil {
+ return password
+ }
+ return *o.Password
+}
+
+// WithOverrideArch
+func (o *PullOptions) WithOverrideArch(value string) *PullOptions {
+ v := &value
+ o.OverrideArch = v
+ return o
+}
+
+// GetOverrideArch
+func (o *PullOptions) GetOverrideArch() string {
+ var overrideArch string
+ if o.OverrideArch == nil {
+ return overrideArch
+ }
+ return *o.OverrideArch
+}
+
+// WithOverrideOS
+func (o *PullOptions) WithOverrideOS(value string) *PullOptions {
+ v := &value
+ o.OverrideOS = v
+ return o
+}
+
+// GetOverrideOS
+func (o *PullOptions) GetOverrideOS() string {
+ var overrideOS string
+ if o.OverrideOS == nil {
+ return overrideOS
+ }
+ return *o.OverrideOS
+}
+
+// WithOverrideVariant
+func (o *PullOptions) WithOverrideVariant(value string) *PullOptions {
+ v := &value
+ o.OverrideVariant = v
+ return o
+}
+
+// GetOverrideVariant
+func (o *PullOptions) GetOverrideVariant() string {
+ var overrideVariant string
+ if o.OverrideVariant == nil {
+ return overrideVariant
+ }
+ return *o.OverrideVariant
+}
+
+// WithQuiet
+func (o *PullOptions) WithQuiet(value bool) *PullOptions {
+ v := &value
+ o.Quiet = v
+ return o
+}
+
+// GetQuiet
+func (o *PullOptions) GetQuiet() bool {
+ var quiet bool
+ if o.Quiet == nil {
+ return quiet
+ }
+ return *o.Quiet
+}
+
+// WithSignaturePolicy
+func (o *PullOptions) WithSignaturePolicy(value string) *PullOptions {
+ v := &value
+ o.SignaturePolicy = v
+ return o
+}
+
+// GetSignaturePolicy
+func (o *PullOptions) GetSignaturePolicy() string {
+ var signaturePolicy string
+ if o.SignaturePolicy == nil {
+ return signaturePolicy
+ }
+ return *o.SignaturePolicy
+}
+
+// WithSkipTLSVerify
+func (o *PullOptions) WithSkipTLSVerify(value bool) *PullOptions {
+ v := &value
+ o.SkipTLSVerify = v
+ return o
+}
+
+// GetSkipTLSVerify
+func (o *PullOptions) GetSkipTLSVerify() bool {
+ var skipTLSVerify bool
+ if o.SkipTLSVerify == nil {
+ return skipTLSVerify
+ }
+ return *o.SkipTLSVerify
+}
+
+// WithPullPolicy
+func (o *PullOptions) WithPullPolicy(value config.PullPolicy) *PullOptions {
+ v := &value
+ o.PullPolicy = v
+ return o
+}
+
+// GetPullPolicy
+func (o *PullOptions) GetPullPolicy() config.PullPolicy {
+ var pullPolicy config.PullPolicy
+ if o.PullPolicy == nil {
+ return pullPolicy
+ }
+ return *o.PullPolicy
+}
diff --git a/pkg/bindings/images/types_push_options.go b/pkg/bindings/images/types_push_options.go
new file mode 100644
index 000000000..f9ce1b835
--- /dev/null
+++ b/pkg/bindings/images/types_push_options.go
@@ -0,0 +1,280 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.881232044 -0600 CST m=+0.000242458
+*/
+
+// Changed
+func (o *PushOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PushOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAuthfile
+func (o *PushOptions) WithAuthfile(value string) *PushOptions {
+ v := &value
+ o.Authfile = v
+ return o
+}
+
+// GetAuthfile
+func (o *PushOptions) GetAuthfile() string {
+ var authfile string
+ if o.Authfile == nil {
+ return authfile
+ }
+ return *o.Authfile
+}
+
+// WithCertDir
+func (o *PushOptions) WithCertDir(value string) *PushOptions {
+ v := &value
+ o.CertDir = v
+ return o
+}
+
+// GetCertDir
+func (o *PushOptions) GetCertDir() string {
+ var certDir string
+ if o.CertDir == nil {
+ return certDir
+ }
+ return *o.CertDir
+}
+
+// WithCompress
+func (o *PushOptions) WithCompress(value bool) *PushOptions {
+ v := &value
+ o.Compress = v
+ return o
+}
+
+// GetCompress
+func (o *PushOptions) GetCompress() bool {
+ var compress bool
+ if o.Compress == nil {
+ return compress
+ }
+ return *o.Compress
+}
+
+// WithUsername
+func (o *PushOptions) WithUsername(value string) *PushOptions {
+ v := &value
+ o.Username = v
+ return o
+}
+
+// GetUsername
+func (o *PushOptions) GetUsername() string {
+ var username string
+ if o.Username == nil {
+ return username
+ }
+ return *o.Username
+}
+
+// WithPassword
+func (o *PushOptions) WithPassword(value string) *PushOptions {
+ v := &value
+ o.Password = v
+ return o
+}
+
+// GetPassword
+func (o *PushOptions) GetPassword() string {
+ var password string
+ if o.Password == nil {
+ return password
+ }
+ return *o.Password
+}
+
+// WithDigestFile
+func (o *PushOptions) WithDigestFile(value string) *PushOptions {
+ v := &value
+ o.DigestFile = v
+ return o
+}
+
+// GetDigestFile
+func (o *PushOptions) GetDigestFile() string {
+ var digestFile string
+ if o.DigestFile == nil {
+ return digestFile
+ }
+ return *o.DigestFile
+}
+
+// WithFormat
+func (o *PushOptions) WithFormat(value string) *PushOptions {
+ v := &value
+ o.Format = v
+ return o
+}
+
+// GetFormat
+func (o *PushOptions) GetFormat() string {
+ var format string
+ if o.Format == nil {
+ return format
+ }
+ return *o.Format
+}
+
+// WithQuiet
+func (o *PushOptions) WithQuiet(value bool) *PushOptions {
+ v := &value
+ o.Quiet = v
+ return o
+}
+
+// GetQuiet
+func (o *PushOptions) GetQuiet() bool {
+ var quiet bool
+ if o.Quiet == nil {
+ return quiet
+ }
+ return *o.Quiet
+}
+
+// WithRemoveSignatures
+func (o *PushOptions) WithRemoveSignatures(value bool) *PushOptions {
+ v := &value
+ o.RemoveSignatures = v
+ return o
+}
+
+// GetRemoveSignatures
+func (o *PushOptions) GetRemoveSignatures() bool {
+ var removeSignatures bool
+ if o.RemoveSignatures == nil {
+ return removeSignatures
+ }
+ return *o.RemoveSignatures
+}
+
+// WithSignaturePolicy
+func (o *PushOptions) WithSignaturePolicy(value string) *PushOptions {
+ v := &value
+ o.SignaturePolicy = v
+ return o
+}
+
+// GetSignaturePolicy
+func (o *PushOptions) GetSignaturePolicy() string {
+ var signaturePolicy string
+ if o.SignaturePolicy == nil {
+ return signaturePolicy
+ }
+ return *o.SignaturePolicy
+}
+
+// WithSignBy
+func (o *PushOptions) WithSignBy(value string) *PushOptions {
+ v := &value
+ o.SignBy = v
+ return o
+}
+
+// GetSignBy
+func (o *PushOptions) GetSignBy() string {
+ var signBy string
+ if o.SignBy == nil {
+ return signBy
+ }
+ return *o.SignBy
+}
+
+// WithSkipTLSVerify
+func (o *PushOptions) WithSkipTLSVerify(value bool) *PushOptions {
+ v := &value
+ o.SkipTLSVerify = v
+ return o
+}
+
+// GetSkipTLSVerify
+func (o *PushOptions) GetSkipTLSVerify() bool {
+ var skipTLSVerify bool
+ if o.SkipTLSVerify == nil {
+ return skipTLSVerify
+ }
+ return *o.SkipTLSVerify
+}
diff --git a/pkg/bindings/images/types_remove_options.go b/pkg/bindings/images/types_remove_options.go
new file mode 100644
index 000000000..c9692c2b7
--- /dev/null
+++ b/pkg/bindings/images/types_remove_options.go
@@ -0,0 +1,120 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.180391541 -0600 CST m=+0.000290244
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *RemoveOptions) WithAll(value bool) *RemoveOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *RemoveOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/images/types_search_options.go b/pkg/bindings/images/types_search_options.go
new file mode 100644
index 000000000..e6168ac33
--- /dev/null
+++ b/pkg/bindings/images/types_search_options.go
@@ -0,0 +1,184 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:28.023569573 -0600 CST m=+0.000245548
+*/
+
+// Changed
+func (o *SearchOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *SearchOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAuthfile
+func (o *SearchOptions) WithAuthfile(value string) *SearchOptions {
+ v := &value
+ o.Authfile = v
+ return o
+}
+
+// GetAuthfile
+func (o *SearchOptions) GetAuthfile() string {
+ var authfile string
+ if o.Authfile == nil {
+ return authfile
+ }
+ return *o.Authfile
+}
+
+// WithFilters
+func (o *SearchOptions) WithFilters(value map[string][]string) *SearchOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *SearchOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
+
+// WithLimit
+func (o *SearchOptions) WithLimit(value int) *SearchOptions {
+ v := &value
+ o.Limit = v
+ return o
+}
+
+// GetLimit
+func (o *SearchOptions) GetLimit() int {
+ var limit int
+ if o.Limit == nil {
+ return limit
+ }
+ return *o.Limit
+}
+
+// WithNoTrunc
+func (o *SearchOptions) WithNoTrunc(value bool) *SearchOptions {
+ v := &value
+ o.NoTrunc = v
+ return o
+}
+
+// GetNoTrunc
+func (o *SearchOptions) GetNoTrunc() bool {
+ var noTrunc bool
+ if o.NoTrunc == nil {
+ return noTrunc
+ }
+ return *o.NoTrunc
+}
+
+// WithSkipTLSVerify
+func (o *SearchOptions) WithSkipTLSVerify(value bool) *SearchOptions {
+ v := &value
+ o.SkipTLSVerify = v
+ return o
+}
+
+// GetSkipTLSVerify
+func (o *SearchOptions) GetSkipTLSVerify() bool {
+ var skipTLSVerify bool
+ if o.SkipTLSVerify == nil {
+ return skipTLSVerify
+ }
+ return *o.SkipTLSVerify
+}
+
+// WithListTags
+func (o *SearchOptions) WithListTags(value bool) *SearchOptions {
+ v := &value
+ o.ListTags = v
+ return o
+}
+
+// GetListTags
+func (o *SearchOptions) GetListTags() bool {
+ var listTags bool
+ if o.ListTags == nil {
+ return listTags
+ }
+ return *o.ListTags
+}
diff --git a/pkg/bindings/images/types_tag_options.go b/pkg/bindings/images/types_tag_options.go
new file mode 100644
index 000000000..f6396e590
--- /dev/null
+++ b/pkg/bindings/images/types_tag_options.go
@@ -0,0 +1,88 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.457906682 -0600 CST m=+0.000245071
+*/
+
+// Changed
+func (o *TagOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *TagOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/images/types_tree_options.go b/pkg/bindings/images/types_tree_options.go
new file mode 100644
index 000000000..fb2493f85
--- /dev/null
+++ b/pkg/bindings/images/types_tree_options.go
@@ -0,0 +1,104 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:26.749625305 -0600 CST m=+0.000267624
+*/
+
+// Changed
+func (o *TreeOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *TreeOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithWhatRequires
+func (o *TreeOptions) WithWhatRequires(value bool) *TreeOptions {
+ v := &value
+ o.WhatRequires = v
+ return o
+}
+
+// GetWhatRequires
+func (o *TreeOptions) GetWhatRequires() bool {
+ var whatRequires bool
+ if o.WhatRequires == nil {
+ return whatRequires
+ }
+ return *o.WhatRequires
+}
diff --git a/pkg/bindings/images/types_untag_options.go b/pkg/bindings/images/types_untag_options.go
new file mode 100644
index 000000000..8faf5c14e
--- /dev/null
+++ b/pkg/bindings/images/types_untag_options.go
@@ -0,0 +1,88 @@
+package images
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:27.600379913 -0600 CST m=+0.000251449
+*/
+
+// Changed
+func (o *UntagOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *UntagOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go
index 0330b13e2..ef4e2a908 100644
--- a/pkg/bindings/manifests/manifests.go
+++ b/pkg/bindings/manifests/manifests.go
@@ -5,11 +5,9 @@ import (
"errors"
"net/http"
"net/url"
- "strconv"
"strings"
"github.com/containers/image/v5/manifest"
- "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
jsoniter "github.com/json-iterator/go"
@@ -19,8 +17,11 @@ import (
// the new manifest can also be specified. The all boolean specifies to add all entries
// of a list if the name provided is a manifest list. The ID of the new manifest list
// is returned as a string.
-func Create(ctx context.Context, names, images []string, all *bool) (string, error) {
+func Create(ctx context.Context, names, images []string, options *CreateOptions) (string, error) {
var idr handlers.IDResponse
+ if options == nil {
+ options = new(CreateOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
@@ -28,9 +29,9 @@ func Create(ctx context.Context, names, images []string, all *bool) (string, err
if len(names) < 1 {
return "", errors.New("creating a manifest requires at least one name argument")
}
- params := url.Values{}
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
+ params, err := options.ToParams()
+ if err != nil {
+ return "", err
}
for _, name := range names {
params.Add("name", name)
@@ -47,8 +48,12 @@ func Create(ctx context.Context, names, images []string, all *bool) (string, err
}
// Inspect returns a manifest list for a given name.
-func Inspect(ctx context.Context, name string) (*manifest.Schema2List, error) {
+func Inspect(ctx context.Context, name string, options *InspectOptions) (*manifest.Schema2List, error) {
var list manifest.Schema2List
+ if options == nil {
+ options = new(InspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -62,8 +67,11 @@ func Inspect(ctx context.Context, name string) (*manifest.Schema2List, error) {
// Add adds a manifest to a given manifest list. Additional options for the manifest
// can also be specified. The ID of the new manifest list is returned as a string
-func Add(ctx context.Context, name string, options image.ManifestAddOpts) (string, error) {
+func Add(ctx context.Context, name string, options *AddOptions) (string, error) {
var idr handlers.IDResponse
+ if options == nil {
+ options = new(AddOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
@@ -82,8 +90,12 @@ func Add(ctx context.Context, name string, options image.ManifestAddOpts) (strin
// Remove deletes a manifest entry from a manifest list. Both name and the digest to be
// removed are mandatory inputs. The ID of the new manifest list is returned as a string.
-func Remove(ctx context.Context, name, digest string) (string, error) {
+func Remove(ctx context.Context, name, digest string, options *RemoveOptions) (string, error) {
var idr handlers.IDResponse
+ if options == nil {
+ options = new(RemoveOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
@@ -100,24 +112,26 @@ func Remove(ctx context.Context, name, digest string) (string, error) {
// Push takes a manifest list and pushes to a destination. If the destination is not specified,
// the name will be used instead. If the optional all boolean is specified, all images specified
// in the list will be pushed as well.
-func Push(ctx context.Context, name string, destination *string, all *bool) (string, error) {
+func Push(ctx context.Context, name, destination string, options *PushOptions) (string, error) {
var (
idr handlers.IDResponse
)
- dest := name
+ if options == nil {
+ options = new(PushOptions)
+ }
+ if len(destination) < 1 {
+ destination = name
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
}
- params := url.Values{}
- params.Set("image", name)
- if destination != nil {
- dest = *destination
- }
- params.Set("destination", dest)
- if all != nil {
- params.Set("all", strconv.FormatBool(*all))
+ params, err := options.ToParams()
+ if err != nil {
+ return "", err
}
+ params.Set("image", name)
+ params.Set("destination", destination)
_, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, nil, name)
if err != nil {
return "", err
diff --git a/pkg/bindings/manifests/types.go b/pkg/bindings/manifests/types.go
new file mode 100644
index 000000000..f5054d424
--- /dev/null
+++ b/pkg/bindings/manifests/types.go
@@ -0,0 +1,36 @@
+package manifests
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting manifests
+type InspectOptions struct {
+}
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating manifests
+type CreateOptions struct {
+ All *bool
+}
+
+//go:generate go run ../generator/generator.go AddOptions
+// AddOptions are optional options for adding manifests
+type AddOptions struct {
+ All *bool
+ Annotation map[string]string
+ Arch *string
+ Features []string
+ Images []string
+ OS *string
+ OSVersion *string
+ Variant *string
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for removing manifests
+type RemoveOptions struct {
+}
+
+//go:generate go run ../generator/generator.go PushOptions
+// RemoveOptions are optional options for pushing manifests
+type PushOptions struct {
+ All *bool
+}
diff --git a/pkg/bindings/manifests/types_add_options.go b/pkg/bindings/manifests/types_add_options.go
new file mode 100644
index 000000000..d45effedc
--- /dev/null
+++ b/pkg/bindings/manifests/types_add_options.go
@@ -0,0 +1,216 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:55.92237379 -0600 CST m=+0.000150701
+*/
+
+// Changed
+func (o *AddOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *AddOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *AddOptions) WithAll(value bool) *AddOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *AddOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithAnnotation
+func (o *AddOptions) WithAnnotation(value map[string]string) *AddOptions {
+ v := value
+ o.Annotation = v
+ return o
+}
+
+// GetAnnotation
+func (o *AddOptions) GetAnnotation() map[string]string {
+ var annotation map[string]string
+ if o.Annotation == nil {
+ return annotation
+ }
+ return o.Annotation
+}
+
+// WithArch
+func (o *AddOptions) WithArch(value string) *AddOptions {
+ v := &value
+ o.Arch = v
+ return o
+}
+
+// GetArch
+func (o *AddOptions) GetArch() string {
+ var arch string
+ if o.Arch == nil {
+ return arch
+ }
+ return *o.Arch
+}
+
+// WithFeatures
+func (o *AddOptions) WithFeatures(value []string) *AddOptions {
+ v := value
+ o.Features = v
+ return o
+}
+
+// GetFeatures
+func (o *AddOptions) GetFeatures() []string {
+ var features []string
+ if o.Features == nil {
+ return features
+ }
+ return o.Features
+}
+
+// WithImages
+func (o *AddOptions) WithImages(value []string) *AddOptions {
+ v := value
+ o.Images = v
+ return o
+}
+
+// GetImages
+func (o *AddOptions) GetImages() []string {
+ var images []string
+ if o.Images == nil {
+ return images
+ }
+ return o.Images
+}
+
+// WithOS
+func (o *AddOptions) WithOS(value string) *AddOptions {
+ v := &value
+ o.OS = v
+ return o
+}
+
+// GetOS
+func (o *AddOptions) GetOS() string {
+ var oS string
+ if o.OS == nil {
+ return oS
+ }
+ return *o.OS
+}
+
+// WithOSVersion
+func (o *AddOptions) WithOSVersion(value string) *AddOptions {
+ v := &value
+ o.OSVersion = v
+ return o
+}
+
+// GetOSVersion
+func (o *AddOptions) GetOSVersion() string {
+ var oSVersion string
+ if o.OSVersion == nil {
+ return oSVersion
+ }
+ return *o.OSVersion
+}
+
+// WithVariant
+func (o *AddOptions) WithVariant(value string) *AddOptions {
+ v := &value
+ o.Variant = v
+ return o
+}
+
+// GetVariant
+func (o *AddOptions) GetVariant() string {
+ var variant string
+ if o.Variant == nil {
+ return variant
+ }
+ return *o.Variant
+}
diff --git a/pkg/bindings/manifests/types_create_options.go b/pkg/bindings/manifests/types_create_options.go
new file mode 100644
index 000000000..da07f1abf
--- /dev/null
+++ b/pkg/bindings/manifests/types_create_options.go
@@ -0,0 +1,104 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:55.784206871 -0600 CST m=+0.000157049
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *CreateOptions) WithAll(value bool) *CreateOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *CreateOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
diff --git a/pkg/bindings/manifests/types_inspect_options.go b/pkg/bindings/manifests/types_inspect_options.go
new file mode 100644
index 000000000..0d32d5bb9
--- /dev/null
+++ b/pkg/bindings/manifests/types_inspect_options.go
@@ -0,0 +1,88 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:55.631746481 -0600 CST m=+0.000143104
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/manifests/types_push_options.go b/pkg/bindings/manifests/types_push_options.go
new file mode 100644
index 000000000..4226733c9
--- /dev/null
+++ b/pkg/bindings/manifests/types_push_options.go
@@ -0,0 +1,104 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:56.197438009 -0600 CST m=+0.000149060
+*/
+
+// Changed
+func (o *PushOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PushOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *PushOptions) WithAll(value bool) *PushOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *PushOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
diff --git a/pkg/bindings/manifests/types_remove_options.go b/pkg/bindings/manifests/types_remove_options.go
new file mode 100644
index 000000000..f99220f6c
--- /dev/null
+++ b/pkg/bindings/manifests/types_remove_options.go
@@ -0,0 +1,88 @@
+package manifests
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:57:56.059954408 -0600 CST m=+0.000146015
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go
index 347f97703..7cd251b0e 100644
--- a/pkg/bindings/network/network.go
+++ b/pkg/bindings/network/network.go
@@ -2,10 +2,8 @@ package network
import (
"context"
- "encoding/json"
"net/http"
"net/url"
- "strconv"
"strings"
"github.com/containers/podman/v2/pkg/bindings"
@@ -14,15 +12,18 @@ import (
)
// Create makes a new CNI network configuration
-func Create(ctx context.Context, options entities.NetworkCreateOptions, name *string) (*entities.NetworkCreateReport, error) {
+func Create(ctx context.Context, options *CreateOptions) (*entities.NetworkCreateReport, error) {
var report entities.NetworkCreateReport
+ if options == nil {
+ options = new(CreateOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
- if name != nil {
- params.Set("name", *name)
+ if options.Name != nil {
+ params.Set("name", options.GetName())
}
networkConfig, err := jsoniter.MarshalToString(options)
if err != nil {
@@ -37,8 +38,12 @@ func Create(ctx context.Context, options entities.NetworkCreateOptions, name *st
}
// Inspect returns low level information about a CNI network configuration
-func Inspect(ctx context.Context, nameOrID string) ([]entities.NetworkInspectReport, error) {
+func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) ([]entities.NetworkInspectReport, error) {
var reports []entities.NetworkInspectReport
+ if options == nil {
+ options = new(InspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -53,15 +58,18 @@ func Inspect(ctx context.Context, nameOrID string) ([]entities.NetworkInspectRep
// Remove deletes a defined CNI network configuration by name. The optional force boolean
// will remove all containers associated with the network when set to true. A slice
// of NetworkRemoveReports are returned.
-func Remove(ctx context.Context, nameOrID string, force *bool) ([]*entities.NetworkRmReport, error) {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) ([]*entities.NetworkRmReport, error) {
var reports []*entities.NetworkRmReport
+ if options == nil {
+ options = new(RemoveOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if force != nil {
- params.Set("force", strconv.FormatBool(*force))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/networks/%s", params, nil, nameOrID)
if err != nil {
@@ -71,21 +79,20 @@ func Remove(ctx context.Context, nameOrID string, force *bool) ([]*entities.Netw
}
// List returns a summary of all CNI network configurations
-func List(ctx context.Context, options entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
+func List(ctx context.Context, options *ListOptions) ([]*entities.NetworkListReport, error) {
var (
netList []*entities.NetworkListReport
)
+ if options == nil {
+ options = new(ListOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if options.Filters != nil {
- b, err := json.Marshal(options.Filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", string(b))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/networks/json", params, nil)
if err != nil {
@@ -95,13 +102,28 @@ func List(ctx context.Context, options entities.NetworkListOptions) ([]*entities
}
// Disconnect removes a container from a given network
-func Disconnect(ctx context.Context, networkName string, options entities.NetworkDisconnectOptions) error {
+func Disconnect(ctx context.Context, networkName string, ContainerNameOrId string, options *DisconnectOptions) error {
+ if options == nil {
+ options = new(DisconnectOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
+ // No params are used for disconnect
params := url.Values{}
- body, err := jsoniter.MarshalToString(options)
+ // Disconnect sends everything in body
+ disconnect := struct {
+ Container string
+ Force bool
+ }{
+ Container: ContainerNameOrId,
+ }
+ if force := options.GetForce(); options.Changed("Force") {
+ disconnect.Force = force
+ }
+
+ body, err := jsoniter.MarshalToString(disconnect)
if err != nil {
return err
}
@@ -114,13 +136,27 @@ func Disconnect(ctx context.Context, networkName string, options entities.Networ
}
// Connect adds a container to a network
-func Connect(ctx context.Context, networkName string, options entities.NetworkConnectOptions) error {
+func Connect(ctx context.Context, networkName string, ContainerNameOrId string, options *ConnectOptions) error {
+ if options == nil {
+ options = new(ConnectOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
+ // No params are used in connect
params := url.Values{}
- body, err := jsoniter.MarshalToString(options)
+ // Connect sends everything in body
+ connect := struct {
+ Container string
+ Aliases []string
+ }{
+ Container: ContainerNameOrId,
+ }
+ if aliases := options.GetAliases(); options.Changed("Aliases") {
+ connect.Aliases = aliases
+ }
+ body, err := jsoniter.MarshalToString(connect)
if err != nil {
return err
}
diff --git a/pkg/bindings/network/types.go b/pkg/bindings/network/types.go
new file mode 100644
index 000000000..2a7e500dd
--- /dev/null
+++ b/pkg/bindings/network/types.go
@@ -0,0 +1,70 @@
+package network
+
+import "net"
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating networks
+type CreateOptions struct {
+ // DisableDNS turns off use of DNSMasq for name resolution
+ // on the network
+ DisableDNS *bool
+ // Driver is the name of network driver
+ Driver *string
+ // Gateway of the network
+ Gateway *net.IP
+ // Internal turns off communication outside the networking
+ // being created
+ Internal *bool
+ // Labels are metadata that can be associated with the network
+ Labels map[string]string
+ // MacVLAN is the name of the macvlan network to associate with
+ MacVLAN *string
+ // Range is the CIDR description of leasable IP addresses
+ IPRange *net.IPNet `scheme:"range"`
+ // Subnet to use
+ Subnet *net.IPNet
+ // IPv6 means the network is ipv6 capable
+ IPv6 *bool
+ // Options are a mapping of driver options and values.
+ Options map[string]string
+ // Name of the network
+ Name *string
+}
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting networks
+type InspectOptions struct {
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for inspecting networks
+type RemoveOptions struct {
+ // Force removes the network even if it is being used
+ Force *bool
+}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing networks
+type ListOptions struct {
+ // Filters are applied to the list of networks to be more
+ // specific on the output
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go DisconnectOptions
+// DisconnectOptions are optional options for disconnecting
+// containers from a network
+type DisconnectOptions struct {
+ // Force indicates to remove the container from
+ // the network forcibly
+ Force *bool
+}
+
+//go:generate go run ../generator/generator.go ConnectOptions
+// ConnectOptions are optional options for connecting
+// containers from a network
+type ConnectOptions struct {
+ // Aliases are names the container will be known as
+ // when using the dns plugin
+ Aliases *[]string
+}
diff --git a/pkg/bindings/network/types_connect_options.go b/pkg/bindings/network/types_connect_options.go
new file mode 100644
index 000000000..6fcc4536e
--- /dev/null
+++ b/pkg/bindings/network/types_connect_options.go
@@ -0,0 +1,104 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:34.075822786 -0600 CST m=+0.000167237
+*/
+
+// Changed
+func (o *ConnectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ConnectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAliases
+func (o *ConnectOptions) WithAliases(value []string) *ConnectOptions {
+ v := &value
+ o.Aliases = v
+ return o
+}
+
+// GetAliases
+func (o *ConnectOptions) GetAliases() []string {
+ var aliases []string
+ if o.Aliases == nil {
+ return aliases
+ }
+ return *o.Aliases
+}
diff --git a/pkg/bindings/network/types_create_options.go b/pkg/bindings/network/types_create_options.go
new file mode 100644
index 000000000..daec6a254
--- /dev/null
+++ b/pkg/bindings/network/types_create_options.go
@@ -0,0 +1,265 @@
+package network
+
+import (
+ "net"
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.37307678 -0600 CST m=+0.000176739
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDisableDNS
+func (o *CreateOptions) WithDisableDNS(value bool) *CreateOptions {
+ v := &value
+ o.DisableDNS = v
+ return o
+}
+
+// GetDisableDNS
+func (o *CreateOptions) GetDisableDNS() bool {
+ var disableDNS bool
+ if o.DisableDNS == nil {
+ return disableDNS
+ }
+ return *o.DisableDNS
+}
+
+// WithDriver
+func (o *CreateOptions) WithDriver(value string) *CreateOptions {
+ v := &value
+ o.Driver = v
+ return o
+}
+
+// GetDriver
+func (o *CreateOptions) GetDriver() string {
+ var driver string
+ if o.Driver == nil {
+ return driver
+ }
+ return *o.Driver
+}
+
+// WithGateway
+func (o *CreateOptions) WithGateway(value net.IP) *CreateOptions {
+ v := &value
+ o.Gateway = v
+ return o
+}
+
+// GetGateway
+func (o *CreateOptions) GetGateway() net.IP {
+ var gateway net.IP
+ if o.Gateway == nil {
+ return gateway
+ }
+ return *o.Gateway
+}
+
+// WithInternal
+func (o *CreateOptions) WithInternal(value bool) *CreateOptions {
+ v := &value
+ o.Internal = v
+ return o
+}
+
+// GetInternal
+func (o *CreateOptions) GetInternal() bool {
+ var internal bool
+ if o.Internal == nil {
+ return internal
+ }
+ return *o.Internal
+}
+
+// WithLabels
+func (o *CreateOptions) WithLabels(value map[string]string) *CreateOptions {
+ v := value
+ o.Labels = v
+ return o
+}
+
+// GetLabels
+func (o *CreateOptions) GetLabels() map[string]string {
+ var labels map[string]string
+ if o.Labels == nil {
+ return labels
+ }
+ return o.Labels
+}
+
+// WithMacVLAN
+func (o *CreateOptions) WithMacVLAN(value string) *CreateOptions {
+ v := &value
+ o.MacVLAN = v
+ return o
+}
+
+// GetMacVLAN
+func (o *CreateOptions) GetMacVLAN() string {
+ var macVLAN string
+ if o.MacVLAN == nil {
+ return macVLAN
+ }
+ return *o.MacVLAN
+}
+
+// WithIPRange
+func (o *CreateOptions) WithIPRange(value net.IPNet) *CreateOptions {
+ v := &value
+ o.IPRange = v
+ return o
+}
+
+// GetIPRange
+func (o *CreateOptions) GetIPRange() net.IPNet {
+ var ipRange net.IPNet
+ if o.IPRange == nil {
+ return ipRange
+ }
+ return *o.IPRange
+}
+
+// WithSubnet
+func (o *CreateOptions) WithSubnet(value net.IPNet) *CreateOptions {
+ v := &value
+ o.Subnet = v
+ return o
+}
+
+// GetSubnet
+func (o *CreateOptions) GetSubnet() net.IPNet {
+ var subnet net.IPNet
+ if o.Subnet == nil {
+ return subnet
+ }
+ return *o.Subnet
+}
+
+// WithIPv6
+func (o *CreateOptions) WithIPv6(value bool) *CreateOptions {
+ v := &value
+ o.IPv6 = v
+ return o
+}
+
+// GetIPv6
+func (o *CreateOptions) GetIPv6() bool {
+ var iPv6 bool
+ if o.IPv6 == nil {
+ return iPv6
+ }
+ return *o.IPv6
+}
+
+// WithOptions
+func (o *CreateOptions) WithOptions(value map[string]string) *CreateOptions {
+ v := value
+ o.Options = v
+ return o
+}
+
+// GetOptions
+func (o *CreateOptions) GetOptions() map[string]string {
+ var options map[string]string
+ if o.Options == nil {
+ return options
+ }
+ return o.Options
+}
+
+// WithName
+func (o *CreateOptions) WithName(value string) *CreateOptions {
+ v := &value
+ o.Name = v
+ return o
+}
+
+// GetName
+func (o *CreateOptions) GetName() string {
+ var name string
+ if o.Name == nil {
+ return name
+ }
+ return *o.Name
+}
diff --git a/pkg/bindings/network/types_disconnect_options.go b/pkg/bindings/network/types_disconnect_options.go
new file mode 100644
index 000000000..821279976
--- /dev/null
+++ b/pkg/bindings/network/types_disconnect_options.go
@@ -0,0 +1,104 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.936088242 -0600 CST m=+0.000168680
+*/
+
+// Changed
+func (o *DisconnectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *DisconnectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *DisconnectOptions) WithForce(value bool) *DisconnectOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *DisconnectOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/network/types_inspect_options.go b/pkg/bindings/network/types_inspect_options.go
new file mode 100644
index 000000000..7704904ce
--- /dev/null
+++ b/pkg/bindings/network/types_inspect_options.go
@@ -0,0 +1,88 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.520438264 -0600 CST m=+0.000172934
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/network/types_list_options.go b/pkg/bindings/network/types_list_options.go
new file mode 100644
index 000000000..bbd2a71db
--- /dev/null
+++ b/pkg/bindings/network/types_list_options.go
@@ -0,0 +1,104 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.796794129 -0600 CST m=+0.000180368
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/network/types_remove_options.go b/pkg/bindings/network/types_remove_options.go
new file mode 100644
index 000000000..b24835ae4
--- /dev/null
+++ b/pkg/bindings/network/types_remove_options.go
@@ -0,0 +1,104 @@
+package network
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:33.658228151 -0600 CST m=+0.000172527
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index cfb40d74b..9ee02a093 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -3,18 +3,19 @@ package play
import (
"context"
"net/http"
- "net/url"
"os"
"strconv"
- "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
)
-func Kube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.PlayKubeReport, error) {
var report entities.PlayKubeReport
+ if options == nil {
+ options = new(KubeOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -26,18 +27,19 @@ func Kube(ctx context.Context, path string, options entities.PlayKubeOptions) (*
}
defer f.Close()
- params := url.Values{}
- params.Set("network", options.Network)
- params.Set("logDriver", options.LogDriver)
- if options.SkipTLSVerify != types.OptionalBoolUndefined {
- params.Set("tlsVerify", strconv.FormatBool(options.SkipTLSVerify != types.OptionalBoolTrue))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
+ if options.SkipTLSVerify != nil {
+ params.Set("tlsVerify", strconv.FormatBool(options.GetSkipTLSVerify()))
}
- if options.Start != types.OptionalBoolUndefined {
- params.Set("start", strconv.FormatBool(options.Start == types.OptionalBoolTrue))
+ if options.Start != nil {
+ params.Set("start", strconv.FormatBool(options.GetStart()))
}
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/play/types.go b/pkg/bindings/play/types.go
new file mode 100644
index 000000000..5fb9a4d41
--- /dev/null
+++ b/pkg/bindings/play/types.go
@@ -0,0 +1,32 @@
+package play
+
+//go:generate go run ../generator/generator.go KubeOptions
+// KubeOptions are optional options for replaying kube YAML files
+type KubeOptions struct {
+ // Authfile - path to an authentication file.
+ Authfile *string
+ // CertDir - to a directory containing TLS certifications and keys.
+ CertDir *string
+ // Username for authenticating against the registry.
+ Username *string
+ // Password for authenticating against the registry.
+ Password *string
+ // Network - name of the CNI network to connect to.
+ Network *string
+ // Quiet - suppress output when pulling images.
+ Quiet *bool
+ // SignaturePolicy - path to a signature-policy file.
+ SignaturePolicy *string
+ // SkipTLSVerify - skip https and certificate validation when
+ // contacting container registries.
+ SkipTLSVerify *bool
+ // SeccompProfileRoot - path to a directory containing seccomp
+ // profiles.
+ SeccompProfileRoot *string
+ // ConfigMaps - slice of pathnames to kubernetes configmap YAMLs.
+ ConfigMaps *[]string
+ // LogDriver for the container. For example: journald
+ LogDriver *string
+ // Start - don't start the pod if false
+ Start *bool
+}
diff --git a/pkg/bindings/play/types_kube_options.go b/pkg/bindings/play/types_kube_options.go
new file mode 100644
index 000000000..91cdd30aa
--- /dev/null
+++ b/pkg/bindings/play/types_kube_options.go
@@ -0,0 +1,280 @@
+package play
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:02.386833736 -0600 CST m=+0.000171080
+*/
+
+// Changed
+func (o *KubeOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *KubeOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAuthfile
+func (o *KubeOptions) WithAuthfile(value string) *KubeOptions {
+ v := &value
+ o.Authfile = v
+ return o
+}
+
+// GetAuthfile
+func (o *KubeOptions) GetAuthfile() string {
+ var authfile string
+ if o.Authfile == nil {
+ return authfile
+ }
+ return *o.Authfile
+}
+
+// WithCertDir
+func (o *KubeOptions) WithCertDir(value string) *KubeOptions {
+ v := &value
+ o.CertDir = v
+ return o
+}
+
+// GetCertDir
+func (o *KubeOptions) GetCertDir() string {
+ var certDir string
+ if o.CertDir == nil {
+ return certDir
+ }
+ return *o.CertDir
+}
+
+// WithUsername
+func (o *KubeOptions) WithUsername(value string) *KubeOptions {
+ v := &value
+ o.Username = v
+ return o
+}
+
+// GetUsername
+func (o *KubeOptions) GetUsername() string {
+ var username string
+ if o.Username == nil {
+ return username
+ }
+ return *o.Username
+}
+
+// WithPassword
+func (o *KubeOptions) WithPassword(value string) *KubeOptions {
+ v := &value
+ o.Password = v
+ return o
+}
+
+// GetPassword
+func (o *KubeOptions) GetPassword() string {
+ var password string
+ if o.Password == nil {
+ return password
+ }
+ return *o.Password
+}
+
+// WithNetwork
+func (o *KubeOptions) WithNetwork(value string) *KubeOptions {
+ v := &value
+ o.Network = v
+ return o
+}
+
+// GetNetwork
+func (o *KubeOptions) GetNetwork() string {
+ var network string
+ if o.Network == nil {
+ return network
+ }
+ return *o.Network
+}
+
+// WithQuiet
+func (o *KubeOptions) WithQuiet(value bool) *KubeOptions {
+ v := &value
+ o.Quiet = v
+ return o
+}
+
+// GetQuiet
+func (o *KubeOptions) GetQuiet() bool {
+ var quiet bool
+ if o.Quiet == nil {
+ return quiet
+ }
+ return *o.Quiet
+}
+
+// WithSignaturePolicy
+func (o *KubeOptions) WithSignaturePolicy(value string) *KubeOptions {
+ v := &value
+ o.SignaturePolicy = v
+ return o
+}
+
+// GetSignaturePolicy
+func (o *KubeOptions) GetSignaturePolicy() string {
+ var signaturePolicy string
+ if o.SignaturePolicy == nil {
+ return signaturePolicy
+ }
+ return *o.SignaturePolicy
+}
+
+// WithSkipTLSVerify
+func (o *KubeOptions) WithSkipTLSVerify(value bool) *KubeOptions {
+ v := &value
+ o.SkipTLSVerify = v
+ return o
+}
+
+// GetSkipTLSVerify
+func (o *KubeOptions) GetSkipTLSVerify() bool {
+ var skipTLSVerify bool
+ if o.SkipTLSVerify == nil {
+ return skipTLSVerify
+ }
+ return *o.SkipTLSVerify
+}
+
+// WithSeccompProfileRoot
+func (o *KubeOptions) WithSeccompProfileRoot(value string) *KubeOptions {
+ v := &value
+ o.SeccompProfileRoot = v
+ return o
+}
+
+// GetSeccompProfileRoot
+func (o *KubeOptions) GetSeccompProfileRoot() string {
+ var seccompProfileRoot string
+ if o.SeccompProfileRoot == nil {
+ return seccompProfileRoot
+ }
+ return *o.SeccompProfileRoot
+}
+
+// WithConfigMaps
+func (o *KubeOptions) WithConfigMaps(value []string) *KubeOptions {
+ v := &value
+ o.ConfigMaps = v
+ return o
+}
+
+// GetConfigMaps
+func (o *KubeOptions) GetConfigMaps() []string {
+ var configMaps []string
+ if o.ConfigMaps == nil {
+ return configMaps
+ }
+ return *o.ConfigMaps
+}
+
+// WithLogDriver
+func (o *KubeOptions) WithLogDriver(value string) *KubeOptions {
+ v := &value
+ o.LogDriver = v
+ return o
+}
+
+// GetLogDriver
+func (o *KubeOptions) GetLogDriver() string {
+ var logDriver string
+ if o.LogDriver == nil {
+ return logDriver
+ }
+ return *o.LogDriver
+}
+
+// WithStart
+func (o *KubeOptions) WithStart(value bool) *KubeOptions {
+ v := &value
+ o.Start = v
+ return o
+}
+
+// GetStart
+func (o *KubeOptions) GetStart() bool {
+ var start bool
+ if o.Start == nil {
+ return start
+ }
+ return *o.Start
+}
diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go
index c3f98eaab..4fcaf81f1 100644
--- a/pkg/bindings/pods/pods.go
+++ b/pkg/bindings/pods/pods.go
@@ -2,10 +2,8 @@ package pods
import (
"context"
- "errors"
"net/http"
"net/url"
- "strconv"
"strings"
"github.com/containers/podman/v2/pkg/api/handlers"
@@ -15,10 +13,14 @@ import (
jsoniter "github.com/json-iterator/go"
)
-func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator) (*entities.PodCreateReport, error) {
+func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator, options *CreateOptions) (*entities.PodCreateReport, error) {
var (
pcr entities.PodCreateReport
)
+ if options == nil {
+ options = new(CreateOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -49,10 +51,14 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
}
// Inspect returns low-level information about the given pod.
-func Inspect(ctx context.Context, nameOrID string) (*entities.PodInspectReport, error) {
+func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*entities.PodInspectReport, error) {
var (
report entities.PodInspectReport
)
+ if options == nil {
+ options = new(InspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -66,17 +72,20 @@ func Inspect(ctx context.Context, nameOrID string) (*entities.PodInspectReport,
// Kill sends a SIGTERM to all the containers in a pod. The optional signal parameter
// can be used to override SIGTERM.
-func Kill(ctx context.Context, nameOrID string, signal *string) (*entities.PodKillReport, error) {
+func Kill(ctx context.Context, nameOrID string, options *KillOptions) (*entities.PodKillReport, error) {
var (
report entities.PodKillReport
)
+ if options == nil {
+ options = new(KillOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if signal != nil {
- params.Set("signal", *signal)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/kill", params, nil, nameOrID)
if err != nil {
@@ -86,8 +95,12 @@ func Kill(ctx context.Context, nameOrID string, signal *string) (*entities.PodKi
}
// Pause pauses all running containers in a given pod.
-func Pause(ctx context.Context, nameOrID string) (*entities.PodPauseReport, error) {
+func Pause(ctx context.Context, nameOrID string, options *PauseOptions) (*entities.PodPauseReport, error) {
var report entities.PodPauseReport
+ if options == nil {
+ options = new(PauseOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -101,8 +114,12 @@ func Pause(ctx context.Context, nameOrID string) (*entities.PodPauseReport, erro
// Prune by default removes all non-running pods in local storage.
// And with force set true removes all pods.
-func Prune(ctx context.Context) ([]*entities.PodPruneReport, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*entities.PodPruneReport, error) {
var reports []*entities.PodPruneReport
+ if options == nil {
+ options = new(PruneOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -116,21 +133,20 @@ func Prune(ctx context.Context) ([]*entities.PodPruneReport, error) {
// List returns all pods in local storage. The optional filters parameter can
// be used to refine which pods should be listed.
-func List(ctx context.Context, filters map[string][]string) ([]*entities.ListPodsReport, error) {
+func List(ctx context.Context, options *ListOptions) ([]*entities.ListPodsReport, error) {
var (
podsReports []*entities.ListPodsReport
)
+ if options == nil {
+ options = new(ListOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if filters != nil {
- stringFilter, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", stringFilter)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/pods/json", params, nil)
if err != nil {
@@ -140,8 +156,12 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.ListPod
}
// Restart restarts all containers in a pod.
-func Restart(ctx context.Context, nameOrID string) (*entities.PodRestartReport, error) {
+func Restart(ctx context.Context, nameOrID string, options *RestartOptions) (*entities.PodRestartReport, error) {
var report entities.PodRestartReport
+ if options == nil {
+ options = new(RestartOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -155,15 +175,18 @@ func Restart(ctx context.Context, nameOrID string) (*entities.PodRestartReport,
// Remove deletes a Pod from from local storage. The optional force parameter denotes
// that the Pod can be removed even if in a running state.
-func Remove(ctx context.Context, nameOrID string, force *bool) (*entities.PodRmReport, error) {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) (*entities.PodRmReport, error) {
var report entities.PodRmReport
+ if options == nil {
+ options = new(RemoveOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if force != nil {
- params.Set("force", strconv.FormatBool(*force))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/pods/%s", params, nil, nameOrID)
if err != nil {
@@ -173,8 +196,12 @@ func Remove(ctx context.Context, nameOrID string, force *bool) (*entities.PodRmR
}
// Start starts all containers in a pod.
-func Start(ctx context.Context, nameOrID string) (*entities.PodStartReport, error) {
+func Start(ctx context.Context, nameOrID string, options *StartOptions) (*entities.PodStartReport, error) {
var report entities.PodStartReport
+ if options == nil {
+ options = new(StartOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -192,15 +219,18 @@ func Start(ctx context.Context, nameOrID string) (*entities.PodStartReport, erro
// Stop stops all containers in a Pod. The optional timeout parameter can be
// used to override the timeout before the container is killed.
-func Stop(ctx context.Context, nameOrID string, timeout *int) (*entities.PodStopReport, error) {
+func Stop(ctx context.Context, nameOrID string, options *StopOptions) (*entities.PodStopReport, error) {
var report entities.PodStopReport
+ if options == nil {
+ options = new(StopOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
- if timeout != nil {
- params.Set("t", strconv.Itoa(*timeout))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/stop", params, nil, nameOrID)
if err != nil {
@@ -215,15 +245,16 @@ func Stop(ctx context.Context, nameOrID string, timeout *int) (*entities.PodStop
// Top gathers statistics about the running processes in a pod. The nameOrID can be a pod name
// or a partial/full ID. The descriptors allow for specifying which data to collect from each process.
-func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string, error) {
+func Top(ctx context.Context, nameOrID string, options *TopOptions) ([]string, error) {
+ if options == nil {
+ options = new(TopOptions)
+ }
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
-
- if len(descriptors) > 0 {
- // flatten the slice into one string
+ if descriptors := options.GetDescriptors(); len(descriptors) > 0 {
params.Set("ps_args", strings.Join(descriptors, ","))
}
response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/top", params, nil, nameOrID)
@@ -248,7 +279,11 @@ func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string,
}
// Unpause unpauses all paused containers in a Pod.
-func Unpause(ctx context.Context, nameOrID string) (*entities.PodUnpauseReport, error) {
+func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) (*entities.PodUnpauseReport, error) {
+ if options == nil {
+ options = new(UnpauseOptions)
+ }
+ _ = options
var report entities.PodUnpauseReport
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -262,19 +297,21 @@ func Unpause(ctx context.Context, nameOrID string) (*entities.PodUnpauseReport,
}
// Stats display resource-usage statistics of one or more pods.
-func Stats(ctx context.Context, namesOrIDs []string, options entities.PodStatsOptions) ([]*entities.PodStatsReport, error) {
- if options.Latest {
- return nil, errors.New("latest is not supported")
+func Stats(ctx context.Context, namesOrIDs []string, options *StatsOptions) ([]*entities.PodStatsReport, error) {
+ if options == nil {
+ options = new(StatsOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- params := url.Values{}
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
for _, i := range namesOrIDs {
params.Add("namesOrIDs", i)
}
- params.Set("all", strconv.FormatBool(options.All))
var reports []*entities.PodStatsReport
response, err := conn.DoRequest(nil, http.MethodGet, "/pods/stats", params, nil)
diff --git a/pkg/bindings/pods/types.go b/pkg/bindings/pods/types.go
new file mode 100644
index 000000000..370c1aaa9
--- /dev/null
+++ b/pkg/bindings/pods/types.go
@@ -0,0 +1,72 @@
+package pods
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating pods
+type CreateOptions struct {
+}
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting pods
+type InspectOptions struct {
+}
+
+//go:generate go run ../generator/generator.go KillOptions
+// KillOptions are optional options for killing pods
+type KillOptions struct {
+ Signal *string
+}
+
+//go:generate go run ../generator/generator.go PauseOptions
+// PauseOptions are optional options for pausing pods
+type PauseOptions struct {
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning pods
+type PruneOptions struct {
+}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing pods
+type ListOptions struct {
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go RestartOptions
+// RestartOptions are optional options for restarting pods
+type RestartOptions struct {
+}
+
+//go:generate go run ../generator/generator.go StartOptions
+// StartOptions are optional options for starting pods
+type StartOptions struct {
+}
+
+//go:generate go run ../generator/generator.go StopOptions
+// StopOptions are optional options for stopping pods
+type StopOptions struct {
+ Timeout *int
+}
+
+//go:generate go run ../generator/generator.go TopOptions
+// TopOptions are optional options for getting top on pods
+type TopOptions struct {
+ Descriptors []string
+}
+
+//go:generate go run ../generator/generator.go UnpauseOptions
+// UnpauseOptions are optional options for unpausinging pods
+type UnpauseOptions struct {
+}
+
+//go:generate go run ../generator/generator.go StatsOptions
+// StatsOptions are optional options for getting stats of pods
+type StatsOptions struct {
+ All *bool
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for removing pods
+type RemoveOptions struct {
+ Force *bool
+}
diff --git a/pkg/bindings/pods/types_create_options.go b/pkg/bindings/pods/types_create_options.go
new file mode 100644
index 000000000..b6cf0fc53
--- /dev/null
+++ b/pkg/bindings/pods/types_create_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.05490508 -0600 CST m=+0.000156396
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_inspect_options.go b/pkg/bindings/pods/types_inspect_options.go
new file mode 100644
index 000000000..1c881ce9c
--- /dev/null
+++ b/pkg/bindings/pods/types_inspect_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.258801519 -0600 CST m=+0.000175055
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_kill_options.go b/pkg/bindings/pods/types_kill_options.go
new file mode 100644
index 000000000..cb5bdfd01
--- /dev/null
+++ b/pkg/bindings/pods/types_kill_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.398857339 -0600 CST m=+0.000160135
+*/
+
+// Changed
+func (o *KillOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *KillOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithSignal
+func (o *KillOptions) WithSignal(value string) *KillOptions {
+ v := &value
+ o.Signal = v
+ return o
+}
+
+// GetSignal
+func (o *KillOptions) GetSignal() string {
+ var signal string
+ if o.Signal == nil {
+ return signal
+ }
+ return *o.Signal
+}
diff --git a/pkg/bindings/pods/types_list_options.go b/pkg/bindings/pods/types_list_options.go
new file mode 100644
index 000000000..d095bf3db
--- /dev/null
+++ b/pkg/bindings/pods/types_list_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.818123838 -0600 CST m=+0.000164328
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/pods/types_pause_options.go b/pkg/bindings/pods/types_pause_options.go
new file mode 100644
index 000000000..06ee6f81d
--- /dev/null
+++ b/pkg/bindings/pods/types_pause_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.538407099 -0600 CST m=+0.000193274
+*/
+
+// Changed
+func (o *PauseOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PauseOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_prune_options.go b/pkg/bindings/pods/types_prune_options.go
new file mode 100644
index 000000000..6610aa7cc
--- /dev/null
+++ b/pkg/bindings/pods/types_prune_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.678507342 -0600 CST m=+0.000183891
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_remove_options.go b/pkg/bindings/pods/types_remove_options.go
new file mode 100644
index 000000000..8f18e43c9
--- /dev/null
+++ b/pkg/bindings/pods/types_remove_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.80320679 -0600 CST m=+0.000158149
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/pods/types_restart_options.go b/pkg/bindings/pods/types_restart_options.go
new file mode 100644
index 000000000..9030de1e7
--- /dev/null
+++ b/pkg/bindings/pods/types_restart_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:40.958315383 -0600 CST m=+0.000168360
+*/
+
+// Changed
+func (o *RestartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RestartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_start_options.go b/pkg/bindings/pods/types_start_options.go
new file mode 100644
index 000000000..0fce21099
--- /dev/null
+++ b/pkg/bindings/pods/types_start_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.099102916 -0600 CST m=+0.000159629
+*/
+
+// Changed
+func (o *StartOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StartOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/pods/types_stats_options.go b/pkg/bindings/pods/types_stats_options.go
new file mode 100644
index 000000000..d38a9a115
--- /dev/null
+++ b/pkg/bindings/pods/types_stats_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.658228243 -0600 CST m=+0.000160769
+*/
+
+// Changed
+func (o *StatsOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StatsOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *StatsOptions) WithAll(value bool) *StatsOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *StatsOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
diff --git a/pkg/bindings/pods/types_stop_options.go b/pkg/bindings/pods/types_stop_options.go
new file mode 100644
index 000000000..ac698b8c5
--- /dev/null
+++ b/pkg/bindings/pods/types_stop_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.237892781 -0600 CST m=+0.000155040
+*/
+
+// Changed
+func (o *StopOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *StopOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithTimeout
+func (o *StopOptions) WithTimeout(value int) *StopOptions {
+ v := &value
+ o.Timeout = v
+ return o
+}
+
+// GetTimeout
+func (o *StopOptions) GetTimeout() int {
+ var timeout int
+ if o.Timeout == nil {
+ return timeout
+ }
+ return *o.Timeout
+}
diff --git a/pkg/bindings/pods/types_top_options.go b/pkg/bindings/pods/types_top_options.go
new file mode 100644
index 000000000..895f62957
--- /dev/null
+++ b/pkg/bindings/pods/types_top_options.go
@@ -0,0 +1,104 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.375876994 -0600 CST m=+0.000154839
+*/
+
+// Changed
+func (o *TopOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *TopOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithDescriptors
+func (o *TopOptions) WithDescriptors(value []string) *TopOptions {
+ v := value
+ o.Descriptors = v
+ return o
+}
+
+// GetDescriptors
+func (o *TopOptions) GetDescriptors() []string {
+ var descriptors []string
+ if o.Descriptors == nil {
+ return descriptors
+ }
+ return o.Descriptors
+}
diff --git a/pkg/bindings/pods/types_unpause_options.go b/pkg/bindings/pods/types_unpause_options.go
new file mode 100644
index 000000000..3d647cf25
--- /dev/null
+++ b/pkg/bindings/pods/types_unpause_options.go
@@ -0,0 +1,88 @@
+package pods
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:41.515225789 -0600 CST m=+0.000158667
+*/
+
+// Changed
+func (o *UnpauseOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *UnpauseOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/system/info.go b/pkg/bindings/system/info.go
index 79ee5cada..798010333 100644
--- a/pkg/bindings/system/info.go
+++ b/pkg/bindings/system/info.go
@@ -9,7 +9,11 @@ import (
)
// Info returns information about the libpod environment and its stores
-func Info(ctx context.Context) (*define.Info, error) {
+func Info(ctx context.Context, options *InfoOptions) (*define.Info, error) {
+ if options == nil {
+ options = new(InfoOptions)
+ }
+ _ = options
info := define.Info{}
conn, err := bindings.GetClient(ctx)
if err != nil {
diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go
index 1203f5c3c..815c967f1 100644
--- a/pkg/bindings/system/system.go
+++ b/pkg/bindings/system/system.go
@@ -6,8 +6,6 @@ import (
"fmt"
"io"
"net/http"
- "net/url"
- "strconv"
"time"
"github.com/containers/podman/v2/libpod/define"
@@ -20,27 +18,14 @@ import (
// Events allows you to monitor libdpod related events like container creation and
// removal. The events are then passed to the eventChan provided. The optional cancelChan
// can be used to cancel the read of events and close down the HTTP connection.
-func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan bool, since, until *string, filters map[string][]string, stream *bool) error {
+func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan bool, options *EventsOptions) error {
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
- if since != nil {
- params.Set("since", *since)
- }
- if until != nil {
- params.Set("until", *until)
- }
- if stream != nil {
- params.Set("stream", strconv.FormatBool(*stream))
- }
- if filters != nil {
- filterString, err := bindings.FiltersToString(filters)
- if err != nil {
- return errors.Wrap(err, "invalid filters")
- }
- params.Set("filters", filterString)
+ params, err := options.ToParams()
+ if err != nil {
+ return err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/events", params, nil)
if err != nil {
@@ -74,7 +59,7 @@ func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan
}
// Prune removes all unused system data.
-func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport, error) {
+func Prune(ctx context.Context, options *PruneOptions) (*entities.SystemPruneReport, error) {
var (
report entities.SystemPruneReport
)
@@ -82,12 +67,9 @@ func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport
if err != nil {
return nil, err
}
- params := url.Values{}
- if all != nil {
- params.Set("All", strconv.FormatBool(*all))
- }
- if volumes != nil {
- params.Set("Volumes", strconv.FormatBool(*volumes))
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/system/prune", params, nil)
if err != nil {
@@ -96,10 +78,15 @@ func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport
return &report, response.Process(&report)
}
-func Version(ctx context.Context) (*entities.SystemVersionReport, error) {
- var report entities.SystemVersionReport
- var component entities.ComponentVersion
-
+func Version(ctx context.Context, options *VersionOptions) (*entities.SystemVersionReport, error) {
+ var (
+ component entities.ComponentVersion
+ report entities.SystemVersionReport
+ )
+ if options == nil {
+ options = new(VersionOptions)
+ }
+ _ = options
version, err := define.GetVersion()
if err != nil {
return nil, err
@@ -140,8 +127,12 @@ func Version(ctx context.Context) (*entities.SystemVersionReport, error) {
// DiskUsage returns information about image, container, and volume disk
// consumption
-func DiskUsage(ctx context.Context) (*entities.SystemDfReport, error) {
+func DiskUsage(ctx context.Context, options *DiskOptions) (*entities.SystemDfReport, error) {
var report entities.SystemDfReport
+ if options == nil {
+ options = new(DiskOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/system/types.go b/pkg/bindings/system/types.go
new file mode 100644
index 000000000..16960b817
--- /dev/null
+++ b/pkg/bindings/system/types.go
@@ -0,0 +1,34 @@
+package system
+
+//go:generate go run ../generator/generator.go EventsOptions
+// EventsOptions are optional options for monitoring events
+type EventsOptions struct {
+ Filters map[string][]string
+ Since *string
+ Stream *bool
+ Until *string
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning
+type PruneOptions struct {
+ All *bool
+ Filters map[string][]string
+ Volumes *bool
+}
+
+//go:generate go run ../generator/generator.go VersionOptions
+// VersionOptions are optional options for getting version info
+type VersionOptions struct {
+}
+
+//go:generate go run ../generator/generator.go DiskOptions
+// DiskOptions are optional options for getting storage consumption
+type DiskOptions struct {
+}
+
+//go:generate go run ../generator/generator.go InfoOptions
+// InfoOptions are optional options for getting info
+// about libpod
+type InfoOptions struct {
+}
diff --git a/pkg/bindings/system/types_disk_options.go b/pkg/bindings/system/types_disk_options.go
new file mode 100644
index 000000000..f7d2cca06
--- /dev/null
+++ b/pkg/bindings/system/types_disk_options.go
@@ -0,0 +1,88 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:08.087362343 -0600 CST m=+0.000150636
+*/
+
+// Changed
+func (o *DiskOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *DiskOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/system/types_events_options.go b/pkg/bindings/system/types_events_options.go
new file mode 100644
index 000000000..6dd64b055
--- /dev/null
+++ b/pkg/bindings/system/types_events_options.go
@@ -0,0 +1,152 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:07.675150173 -0600 CST m=+0.000140977
+*/
+
+// Changed
+func (o *EventsOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *EventsOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *EventsOptions) WithFilters(value map[string][]string) *EventsOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *EventsOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
+
+// WithSince
+func (o *EventsOptions) WithSince(value string) *EventsOptions {
+ v := &value
+ o.Since = v
+ return o
+}
+
+// GetSince
+func (o *EventsOptions) GetSince() string {
+ var since string
+ if o.Since == nil {
+ return since
+ }
+ return *o.Since
+}
+
+// WithStream
+func (o *EventsOptions) WithStream(value bool) *EventsOptions {
+ v := &value
+ o.Stream = v
+ return o
+}
+
+// GetStream
+func (o *EventsOptions) GetStream() bool {
+ var stream bool
+ if o.Stream == nil {
+ return stream
+ }
+ return *o.Stream
+}
+
+// WithUntil
+func (o *EventsOptions) WithUntil(value string) *EventsOptions {
+ v := &value
+ o.Until = v
+ return o
+}
+
+// GetUntil
+func (o *EventsOptions) GetUntil() string {
+ var until string
+ if o.Until == nil {
+ return until
+ }
+ return *o.Until
+}
diff --git a/pkg/bindings/system/types_info_options.go b/pkg/bindings/system/types_info_options.go
new file mode 100644
index 000000000..3a8960e1b
--- /dev/null
+++ b/pkg/bindings/system/types_info_options.go
@@ -0,0 +1,88 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:08.233760126 -0600 CST m=+0.000142369
+*/
+
+// Changed
+func (o *InfoOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InfoOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/system/types_prune_options.go b/pkg/bindings/system/types_prune_options.go
new file mode 100644
index 000000000..2cd3c8000
--- /dev/null
+++ b/pkg/bindings/system/types_prune_options.go
@@ -0,0 +1,136 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:07.812719858 -0600 CST m=+0.000143214
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithAll
+func (o *PruneOptions) WithAll(value bool) *PruneOptions {
+ v := &value
+ o.All = v
+ return o
+}
+
+// GetAll
+func (o *PruneOptions) GetAll() bool {
+ var all bool
+ if o.All == nil {
+ return all
+ }
+ return *o.All
+}
+
+// WithFilters
+func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *PruneOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
+
+// WithVolumes
+func (o *PruneOptions) WithVolumes(value bool) *PruneOptions {
+ v := &value
+ o.Volumes = v
+ return o
+}
+
+// GetVolumes
+func (o *PruneOptions) GetVolumes() bool {
+ var volumes bool
+ if o.Volumes == nil {
+ return volumes
+ }
+ return *o.Volumes
+}
diff --git a/pkg/bindings/system/types_version_options.go b/pkg/bindings/system/types_version_options.go
new file mode 100644
index 000000000..4974e8d8f
--- /dev/null
+++ b/pkg/bindings/system/types_version_options.go
@@ -0,0 +1,88 @@
+package system
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:07.950759332 -0600 CST m=+0.000140376
+*/
+
+// Changed
+func (o *VersionOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *VersionOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/test/attach_test.go b/pkg/bindings/test/attach_test.go
index 12e51e734..9a46f6309 100644
--- a/pkg/bindings/test/attach_test.go
+++ b/pkg/bindings/test/attach_test.go
@@ -6,7 +6,6 @@ import (
"time"
"github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/specgen"
. "github.com/onsi/ginkgo"
@@ -43,7 +42,7 @@ var _ = Describe("Podman containers attach", func() {
go func() {
<-tickTock.C
timeout := uint(5)
- err := containers.Stop(bt.conn, id, &timeout)
+ err := containers.Stop(bt.conn, id, new(containers.StopOptions).WithTimeout(timeout))
if err != nil {
GinkgoWriter.Write([]byte(err.Error()))
}
@@ -53,8 +52,8 @@ var _ = Describe("Podman containers attach", func() {
stderr := &bytes.Buffer{}
go func() {
defer GinkgoRecover()
-
- err := containers.Attach(bt.conn, id, nil, bindings.PTrue, bindings.PTrue, nil, stdout, stderr, nil)
+ options := new(containers.AttachOptions).WithLogs(true).WithStream(true)
+ err := containers.Attach(bt.conn, id, nil, stdout, stderr, nil, options)
Expect(err).ShouldNot(HaveOccurred())
}()
@@ -69,21 +68,21 @@ var _ = Describe("Podman containers attach", func() {
s.Name = "CatAttachTest"
s.Terminal = true
s.Command = []string{"/bin/cat"}
- ctnr, err := containers.CreateWithSpec(bt.conn, s)
+ ctnr, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).ShouldNot(HaveOccurred())
err = containers.Start(bt.conn, ctnr.ID, nil)
Expect(err).ShouldNot(HaveOccurred())
wait := define.ContainerStateRunning
- _, err = containers.Wait(bt.conn, ctnr.ID, &wait)
+ _, err = containers.Wait(bt.conn, ctnr.ID, new(containers.WaitOptions).WithCondition(wait))
Expect(err).ShouldNot(HaveOccurred())
tickTock := time.NewTimer(2 * time.Second)
go func() {
<-tickTock.C
timeout := uint(5)
- err := containers.Stop(bt.conn, ctnr.ID, &timeout)
+ err := containers.Stop(bt.conn, ctnr.ID, new(containers.StopOptions).WithTimeout(timeout))
if err != nil {
GinkgoWriter.Write([]byte(err.Error()))
}
@@ -97,8 +96,8 @@ var _ = Describe("Podman containers attach", func() {
stderr := &bytes.Buffer{}
go func() {
defer GinkgoRecover()
-
- err := containers.Attach(bt.conn, ctnr.ID, nil, bindings.PFalse, bindings.PTrue, stdin, stdout, stderr, nil)
+ options := new(containers.AttachOptions).WithStream(true)
+ err := containers.Attach(bt.conn, ctnr.ID, stdin, stdout, stderr, nil, options)
Expect(err).ShouldNot(HaveOccurred())
}()
diff --git a/pkg/bindings/test/auth_test.go b/pkg/bindings/test/auth_test.go
index 4565b82b0..e647b3c36 100644
--- a/pkg/bindings/test/auth_test.go
+++ b/pkg/bindings/test/auth_test.go
@@ -9,7 +9,6 @@ import (
"github.com/containers/image/v5/types"
podmanRegistry "github.com/containers/podman/v2/hack/podman-registry-go"
"github.com/containers/podman/v2/pkg/bindings/images"
- "github.com/containers/podman/v2/pkg/domain/entities"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -52,27 +51,19 @@ var _ = Describe("Podman images", func() {
imageRef := imageRep + ":" + imageTag
// Tag the alpine image and verify it has worked.
- err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep)
+ err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep, nil)
Expect(err).To(BeNil())
_, err = images.GetImage(bt.conn, imageRef, nil)
Expect(err).To(BeNil())
// Now push the image.
- pushOpts := entities.ImagePushOptions{
- Username: registry.User,
- Password: registry.Password,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
+ pushOpts := new(images.PushOptions)
+ err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithUsername(registry.User).WithPassword(registry.Password).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Now pull the image.
- pullOpts := entities.ImagePullOptions{
- Username: registry.User,
- Password: registry.Password,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- _, err = images.Pull(bt.conn, imageRef, pullOpts)
+ pullOpts := new(images.PullOptions)
+ _, err = images.Pull(bt.conn, imageRef, pullOpts.WithSkipTLSVerify(true).WithPassword(registry.Password).WithUsername(registry.User))
Expect(err).To(BeNil())
})
@@ -110,33 +101,24 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil())
// Tag the alpine image and verify it has worked.
- err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep)
+ err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep, nil)
Expect(err).To(BeNil())
_, err = images.GetImage(bt.conn, imageRef, nil)
Expect(err).To(BeNil())
// Now push the image.
- pushOpts := entities.ImagePushOptions{
- Authfile: authFilePath,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
+ pushOpts := new(images.PushOptions)
+ err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Now pull the image.
- pullOpts := entities.ImagePullOptions{
- Authfile: authFilePath,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- _, err = images.Pull(bt.conn, imageRef, pullOpts)
+ pullOpts := new(images.PullOptions)
+ _, err = images.Pull(bt.conn, imageRef, pullOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Last, but not least, exercise search.
- searchOptions := entities.ImageSearchOptions{
- Authfile: authFilePath,
- SkipTLSVerify: types.OptionalBoolTrue,
- }
- _, err = images.Search(bt.conn, imageRef, searchOptions)
+ searchOptions := new(images.SearchOptions)
+ _, err = images.Search(bt.conn, imageRef, searchOptions.WithSkipTLSVerify(true).WithAuthfile(authFilePath))
Expect(err).To(BeNil())
})
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index 9dff2985f..232d7136f 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -198,7 +198,7 @@ func (b *bindingTest) RunTopContainer(containerName *string, insidePod *bool, po
if insidePod != nil && podName != nil {
s.Pod = *podName
}
- ctr, err := containers.CreateWithSpec(b.conn, s)
+ ctr, err := containers.CreateWithSpec(b.conn, s, nil)
if err != nil {
return "", nil
}
@@ -207,7 +207,7 @@ func (b *bindingTest) RunTopContainer(containerName *string, insidePod *bool, po
return "", err
}
wait := define.ContainerStateRunning
- _, err = containers.Wait(b.conn, ctr.ID, &wait)
+ _, err = containers.Wait(b.conn, ctr.ID, new(containers.WaitOptions).WithCondition(wait))
return ctr.ID, err
}
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index 15066ff1a..fa601e7e5 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/specgen"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -37,7 +38,7 @@ var _ = Describe("Podman containers ", func() {
It("podman pause a bogus container", func() {
// Pausing bogus container should return 404
- err = containers.Pause(bt.conn, "foobar")
+ err = containers.Pause(bt.conn, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -45,7 +46,7 @@ var _ = Describe("Podman containers ", func() {
It("podman unpause a bogus container", func() {
// Unpausing bogus container should return 404
- err = containers.Unpause(bt.conn, "foobar")
+ err = containers.Unpause(bt.conn, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -56,7 +57,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
// Ensure container is paused
@@ -70,7 +71,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
// Ensure container is paused
@@ -84,9 +85,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
- err = containers.Unpause(bt.conn, name)
+ err = containers.Unpause(bt.conn, name, nil)
Expect(err).To(BeNil())
// Ensure container is unpaused
@@ -101,11 +102,11 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Pause by name
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
//paused := "paused"
//_, err = containers.Wait(bt.conn, cid, &paused)
//Expect(err).To(BeNil())
- err = containers.Unpause(bt.conn, name)
+ err = containers.Unpause(bt.conn, name, nil)
Expect(err).To(BeNil())
// Ensure container is unpaused
@@ -119,9 +120,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -132,9 +133,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -147,7 +148,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).To(BeNil())
err = containers.Stop(bt.conn, name, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -160,7 +161,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).To(BeNil())
err = containers.Stop(bt.conn, cid, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -171,9 +172,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
- err = containers.Remove(bt.conn, cid, bindings.PFalse, bindings.PFalse)
+ err = containers.Remove(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -184,9 +185,9 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
- err = containers.Remove(bt.conn, cid, bindings.PTrue, bindings.PFalse)
+ err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true))
Expect(err).To(BeNil())
})
@@ -195,7 +196,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
err = containers.Stop(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
@@ -208,7 +209,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, cid)
+ err = containers.Pause(bt.conn, cid, nil)
Expect(err).To(BeNil())
err = containers.Stop(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
@@ -280,11 +281,11 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, nil, nil)
Expect(err).To(BeNil())
go func() {
- exitCode, err = containers.Wait(bt.conn, name, &pause)
+ exitCode, err = containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition(pause))
errChan <- err
close(errChan)
}()
- err = containers.Pause(bt.conn, name)
+ err = containers.Pause(bt.conn, name, nil)
Expect(err).To(BeNil())
wait := <-errChan
Expect(wait).To(BeNil())
@@ -294,11 +295,11 @@ var _ = Describe("Podman containers ", func() {
go func() {
defer GinkgoRecover()
- _, waitErr := containers.Wait(bt.conn, name, &running)
+ _, waitErr := containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition(running))
unpauseErrChan <- waitErr
close(unpauseErrChan)
}()
- err = containers.Unpause(bt.conn, name)
+ err = containers.Unpause(bt.conn, name, nil)
Expect(err).To(BeNil())
unPausewait := <-unpauseErrChan
Expect(unPausewait).To(BeNil())
@@ -309,7 +310,7 @@ var _ = Describe("Podman containers ", func() {
bt.runPodman([]string{"run", "-d", "--name", "hc", "--health-interval", "disable", "--health-retries", "2", "--health-cmd", "ls / || exit 1", alpine.name, "top"})
// bogus name should result in 404
- _, err := containers.RunHealthCheck(bt.conn, "foobar")
+ _, err := containers.RunHealthCheck(bt.conn, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -317,7 +318,7 @@ var _ = Describe("Podman containers ", func() {
// a container that has no healthcheck should be a 409
var name = "top"
bt.RunTopContainer(&name, bindings.PFalse, nil)
- _, err = containers.RunHealthCheck(bt.conn, name)
+ _, err = containers.RunHealthCheck(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusConflict))
@@ -355,7 +356,7 @@ var _ = Describe("Podman containers ", func() {
s := specgen.NewSpecGenerator(alpine.name, false)
s.Terminal = true
s.Command = []string{"date", "-R"}
- r, err := containers.CreateWithSpec(bt.conn, s)
+ r, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
err = containers.Start(bt.conn, r.ID, nil)
Expect(err).To(BeNil())
@@ -363,7 +364,7 @@ var _ = Describe("Podman containers ", func() {
_, err = containers.Wait(bt.conn, r.ID, nil)
Expect(err).To(BeNil())
- opts := containers.LogOptions{Stdout: bindings.PTrue, Follow: bindings.PTrue}
+ opts := new(containers.LogOptions).WithStdout(true).WithFollow(true)
go func() {
containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil)
}()
@@ -387,7 +388,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).To(BeNil())
// With descriptors
- output, err := containers.Top(bt.conn, cid, []string{"user,pid,hpid"})
+ output, err := containers.Top(bt.conn, cid, new(containers.TopOptions).WithDescriptors([]string{"user", "pid", "hpid"}))
Expect(err).To(BeNil())
header := strings.Split(output[0], "\t")
for _, d := range []string{"USER", "PID", "HPID"} {
@@ -399,7 +400,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).ToNot(BeNil())
// With bogus descriptors
- _, err = containers.Top(bt.conn, cid, []string{"Me,Neither"})
+ _, err = containers.Top(bt.conn, cid, new(containers.TopOptions).WithDescriptors([]string{"Me,Neither"}))
Expect(err).To(BeNil())
})
@@ -442,7 +443,7 @@ var _ = Describe("Podman containers ", func() {
It("podman kill bogus container", func() {
// Killing bogus container should return 404
- err := containers.Kill(bt.conn, "foobar", "SIGTERM")
+ err := containers.Kill(bt.conn, "foobar", "SIGTERM", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -453,7 +454,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, name, "SIGINT")
+ err = containers.Kill(bt.conn, name, "SIGINT", nil)
Expect(err).To(BeNil())
_, err = containers.Exists(bt.conn, name, false)
Expect(err).To(BeNil())
@@ -464,7 +465,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, cid, "SIGTERM")
+ err = containers.Kill(bt.conn, cid, "SIGTERM", nil)
Expect(err).To(BeNil())
_, err = containers.Exists(bt.conn, cid, false)
Expect(err).To(BeNil())
@@ -475,7 +476,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, cid, "SIGKILL")
+ err = containers.Kill(bt.conn, cid, "SIGKILL", nil)
Expect(err).To(BeNil())
})
@@ -484,7 +485,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, cid, "foobar")
+ err = containers.Kill(bt.conn, cid, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -494,19 +495,18 @@ var _ = Describe("Podman containers ", func() {
// Killing latest container should work
var name1 = "first"
var name2 = "second"
- var latestContainers = 1
_, err := bt.RunTopContainer(&name1, bindings.PFalse, nil)
Expect(err).To(BeNil())
_, err = bt.RunTopContainer(&name2, bindings.PFalse, nil)
Expect(err).To(BeNil())
- containerLatestList, err := containers.List(bt.conn, nil, nil, &latestContainers, nil, nil, nil)
+ containerLatestList, err := containers.List(bt.conn, new(containers.ListOptions).WithLast(1))
Expect(err).To(BeNil())
- err = containers.Kill(bt.conn, containerLatestList[0].Names[0], "SIGTERM")
+ err = containers.Kill(bt.conn, containerLatestList[0].Names[0], "SIGTERM", nil)
Expect(err).To(BeNil())
})
It("container init on a bogus container", func() {
- err := containers.ContainerInit(bt.conn, "doesnotexist")
+ err := containers.ContainerInit(bt.conn, "doesnotexist", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -514,12 +514,12 @@ var _ = Describe("Podman containers ", func() {
It("container init", func() {
s := specgen.NewSpecGenerator(alpine.name, false)
- ctr, err := containers.CreateWithSpec(bt.conn, s)
+ ctr, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
- err = containers.ContainerInit(bt.conn, ctr.ID)
+ err = containers.ContainerInit(bt.conn, ctr.ID, nil)
Expect(err).To(BeNil())
// trying to init again should be an error
- err = containers.ContainerInit(bt.conn, ctr.ID)
+ err = containers.ContainerInit(bt.conn, ctr.ID, nil)
Expect(err).ToNot(BeNil())
})
@@ -534,8 +534,8 @@ var _ = Describe("Podman containers ", func() {
// Prune container should return no errors and one pruned container ID.
pruneResponse, err := containers.Prune(bt.conn, nil)
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(1))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1))
})
It("podman prune stopped containers with filters", func() {
@@ -550,26 +550,26 @@ var _ = Describe("Podman containers ", func() {
filtersIncorrect := map[string][]string{
"status": {"dummy"},
}
- pruneResponse, err := containers.Prune(bt.conn, filtersIncorrect)
+ pruneResponse, err := containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
Expect(err).ToNot(BeNil())
// Mismatched filter params no container should be pruned.
filtersIncorrect = map[string][]string{
"name": {"r"},
}
- pruneResponse, err = containers.Prune(bt.conn, filtersIncorrect)
+ pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
// Valid filter params container should be pruned now.
filters := map[string][]string{
"name": {"top"},
}
- pruneResponse, err = containers.Prune(bt.conn, filters)
+ pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filters))
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(1))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1))
})
It("podman prune running containers", func() {
@@ -586,7 +586,7 @@ var _ = Describe("Podman containers ", func() {
// Prune. Should return no error no prune response ID.
pruneResponse, err := containers.Prune(bt.conn, nil)
Expect(err).To(BeNil())
- Expect(len(pruneResponse.ID)).To(Equal(0))
+ Expect(len(pruneResponse)).To(Equal(0))
})
It("podman inspect bogus container", func() {
@@ -620,7 +620,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- _, err = containers.Inspect(bt.conn, name, bindings.PTrue)
+ _, err = containers.Inspect(bt.conn, name, new(containers.InspectOptions).WithSize(true))
Expect(err).To(BeNil())
})
@@ -631,12 +631,12 @@ var _ = Describe("Podman containers ", func() {
err = containers.Stop(bt.conn, name, nil)
Expect(err).To(BeNil())
// Inspecting stopped container with size should succeed
- _, err = containers.Inspect(bt.conn, name, bindings.PTrue)
+ _, err = containers.Inspect(bt.conn, name, new(containers.InspectOptions).WithSize(true))
Expect(err).To(BeNil())
})
It("podman remove bogus container", func() {
- err = containers.Remove(bt.conn, "foobar", nil, nil)
+ err = containers.Remove(bt.conn, "foobar", nil)
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
})
@@ -646,7 +646,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, name, nil, nil)
+ err = containers.Remove(bt.conn, name, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -657,7 +657,7 @@ var _ = Describe("Podman containers ", func() {
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, cid, nil, nil)
+ err = containers.Remove(bt.conn, cid, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -668,7 +668,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, name, bindings.PTrue, nil)
+ err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithForce(true))
Expect(err).To(BeNil())
//code, _ := bindings.CheckResponseCode(err)
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -679,7 +679,7 @@ var _ = Describe("Podman containers ", func() {
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, cid, bindings.PTrue, nil)
+ err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true))
Expect(err).To(BeNil())
//code, _ := bindings.CheckResponseCode(err)
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -690,7 +690,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, name, nil, bindings.PTrue)
+ err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithVolumes(true))
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -701,7 +701,7 @@ var _ = Describe("Podman containers ", func() {
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, cid, nil, bindings.PTrue)
+ err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithVolumes(true))
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -712,7 +712,7 @@ var _ = Describe("Podman containers ", func() {
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, name, bindings.PTrue, bindings.PTrue)
+ err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithVolumes(true).WithForce(true))
Expect(err).To(BeNil())
//code, _ := bindings.CheckResponseCode(err)
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -723,7 +723,7 @@ var _ = Describe("Podman containers ", func() {
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
// Removing running container should fail
- err = containers.Remove(bt.conn, cid, bindings.PTrue, bindings.PTrue)
+ err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true).WithVolumes(true))
Expect(err).To(BeNil())
//code, _ := bindings.CheckResponseCode(err)
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -739,12 +739,12 @@ var _ = Describe("Podman containers ", func() {
s := specgen.NewSpecGenerator(alpine.name, false)
s.Terminal = true
s.Command = []string{"date", "-R"}
- _, err = containers.CreateWithSpec(bt.conn, s)
+ _, err = containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
// Validate list container with id filter
filters := make(map[string][]string)
filters["id"] = []string{cid}
- c, err := containers.List(bt.conn, filters, bindings.PTrue, nil, nil, nil, nil)
+ c, err := containers.List(bt.conn, new(containers.ListOptions).WithFilters(filters).WithAll(true))
Expect(err).To(BeNil())
Expect(len(c)).To(Equal(1))
})
@@ -758,7 +758,7 @@ var _ = Describe("Podman containers ", func() {
lastNum := 1
- c, err := containers.List(bt.conn, nil, bindings.PTrue, &lastNum, nil, nil, nil)
+ c, err := containers.List(bt.conn, new(containers.ListOptions).WithAll(true).WithLast(lastNum))
Expect(err).To(BeNil())
Expect(len(c)).To(Equal(1))
Expect(c[0].PodName).To(Equal(podName))
diff --git a/pkg/bindings/test/create_test.go b/pkg/bindings/test/create_test.go
index fd9ce23ca..2d2d657de 100644
--- a/pkg/bindings/test/create_test.go
+++ b/pkg/bindings/test/create_test.go
@@ -35,7 +35,7 @@ var _ = Describe("Create containers ", func() {
s.Command = []string{"top"}
s.Terminal = true
s.Name = "top"
- ctr, err := containers.CreateWithSpec(bt.conn, s)
+ ctr, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
data, err := containers.Inspect(bt.conn, ctr.ID, nil)
Expect(err).To(BeNil())
diff --git a/pkg/bindings/test/exec_test.go b/pkg/bindings/test/exec_test.go
index e3d90b9ea..8e20a192f 100644
--- a/pkg/bindings/test/exec_test.go
+++ b/pkg/bindings/test/exec_test.go
@@ -43,7 +43,7 @@ var _ = Describe("Podman containers exec", func() {
Expect(err).To(BeNil())
Expect(sessionID).To(Not(Equal("")))
- inspectOut, err := containers.ExecInspect(bt.conn, sessionID)
+ inspectOut, err := containers.ExecInspect(bt.conn, sessionID, nil)
Expect(err).To(BeNil())
Expect(inspectOut.ContainerID).To(Equal(cid))
Expect(inspectOut.ProcessConfig.Entrypoint).To(Equal("echo"))
@@ -71,7 +71,7 @@ var _ = Describe("Podman containers exec", func() {
})
It("Podman exec inspect on invalid session fails", func() {
- _, err := containers.ExecInspect(bt.conn, "0000000000000000000000000000000000000000000000000000000000000000")
+ _, err := containers.ExecInspect(bt.conn, "0000000000000000000000000000000000000000000000000000000000000000", nil)
Expect(err).To(Not(BeNil()))
})
})
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 7d9415f91..c6b9c20f9 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -9,7 +9,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/images"
- "github.com/containers/podman/v2/pkg/domain/entities"
+ dreports "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -71,12 +71,13 @@ var _ = Describe("Podman images", func() {
// Inspect by long name
_, err = images.GetImage(bt.conn, alpine.name, nil)
Expect(err).To(BeNil())
- // TODO it looks like the images API alwaays returns size regardless
+ // TODO it looks like the images API always returns size regardless
// of bool or not. What should we do ?
// Expect(data.Size).To(BeZero())
+ options := new(images.GetOptions).WithSize(true)
// Enabling the size parameter should result in size being populated
- data, err = images.GetImage(bt.conn, alpine.name, bindings.PTrue)
+ data, err = images.GetImage(bt.conn, alpine.name, options)
Expect(err).To(BeNil())
Expect(data.Size).To(BeNumerically(">", 0))
})
@@ -84,23 +85,19 @@ var _ = Describe("Podman images", func() {
// Test to validate the remove image api
It("remove image", func() {
// Remove invalid image should be a 404
- response, err := images.Remove(bt.conn, "foobar5000", false)
- Expect(err).ToNot(BeNil())
- Expect(response).To(BeNil())
- code, _ := bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusNotFound))
+ response, errs := images.Remove(bt.conn, []string{"foobar5000"}, nil)
+ Expect(len(errs)).To(BeNumerically(">", 0))
+ code, _ := bindings.CheckResponseCode(errs[0])
// Remove an image by name, validate image is removed and error is nil
inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil)
Expect(err).To(BeNil())
- response, err = images.Remove(bt.conn, busybox.shortName, false)
- Expect(err).To(BeNil())
- code, _ = bindings.CheckResponseCode(err)
+ response, errs = images.Remove(bt.conn, []string{busybox.shortName}, nil)
+ Expect(len(errs)).To(BeZero())
Expect(inspectData.ID).To(Equal(response.Deleted[0]))
inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil)
code, _ = bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Start a container with alpine image
var top string = "top"
@@ -113,23 +110,21 @@ var _ = Describe("Podman images", func() {
// try to remove the image "alpine". This should fail since we are not force
// deleting hence image cannot be deleted until the container is deleted.
- response, err = images.Remove(bt.conn, alpine.shortName, false)
- code, _ = bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusConflict))
+ response, errs = images.Remove(bt.conn, []string{alpine.shortName}, nil)
+ code, _ = bindings.CheckResponseCode(errs[0])
// Removing the image "alpine" where force = true
- response, err = images.Remove(bt.conn, alpine.shortName, true)
- Expect(err).To(BeNil())
+ options := new(images.RemoveOptions).WithForce(true)
+ response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options)
+ Expect(len(errs)).To(BeZero())
// To be extra sure, check if the previously created container
// is gone as well.
- _, err = containers.Inspect(bt.conn, "top", bindings.PFalse)
+ _, err = containers.Inspect(bt.conn, "top", nil)
code, _ = bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Now make sure both images are gone.
inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil)
code, _ = bindings.CheckResponseCode(err)
- Expect(code).To(BeNumerically("==", http.StatusNotFound))
inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil)
code, _ = bindings.CheckResponseCode(err)
@@ -138,14 +133,15 @@ var _ = Describe("Podman images", func() {
// Tests to validate the image tag command.
It("tag image", func() {
+
// Validates if invalid image name is given a bad response is encountered.
- err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName)
+ err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Validates if the image is tagged successfully.
- err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName)
+ err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName, nil)
Expect(err).To(BeNil())
// Validates if name updates when the image is retagged.
@@ -157,7 +153,7 @@ var _ = Describe("Podman images", func() {
// Test to validate the List images command.
It("List image", func() {
// Array to hold the list of images returned
- imageSummary, err := images.List(bt.conn, nil, nil)
+ imageSummary, err := images.List(bt.conn, nil)
// There Should be no errors in the response.
Expect(err).To(BeNil())
// Since in the begin context two images are created the
@@ -167,7 +163,7 @@ var _ = Describe("Podman images", func() {
// Adding one more image. There Should be no errors in the response.
// And the count should be three now.
bt.Pull("testimage:20200929")
- imageSummary, err = images.List(bt.conn, nil, nil)
+ imageSummary, err = images.List(bt.conn, nil)
Expect(err).To(BeNil())
Expect(len(imageSummary)).To(Equal(3))
@@ -182,13 +178,15 @@ var _ = Describe("Podman images", func() {
// List images with a filter
filters := make(map[string][]string)
filters["reference"] = []string{alpine.name}
- filteredImages, err := images.List(bt.conn, bindings.PFalse, filters)
+ options := new(images.ListOptions).WithFilters(filters).WithAll(false)
+ filteredImages, err := images.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredImages)).To(BeNumerically("==", 1))
// List images with a bad filter
filters["name"] = []string{alpine.name}
- _, err = images.List(bt.conn, bindings.PFalse, filters)
+ options = new(images.ListOptions).WithFilters(filters)
+ _, err = images.List(bt.conn, options)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -213,8 +211,8 @@ var _ = Describe("Podman images", func() {
It("Load|Import Image", func() {
// load an image
- _, err := images.Remove(bt.conn, alpine.name, false)
- Expect(err).To(BeNil())
+ _, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
+ Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
@@ -231,13 +229,14 @@ var _ = Describe("Podman images", func() {
// load with a repo name
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
Expect(err).To(BeNil())
- _, err = images.Remove(bt.conn, alpine.name, false)
- Expect(err).To(BeNil())
+ _, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
+ Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
newName := "quay.io/newname:fizzle"
- names, err = images.Load(bt.conn, f, &newName)
+ options := new(images.LoadOptions).WithReference(newName)
+ names, err = images.Load(bt.conn, f, options)
Expect(err).To(BeNil())
Expect(names.Names[0]).To(Equal(alpine.name))
exists, err = images.Exists(bt.conn, newName)
@@ -247,13 +246,13 @@ var _ = Describe("Podman images", func() {
// load with a bad repo name should trigger a 500
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
Expect(err).To(BeNil())
- _, err = images.Remove(bt.conn, alpine.name, false)
- Expect(err).To(BeNil())
+ _, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
+ Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
- badName := "quay.io/newName:fizzle"
- _, err = images.Load(bt.conn, f, &badName)
+ options = new(images.LoadOptions).WithReference("quay.io/newName:fizzle")
+ _, err = images.Load(bt.conn, f, options)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -265,7 +264,7 @@ var _ = Describe("Podman images", func() {
w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName))
defer w.Close()
Expect(err).To(BeNil())
- err = images.Export(bt.conn, alpine.name, w, nil, nil)
+ err = images.Export(bt.conn, []string{alpine.name}, w, nil)
Expect(err).To(BeNil())
_, err = os.Stat(exportPath)
Expect(err).To(BeNil())
@@ -275,8 +274,8 @@ var _ = Describe("Podman images", func() {
It("Import Image", func() {
// load an image
- _, err = images.Remove(bt.conn, alpine.name, false)
- Expect(err).To(BeNil())
+ _, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
+ Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
@@ -285,7 +284,8 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil())
changes := []string{"CMD /bin/foobar"}
testMessage := "test_import"
- _, err = images.Import(bt.conn, changes, &testMessage, &alpine.name, nil, f)
+ options := new(images.ImportOptions).WithMessage(testMessage).WithChanges(changes).WithReference(alpine.name)
+ _, err = images.Import(bt.conn, f, options)
Expect(err).To(BeNil())
exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil())
@@ -298,7 +298,7 @@ var _ = Describe("Podman images", func() {
It("History Image", func() {
// a bogus name should return a 404
- _, err := images.History(bt.conn, "foobar")
+ _, err := images.History(bt.conn, "foobar", nil)
Expect(err).To(Not(BeNil()))
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -306,7 +306,7 @@ var _ = Describe("Podman images", func() {
var foundID bool
data, err := images.GetImage(bt.conn, alpine.name, nil)
Expect(err).To(BeNil())
- history, err := images.History(bt.conn, alpine.name)
+ history, err := images.History(bt.conn, alpine.name, nil)
Expect(err).To(BeNil())
for _, i := range history {
if i.ID == data.ID {
@@ -318,7 +318,7 @@ var _ = Describe("Podman images", func() {
})
It("Search for an image", func() {
- reports, err := images.Search(bt.conn, "alpine", entities.ImageSearchOptions{})
+ reports, err := images.Search(bt.conn, "alpine", nil)
Expect(err).To(BeNil())
Expect(len(reports)).To(BeNumerically(">", 1))
var foundAlpine bool
@@ -331,35 +331,39 @@ var _ = Describe("Podman images", func() {
Expect(foundAlpine).To(BeTrue())
// Search for alpine with a limit of 10
- reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Limit: 10})
+ options := new(images.SearchOptions).WithLimit(10)
+ reports, err = images.Search(bt.conn, "docker.io/alpine", options)
Expect(err).To(BeNil())
Expect(len(reports)).To(BeNumerically("<=", 10))
+ filters := make(map[string][]string)
+ filters["stars"] = []string{"100"}
// Search for alpine with stars greater than 100
- reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Filters: []string{"stars=100"}})
+ options = new(images.SearchOptions).WithFilters(filters)
+ reports, err = images.Search(bt.conn, "docker.io/alpine", options)
Expect(err).To(BeNil())
for _, i := range reports {
Expect(i.Stars).To(BeNumerically(">=", 100))
}
// Search with a fqdn
- reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", entities.ImageSearchOptions{})
+ reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", nil)
Expect(len(reports)).To(BeNumerically(">=", 1))
})
It("Prune images", func() {
- trueBoxed := true
- results, err := images.Prune(bt.conn, &trueBoxed, nil)
+ options := new(images.PruneOptions).WithAll(true)
+ results, err := images.Prune(bt.conn, options)
Expect(err).NotTo(HaveOccurred())
Expect(len(results)).To(BeNumerically(">", 0))
- Expect(results).To(ContainElement("docker.io/library/alpine:latest"))
+ 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.
It("Image Pull", func() {
rawImage := "docker.io/library/busybox:latest"
- pulledImages, err := images.Pull(bt.conn, rawImage, entities.ImagePullOptions{})
+ pulledImages, err := images.Pull(bt.conn, rawImage, nil)
Expect(err).NotTo(HaveOccurred())
Expect(len(pulledImages)).To(Equal(1))
@@ -368,11 +372,11 @@ var _ = Describe("Podman images", func() {
Expect(exists).To(BeTrue())
// Make sure the normalization AND the full-transport reference works.
- _, err = images.Pull(bt.conn, "docker://"+rawImage, entities.ImagePullOptions{})
+ _, err = images.Pull(bt.conn, "docker://"+rawImage, nil)
Expect(err).NotTo(HaveOccurred())
// The v2 endpoint only supports the docker transport. Let's see if that's really true.
- _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", entities.ImagePullOptions{})
+ _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", nil)
Expect(err).To(HaveOccurred())
})
})
diff --git a/pkg/bindings/test/info_test.go b/pkg/bindings/test/info_test.go
index 6cd5d6724..4d696b59e 100644
--- a/pkg/bindings/test/info_test.go
+++ b/pkg/bindings/test/info_test.go
@@ -17,7 +17,6 @@ var _ = Describe("Podman info", func() {
var (
bt *bindingTest
s *gexec.Session
- t bool = true
)
BeforeEach(func() {
@@ -35,23 +34,24 @@ var _ = Describe("Podman info", func() {
})
It("podman info", func() {
- info, err := system.Info(bt.conn)
+ info, err := system.Info(bt.conn, nil)
Expect(err).To(BeNil())
Expect(info.Host.Arch).To(Equal(runtime.GOARCH))
Expect(info.Host.OS).To(Equal(runtime.GOOS))
- i, err := images.List(bt.conn, &t, nil)
+ listOptions := new(images.ListOptions)
+ i, err := images.List(bt.conn, listOptions.WithAll(true))
Expect(err).To(BeNil())
Expect(info.Store.ImageStore.Number).To(Equal(len(i)))
})
It("podman info container counts", func() {
s := specgen.NewSpecGenerator(alpine.name, false)
- _, err := containers.CreateWithSpec(bt.conn, s)
+ _, err := containers.CreateWithSpec(bt.conn, s, nil)
Expect(err).To(BeNil())
idPause, err := bt.RunTopContainer(nil, nil, nil)
Expect(err).To(BeNil())
- err = containers.Pause(bt.conn, idPause)
+ err = containers.Pause(bt.conn, idPause, nil)
Expect(err).To(BeNil())
idStop, err := bt.RunTopContainer(nil, nil, nil)
@@ -62,7 +62,7 @@ var _ = Describe("Podman info", func() {
_, err = bt.RunTopContainer(nil, nil, nil)
Expect(err).To(BeNil())
- info, err := system.Info(bt.conn)
+ info, err := system.Info(bt.conn, nil)
Expect(err).To(BeNil())
Expect(info.Store.ContainerStore.Number).To(BeNumerically("==", 4))
diff --git a/pkg/bindings/test/manifests_test.go b/pkg/bindings/test/manifests_test.go
index 55fc4cb0d..b93f64b4b 100644
--- a/pkg/bindings/test/manifests_test.go
+++ b/pkg/bindings/test/manifests_test.go
@@ -4,7 +4,6 @@ import (
"net/http"
"time"
- "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/images"
"github.com/containers/podman/v2/pkg/bindings/manifests"
@@ -37,7 +36,7 @@ var _ = Describe("Podman containers ", func() {
// create manifest list without images
id, err := manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{}, nil)
Expect(err).To(BeNil())
- list, err := manifests.Inspect(bt.conn, id)
+ list, err := manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(list.Manifests)).To(BeZero())
@@ -47,19 +46,19 @@ var _ = Describe("Podman containers ", func() {
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
- _, err = images.Remove(bt.conn, id, false)
- Expect(err).To(BeNil())
+ _, errs := images.Remove(bt.conn, []string{id}, nil)
+ Expect(len(errs)).To(BeZero())
// create manifest list with images
id, err = manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{alpine.name}, nil)
Expect(err).To(BeNil())
- list, err = manifests.Inspect(bt.conn, id)
+ list, err = manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(list.Manifests)).To(BeNumerically("==", 1))
})
It("inspect bogus manifest", func() {
- _, err := manifests.Inspect(bt.conn, "larry")
+ _, err := manifests.Inspect(bt.conn, "larry", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -67,23 +66,23 @@ var _ = Describe("Podman containers ", func() {
It("add manifest", func() {
// add to bogus should 404
- _, err := manifests.Add(bt.conn, "foobar", image.ManifestAddOpts{})
+ _, err := manifests.Add(bt.conn, "foobar", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
id, err := manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{}, nil)
Expect(err).To(BeNil())
- opts := image.ManifestAddOpts{Images: []string{alpine.name}}
- _, err = manifests.Add(bt.conn, id, opts)
+ options := new(manifests.AddOptions).WithImages([]string{alpine.name})
+ _, err = manifests.Add(bt.conn, id, options)
Expect(err).To(BeNil())
- list, err := manifests.Inspect(bt.conn, id)
+ list, err := manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(list.Manifests)).To(BeNumerically("==", 1))
// add bogus name to existing list should fail
- opts.Images = []string{"larry"}
- _, err = manifests.Add(bt.conn, id, opts)
+ options.WithImages([]string{"larry"})
+ _, err = manifests.Add(bt.conn, id, options)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -91,29 +90,29 @@ var _ = Describe("Podman containers ", func() {
It("remove manifest", func() {
// removal on bogus manifest list should be 404
- _, err := manifests.Remove(bt.conn, "larry", "1234")
+ _, err := manifests.Remove(bt.conn, "larry", "1234", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
id, err := manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{alpine.name}, nil)
Expect(err).To(BeNil())
- data, err := manifests.Inspect(bt.conn, id)
+ data, err := manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(data.Manifests)).To(BeNumerically("==", 1))
// removal on a good manifest list with a bad digest should be 400
- _, err = manifests.Remove(bt.conn, id, "!234")
+ _, err = manifests.Remove(bt.conn, id, "!234", nil)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusBadRequest))
digest := data.Manifests[0].Digest.String()
- _, err = manifests.Remove(bt.conn, id, digest)
+ _, err = manifests.Remove(bt.conn, id, digest, nil)
Expect(err).To(BeNil())
// removal on good manifest with good digest should work
- data, err = manifests.Inspect(bt.conn, id)
+ data, err = manifests.Inspect(bt.conn, id, nil)
Expect(err).To(BeNil())
Expect(len(data.Manifests)).To(BeZero())
})
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
index 8498de020..38c5997ef 100644
--- a/pkg/bindings/test/pods_test.go
+++ b/pkg/bindings/test/pods_test.go
@@ -40,13 +40,13 @@ var _ = Describe("Podman pods", func() {
It("inspect pod", func() {
//Inspect an invalid pod name
- _, err := pods.Inspect(bt.conn, "dummyname")
+ _, err := pods.Inspect(bt.conn, "dummyname", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
//Inspect an valid pod name
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.Name).To(Equal(newpod))
})
@@ -59,7 +59,7 @@ var _ = Describe("Podman pods", func() {
Expect(len(podSummary)).To(Equal(1))
// Start the pod
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
// Adding an alpine container to the existing pod
@@ -90,7 +90,7 @@ var _ = Describe("Podman pods", func() {
bt.Podcreate(&newpod2)
// Start the pod
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
_, err = bt.RunTopContainer(nil, bindings.PTrue, &newpod)
@@ -99,7 +99,8 @@ var _ = Describe("Podman pods", func() {
// Expected err with invalid filter params
filters := make(map[string][]string)
filters["dummy"] = []string{"dummy"}
- filteredPods, err := pods.List(bt.conn, filters)
+ options := new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err := pods.List(bt.conn, options)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -107,14 +108,16 @@ var _ = Describe("Podman pods", func() {
// Expected empty response with invalid filters
filters = make(map[string][]string)
filters["name"] = []string{"dummy"}
- filteredPods, err = pods.List(bt.conn, filters)
+ options = new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err = pods.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredPods)).To(BeNumerically("==", 0))
// Validate list pod with name filter
filters = make(map[string][]string)
filters["name"] = []string{newpod2}
- filteredPods, err = pods.List(bt.conn, filters)
+ options = new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err = pods.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredPods)).To(BeNumerically("==", 1))
var names []string
@@ -125,11 +128,12 @@ var _ = Describe("Podman pods", func() {
// Validate list pod with id filter
filters = make(map[string][]string)
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
id := response.ID
filters["id"] = []string{id}
- filteredPods, err = pods.List(bt.conn, filters)
+ options = new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err = pods.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredPods)).To(BeNumerically("==", 1))
names = names[:0]
@@ -140,7 +144,8 @@ var _ = Describe("Podman pods", func() {
// Using multiple filters
filters["name"] = []string{newpod}
- filteredPods, err = pods.List(bt.conn, filters)
+ options = new(pods.ListOptions).WithFilters(filters)
+ filteredPods, err = pods.List(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(filteredPods)).To(BeNumerically("==", 1))
names = names[:0]
@@ -164,11 +169,11 @@ var _ = Describe("Podman pods", func() {
// This test validates if All running containers within
// each specified pod are paused and unpaused
- It("pause upause pod", func() {
+ It("pause unpause pod", func() {
// TODO fix this
Skip("Pod behavior is jacked right now.")
// Pause invalid container
- _, err := pods.Pause(bt.conn, "dummyName")
+ _, err := pods.Pause(bt.conn, "dummyName", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -180,9 +185,9 @@ var _ = Describe("Podman pods", func() {
// Binding needs to be modified to inspect the pod state.
// Since we don't have a pod state we inspect the states of the containers within the pod.
// Pause a valid container
- _, err = pods.Pause(bt.conn, newpod)
+ _, err = pods.Pause(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStatePaused))
for _, i := range response.Containers {
@@ -191,9 +196,9 @@ var _ = Describe("Podman pods", func() {
}
// Unpause a valid container
- _, err = pods.Unpause(bt.conn, newpod)
+ _, err = pods.Unpause(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err = pods.Inspect(bt.conn, newpod)
+ response, err = pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
@@ -204,7 +209,7 @@ var _ = Describe("Podman pods", func() {
It("start stop restart pod", func() {
// Start an invalid pod
- _, err = pods.Start(bt.conn, "dummyName")
+ _, err = pods.Start(bt.conn, "dummyName", nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -216,16 +221,16 @@ var _ = Describe("Podman pods", func() {
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Restart an invalid pod
- _, err = pods.Restart(bt.conn, "dummyName")
+ _, err = pods.Restart(bt.conn, "dummyName", nil)
Expect(err).ToNot(BeNil())
code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Start a valid pod and inspect status of each container
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
@@ -234,13 +239,13 @@ var _ = Describe("Podman pods", func() {
}
// Start an already running pod
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
// Stop the running pods
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, _ = pods.Inspect(bt.conn, newpod)
+ response, _ = pods.Inspect(bt.conn, newpod, nil)
Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
@@ -251,9 +256,9 @@ var _ = Describe("Podman pods", func() {
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- _, err = pods.Restart(bt.conn, newpod)
+ _, err = pods.Restart(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, _ = pods.Inspect(bt.conn, newpod)
+ response, _ = pods.Inspect(bt.conn, newpod, nil)
Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
@@ -267,7 +272,7 @@ var _ = Describe("Podman pods", func() {
var newpod2 string = "newpod2"
bt.Podcreate(&newpod2)
// No pods pruned since no pod in exited state
- pruneResponse, err := pods.Prune(bt.conn)
+ pruneResponse, err := pods.Prune(bt.conn, nil)
Expect(err).To(BeNil())
podSummary, err := pods.List(bt.conn, nil)
Expect(err).To(BeNil())
@@ -276,14 +281,14 @@ var _ = Describe("Podman pods", func() {
// Prune only one pod which is in exited state.
// Start then stop a pod.
// pod moves to exited state one pod should be pruned now.
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err := pods.Inspect(bt.conn, newpod)
+ response, err := pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateExited))
- pruneResponse, err = pods.Prune(bt.conn)
+ pruneResponse, err = pods.Prune(bt.conn, nil)
Expect(err).To(BeNil())
// Validate status and record pod id of pod to be pruned
Expect(response.State).To(Equal(define.PodStateExited))
@@ -298,13 +303,13 @@ var _ = Describe("Podman pods", func() {
// Test prune multiple pods.
bt.Podcreate(&newpod)
- _, err = pods.Start(bt.conn, newpod)
+ _, err = pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- _, err = pods.Start(bt.conn, newpod2)
+ _, err = pods.Start(bt.conn, newpod2, nil)
Expect(err).To(BeNil())
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
- response, err = pods.Inspect(bt.conn, newpod)
+ response, err = pods.Inspect(bt.conn, newpod, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
@@ -313,14 +318,14 @@ var _ = Describe("Podman pods", func() {
}
_, err = pods.Stop(bt.conn, newpod2, nil)
Expect(err).To(BeNil())
- response, err = pods.Inspect(bt.conn, newpod2)
+ response, err = pods.Inspect(bt.conn, newpod2, nil)
Expect(err).To(BeNil())
Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStateExited))
}
- _, err = pods.Prune(bt.conn)
+ _, err = pods.Prune(bt.conn, nil)
Expect(err).To(BeNil())
podSummary, err = pods.List(bt.conn, nil)
Expect(err).To(BeNil())
@@ -330,7 +335,7 @@ var _ = Describe("Podman pods", func() {
It("simple create pod", func() {
ps := specgen.PodSpecGenerator{}
ps.Name = "foobar"
- _, err := pods.CreatePodFromSpec(bt.conn, &ps)
+ _, err := pods.CreatePodFromSpec(bt.conn, &ps, nil)
Expect(err).To(BeNil())
exists, err := pods.Exists(bt.conn, "foobar")
@@ -343,7 +348,7 @@ var _ = Describe("Podman pods", func() {
var name string = "podA"
bt.Podcreate(&name)
- _, err := pods.Start(bt.conn, name)
+ _, err := pods.Start(bt.conn, name, nil)
Expect(err).To(BeNil())
// By name
@@ -351,7 +356,8 @@ var _ = Describe("Podman pods", func() {
Expect(err).To(BeNil())
// With descriptors
- output, err := pods.Top(bt.conn, name, []string{"user,pid,hpid"})
+ options := new(pods.TopOptions).WithDescriptors([]string{"user,pid,hpid"})
+ output, err := pods.Top(bt.conn, name, options)
Expect(err).To(BeNil())
header := strings.Split(output[0], "\t")
for _, d := range []string{"USER", "PID", "HPID"} {
@@ -363,7 +369,8 @@ var _ = Describe("Podman pods", func() {
Expect(err).ToNot(BeNil())
// With bogus descriptors
- _, err = pods.Top(bt.conn, name, []string{"Me,Neither"})
+ options = new(pods.TopOptions).WithDescriptors([]string{"Me,Neither"})
+ _, err = pods.Top(bt.conn, name, options)
Expect(err).ToNot(BeNil())
})
})
diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go
index 82e5c7541..44067b61d 100644
--- a/pkg/bindings/test/system_test.go
+++ b/pkg/bindings/test/system_test.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/system"
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -56,8 +57,8 @@ var _ = Describe("Podman system", func() {
eventCounter++
}
}()
-
- err = system.Events(bt.conn, binChan, nil, nil, nil, filters, bindings.PFalse)
+ options := new(system.EventsOptions).WithFilters(filters).WithStream(false)
+ err = system.Events(bt.conn, binChan, nil, options)
Expect(err).To(BeNil())
done.Lock()
Expect(eventCounter).To(BeNumerically(">", 0))
@@ -65,7 +66,7 @@ var _ = Describe("Podman system", func() {
It("podman system prune - pod,container stopped", func() {
// Start and stop a pod to enter in exited state.
- _, err := pods.Start(bt.conn, newpod)
+ _, err := pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
@@ -76,20 +77,21 @@ var _ = Describe("Podman system", func() {
err = containers.Stop(bt.conn, name, nil)
Expect(err).To(BeNil())
- systemPruneResponse, err := system.Prune(bt.conn, bindings.PTrue, bindings.PFalse)
+ options := new(system.PruneOptions).WithAll(true)
+ systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
To(ContainElement("docker.io/library/alpine:latest"))
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
})
It("podman system prune running alpine container", func() {
// Start and stop a pod to enter in exited state.
- _, err := pods.Start(bt.conn, newpod)
+ _, err := pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
@@ -107,25 +109,25 @@ var _ = Describe("Podman system", func() {
Expect(err).To(BeNil())
// Adding an unused volume
- _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{})
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
-
- systemPruneResponse, err := system.Prune(bt.conn, bindings.PTrue, bindings.PFalse)
+ options := new(system.PruneOptions).WithAll(true)
+ systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
// Alpine image should not be pruned as used by running container
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
ToNot(ContainElement("docker.io/library/alpine:latest"))
// Though unused volume is available it should not be pruned as flag set to false.
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
})
It("podman system prune running alpine container volume prune", func() {
// Start a pod and leave it running
- _, err := pods.Start(bt.conn, newpod)
+ _, err := pods.Start(bt.conn, newpod, nil)
Expect(err).To(BeNil())
// Start and stop a container to enter in exited state.
@@ -141,19 +143,77 @@ var _ = Describe("Podman system", func() {
Expect(err).To(BeNil())
// Adding an unused volume should work
- _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{})
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
- systemPruneResponse, err := system.Prune(bt.conn, bindings.PTrue, bindings.PTrue)
+ options := new(system.PruneOptions).WithAll(true).WithVolumes(true)
+ systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
// Alpine image should not be pruned as used by running container
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
ToNot(ContainElement("docker.io/library/alpine:latest"))
// Volume should be pruned now as flag set true
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1))
+ })
+
+ It("podman system prune running alpine container volume prune --filter", func() {
+ // Start a pod and leave it running
+ _, err := pods.Start(bt.conn, newpod, nil)
+ Expect(err).To(BeNil())
+
+ // Start and stop a container to enter in exited state.
+ var name = "top"
+ _, err = bt.RunTopContainer(&name, bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+ err = containers.Stop(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+
+ // Start second container and leave in running
+ var name2 = "top2"
+ _, err = bt.RunTopContainer(&name2, bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+
+ // Adding an unused volume should work
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{}, nil)
+ Expect(err).To(BeNil())
+
+ // Adding an unused volume with label should work
+ _, err = volumes.Create(bt.conn, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value1",
+ }}, nil)
+ Expect(err).To(BeNil())
+
+ f := make(map[string][]string)
+ f["label"] = []string{"label1=idontmatch"}
+
+ options := new(system.PruneOptions).WithAll(true).WithVolumes(true).WithFilters(f)
+ 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))
+ // Alpine image should not be pruned as used by running container
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
+ ToNot(ContainElement("docker.io/library/alpine:latest"))
+ // Volume shouldn't be pruned because the PruneOptions filters doesn't match
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
+
+ // Fix filter and re prune
+ f["label"] = []string{"label1=value1"}
+ options = new(system.PruneOptions).WithAll(true).WithVolumes(true).WithFilters(f)
+ systemPruneResponse, err = system.Prune(bt.conn, options)
+ Expect(err).To(BeNil())
+
+ // Volume should be pruned because the PruneOptions filters now match
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1))
})
})
diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go
index dc90d4d00..1f1da3cfa 100644
--- a/pkg/bindings/test/volumes_test.go
+++ b/pkg/bindings/test/volumes_test.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -52,7 +53,7 @@ var _ = Describe("Podman volumes", func() {
It("create volume", func() {
// create a volume with blank config should work
- _, err := volumes.Create(connText, entities.VolumeCreateOptions{})
+ _, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
vcc := entities.VolumeCreateOptions{
@@ -60,21 +61,21 @@ var _ = Describe("Podman volumes", func() {
Label: nil,
Options: nil,
}
- vol, err := volumes.Create(connText, vcc)
+ vol, err := volumes.Create(connText, vcc, nil)
Expect(err).To(BeNil())
Expect(vol.Name).To(Equal("foobar"))
// create volume with same name should 500
- _, err = volumes.Create(connText, vcc)
+ _, err = volumes.Create(connText, vcc, nil)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
})
It("inspect volume", func() {
- vol, err := volumes.Create(connText, entities.VolumeCreateOptions{})
+ vol, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
- data, err := volumes.Inspect(connText, vol.Name)
+ data, err := volumes.Inspect(connText, vol.Name, nil)
Expect(err).To(BeNil())
Expect(data.Name).To(Equal(vol.Name))
})
@@ -86,13 +87,13 @@ var _ = Describe("Podman volumes", func() {
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Removing an unused volume should work
- vol, err := volumes.Create(connText, entities.VolumeCreateOptions{})
+ vol, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
err = volumes.Remove(connText, vol.Name, nil)
Expect(err).To(BeNil())
// Removing a volume that is being used without force should be 409
- vol, err = volumes.Create(connText, entities.VolumeCreateOptions{})
+ vol, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
session := bt.runPodman([]string{"run", "-dt", "-v", fmt.Sprintf("%s:/foobar", vol.Name), "--name", "vtest", alpine.name, "top"})
session.Wait(45)
@@ -102,10 +103,10 @@ var _ = Describe("Podman volumes", func() {
Expect(code).To(BeNumerically("==", http.StatusConflict))
// Removing with a volume in use with force should work with a stopped container
- zero := uint(0)
- err = containers.Stop(connText, "vtest", &zero)
+ err = containers.Stop(connText, "vtest", new(containers.StopOptions).WithTimeout(0))
Expect(err).To(BeNil())
- err = volumes.Remove(connText, vol.Name, bindings.PTrue)
+ options := new(volumes.RemoveOptions).WithForce(true)
+ err = volumes.Remove(connText, vol.Name, options)
Expect(err).To(BeNil())
})
@@ -118,7 +119,7 @@ var _ = Describe("Podman volumes", func() {
// create a bunch of named volumes and make verify with list
volNames := []string{"homer", "bart", "lisa", "maggie", "marge"}
for i := 0; i < 5; i++ {
- _, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: volNames[i]})
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: volNames[i]}, nil)
Expect(err).To(BeNil())
}
vols, err = volumes.List(connText, nil)
@@ -131,43 +132,81 @@ var _ = Describe("Podman volumes", func() {
// list with bad filter should be 500
filters := make(map[string][]string)
filters["foobar"] = []string{"1234"}
- _, err = volumes.List(connText, filters)
+ options := new(volumes.ListOptions).WithFilters(filters)
+ _, err = volumes.List(connText, options)
Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
filters = make(map[string][]string)
filters["name"] = []string{"homer"}
- vols, err = volumes.List(connText, filters)
+ options = new(volumes.ListOptions).WithFilters(filters)
+ vols, err = volumes.List(connText, options)
Expect(err).To(BeNil())
Expect(len(vols)).To(BeNumerically("==", 1))
Expect(vols[0].Name).To(Equal("homer"))
})
- // TODO we need to add filtering to tests
It("prune unused volume", func() {
// Pruning when no volumes present should be ok
- _, err := volumes.Prune(connText)
+ _, err := volumes.Prune(connText, nil)
Expect(err).To(BeNil())
// Removing an unused volume should work
- _, err = volumes.Create(connText, entities.VolumeCreateOptions{})
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
- vols, err := volumes.Prune(connText)
+ vols, err := volumes.Prune(connText, nil)
Expect(err).To(BeNil())
Expect(len(vols)).To(BeNumerically("==", 1))
- _, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: "homer"})
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: "homer"}, nil)
Expect(err).To(BeNil())
- _, err = volumes.Create(connText, entities.VolumeCreateOptions{})
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
Expect(err).To(BeNil())
session := bt.runPodman([]string{"run", "-dt", "-v", fmt.Sprintf("%s:/homer", "homer"), "--name", "vtest", alpine.name, "top"})
session.Wait(45)
- vols, err = volumes.Prune(connText)
+ vols, err = volumes.Prune(connText, nil)
+ Expect(err).To(BeNil())
+ Expect(len(reports.PruneReportsIds(vols))).To(BeNumerically("==", 1))
+ _, err = volumes.Inspect(connText, "homer", nil)
+ Expect(err).To(BeNil())
+
+ // Removing volume with non matching filter shouldn't prune any volumes
+ filters := make(map[string][]string)
+ filters["label"] = []string{"label1=idontmatch"}
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value1",
+ }}, nil)
+ Expect(err).To(BeNil())
+ options := new(volumes.PruneOptions).WithFilters(filters)
+ vols, err = volumes.Prune(connText, options)
+ Expect(err).To(BeNil())
+ Expect(len(vols)).To(BeNumerically("==", 0))
+ vol2, err := volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value2",
+ }}, nil)
+ Expect(err).To(BeNil())
+ _, err = volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
+ "label1": "value3",
+ }}, nil)
+ Expect(err).To(BeNil())
+
+ // Removing volume with matching filter label and value should remove specific entry
+ filters = make(map[string][]string)
+ filters["label"] = []string{"label1=value2"}
+ options = new(volumes.PruneOptions).WithFilters(filters)
+ vols, err = volumes.Prune(connText, options)
Expect(err).To(BeNil())
Expect(len(vols)).To(BeNumerically("==", 1))
- _, err = volumes.Inspect(connText, "homer")
+ Expect(vols[0].Id).To(Equal(vol2.Name))
+
+ // Removing volumes with matching filter label should remove all matching volumes
+ filters = make(map[string][]string)
+ filters["label"] = []string{"label1"}
+ options = new(volumes.PruneOptions).WithFilters(filters)
+ vols, err = volumes.Prune(connText, options)
Expect(err).To(BeNil())
+ Expect(len(vols)).To(BeNumerically("==", 2))
})
})
diff --git a/pkg/bindings/volumes/types.go b/pkg/bindings/volumes/types.go
new file mode 100644
index 000000000..379174e33
--- /dev/null
+++ b/pkg/bindings/volumes/types.go
@@ -0,0 +1,32 @@
+package volumes
+
+//go:generate go run ../generator/generator.go CreateOptions
+// CreateOptions are optional options for creating volumes
+type CreateOptions struct {
+}
+
+//go:generate go run ../generator/generator.go InspectOptions
+// InspectOptions are optional options for inspecting volumes
+type InspectOptions struct {
+}
+
+//go:generate go run ../generator/generator.go ListOptions
+// ListOptions are optional options for listing volumes
+type ListOptions struct {
+ // Filters applied to the listing of volumes
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go PruneOptions
+// PruneOptions are optional options for pruning volumes
+type PruneOptions struct {
+ // Filters applied to the pruning of volumes
+ Filters map[string][]string
+}
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for removing volumes
+type RemoveOptions struct {
+ // Force removes the volume even if it is being used
+ Force *bool
+}
diff --git a/pkg/bindings/volumes/types_create_options.go b/pkg/bindings/volumes/types_create_options.go
new file mode 100644
index 000000000..80bdac2d2
--- /dev/null
+++ b/pkg/bindings/volumes/types_create_options.go
@@ -0,0 +1,88 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.043860791 -0600 CST m=+0.000188944
+*/
+
+// Changed
+func (o *CreateOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *CreateOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/volumes/types_inspect_options.go b/pkg/bindings/volumes/types_inspect_options.go
new file mode 100644
index 000000000..ba8c70b63
--- /dev/null
+++ b/pkg/bindings/volumes/types_inspect_options.go
@@ -0,0 +1,88 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.189902005 -0600 CST m=+0.000151439
+*/
+
+// Changed
+func (o *InspectOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *InspectOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
diff --git a/pkg/bindings/volumes/types_list_options.go b/pkg/bindings/volumes/types_list_options.go
new file mode 100644
index 000000000..99dec132c
--- /dev/null
+++ b/pkg/bindings/volumes/types_list_options.go
@@ -0,0 +1,104 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.326721724 -0600 CST m=+0.000172471
+*/
+
+// Changed
+func (o *ListOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *ListOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *ListOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/volumes/types_prune_options.go b/pkg/bindings/volumes/types_prune_options.go
new file mode 100644
index 000000000..cdbc03fc9
--- /dev/null
+++ b/pkg/bindings/volumes/types_prune_options.go
@@ -0,0 +1,104 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.463307398 -0600 CST m=+0.000180868
+*/
+
+// Changed
+func (o *PruneOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *PruneOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithFilters
+func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions {
+ v := value
+ o.Filters = v
+ return o
+}
+
+// GetFilters
+func (o *PruneOptions) GetFilters() map[string][]string {
+ var filters map[string][]string
+ if o.Filters == nil {
+ return filters
+ }
+ return o.Filters
+}
diff --git a/pkg/bindings/volumes/types_remove_options.go b/pkg/bindings/volumes/types_remove_options.go
new file mode 100644
index 000000000..923d1353c
--- /dev/null
+++ b/pkg/bindings/volumes/types_remove_options.go
@@ -0,0 +1,104 @@
+package volumes
+
+import (
+ "net/url"
+ "reflect"
+ "strconv"
+
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate. Do not edit.
+
+Created 2020-12-18 15:58:14.60278922 -0600 CST m=+0.000134408
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+ r := reflect.ValueOf(o)
+ value := reflect.Indirect(r).FieldByName(fieldName)
+ return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+ params := url.Values{}
+ if o == nil {
+ return params, nil
+ }
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ s := reflect.ValueOf(o)
+ if reflect.Ptr == s.Kind() {
+ s = s.Elem()
+ }
+ sType := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ fieldName := sType.Field(i).Name
+ if !o.Changed(fieldName) {
+ continue
+ }
+ f := s.Field(i)
+ if reflect.Ptr == f.Kind() {
+ f = f.Elem()
+ }
+ switch f.Kind() {
+ case reflect.Bool:
+ params.Set(fieldName, strconv.FormatBool(f.Bool()))
+ case reflect.String:
+ params.Set(fieldName, f.String())
+ case reflect.Int, reflect.Int64:
+ // f.Int() is always an int64
+ params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+ case reflect.Uint, reflect.Uint64:
+ // f.Uint() is always an uint64
+ params.Set(fieldName, strconv.FormatUint(f.Uint(), 10))
+ case reflect.Slice:
+ typ := reflect.TypeOf(f.Interface()).Elem()
+ switch typ.Kind() {
+ case reflect.String:
+ sl := f.Slice(0, f.Len())
+ s, ok := sl.Interface().([]string)
+ if !ok {
+ return nil, errors.New("failed to convert to string slice")
+ }
+ for _, val := range s {
+ params.Add(fieldName, val)
+ }
+ default:
+ return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+ }
+ case reflect.Map:
+ lowerCaseKeys := make(map[string][]string)
+ iter := f.MapRange()
+ for iter.Next() {
+ lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
+
+ }
+ s, err := json.MarshalToString(lowerCaseKeys)
+ if err != nil {
+ return nil, err
+ }
+
+ params.Set(fieldName, s)
+ }
+ }
+ return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+ v := &value
+ o.Force = v
+ return o
+}
+
+// GetForce
+func (o *RemoveOptions) GetForce() bool {
+ var force bool
+ if o.Force == nil {
+ return force
+ }
+ return *o.Force
+}
diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go
index 00f1e5720..fe081eb46 100644
--- a/pkg/bindings/volumes/volumes.go
+++ b/pkg/bindings/volumes/volumes.go
@@ -3,20 +3,23 @@ package volumes
import (
"context"
"net/http"
- "net/url"
- "strconv"
"strings"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
jsoniter "github.com/json-iterator/go"
)
// Create creates a volume given its configuration.
-func Create(ctx context.Context, config entities.VolumeCreateOptions) (*entities.VolumeConfigResponse, error) {
+func Create(ctx context.Context, config entities.VolumeCreateOptions, options *CreateOptions) (*entities.VolumeConfigResponse, error) {
var (
v entities.VolumeConfigResponse
)
+ if options == nil {
+ options = new(CreateOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -34,10 +37,14 @@ func Create(ctx context.Context, config entities.VolumeCreateOptions) (*entities
}
// Inspect returns low-level information about a volume.
-func Inspect(ctx context.Context, nameOrID string) (*entities.VolumeConfigResponse, error) {
+func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*entities.VolumeConfigResponse, error) {
var (
inspect entities.VolumeConfigResponse
)
+ if options == nil {
+ options = new(InspectOptions)
+ }
+ _ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -51,7 +58,7 @@ func Inspect(ctx context.Context, nameOrID string) (*entities.VolumeConfigRespon
// List returns the configurations for existing volumes in the form of a slice. Optionally, filters
// can be used to refine the list of volumes.
-func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeListReport, error) {
+func List(ctx context.Context, options *ListOptions) ([]*entities.VolumeListReport, error) {
var (
vols []*entities.VolumeListReport
)
@@ -59,13 +66,9 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeL
if err != nil {
return nil, err
}
- params := url.Values{}
- if len(filters) > 0 {
- strFilters, err := bindings.FiltersToString(filters)
- if err != nil {
- return nil, err
- }
- params.Set("filters", strFilters)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/json", params, nil)
if err != nil {
@@ -75,15 +78,19 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeL
}
// Prune removes unused volumes from the local filesystem.
-func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
var (
- pruned []*entities.VolumePruneReport
+ pruned []*reports.PruneReport
)
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", nil, nil)
+ params, err := options.ToParams()
+ if err != nil {
+ return nil, err
+ }
+ response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", params, nil)
if err != nil {
return nil, err
}
@@ -92,14 +99,14 @@ func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
// Remove deletes the given volume from storage. The optional force parameter
// is used to remove a volume even if it is being used by a container.
-func Remove(ctx context.Context, nameOrID string, force *bool) error {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error {
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- params := url.Values{}
- if force != nil {
- params.Set("force", strconv.FormatBool(*force))
+ params, err := options.ToParams()
+ if err != nil {
+ return err
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/volumes/%s", params, nil, nameOrID)
if err != nil {
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index 0d7ed05b2..c200dd01a 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -22,7 +22,7 @@ import (
var (
// ErrCgroupDeleted means the cgroup was deleted
ErrCgroupDeleted = errors.New("cgroup deleted")
- // ErrCgroupV1Rootless means the cgroup v1 were attempted to be used in rootless environmen
+ // ErrCgroupV1Rootless means the cgroup v1 were attempted to be used in rootless environment
ErrCgroupV1Rootless = errors.New("no support for CGroups V1 in rootless environments")
)
diff --git a/pkg/copy/copy.go b/pkg/copy/copy.go
deleted file mode 100644
index 13893deb2..000000000
--- a/pkg/copy/copy.go
+++ /dev/null
@@ -1,220 +0,0 @@
-package copy
-
-import (
- "io"
- "os"
- "path/filepath"
- "strings"
-
- buildahCopiah "github.com/containers/buildah/copier"
- "github.com/containers/storage/pkg/archive"
- securejoin "github.com/cyphar/filepath-securejoin"
- "github.com/pkg/errors"
-)
-
-// ********************************* NOTE *************************************
-//
-// Most security bugs are caused by attackers playing around with symlinks
-// trying to escape from the container onto the host and/or trick into data
-// corruption on the host. Hence, file operations on containers (including
-// *stat) should always be handled by `github.com/containers/buildah/copier`
-// which makes sure to evaluate files in a chroot'ed environment.
-//
-// Please make sure to add verbose comments when changing code to make the
-// lives of future readers easier.
-//
-// ****************************************************************************
-
-// Copier copies data from a source to a destination CopyItem.
-type Copier struct {
- copyFunc func() error
- cleanUpFuncs []deferFunc
-}
-
-// cleanUp releases resources the Copier may hold open.
-func (c *Copier) cleanUp() {
- for _, f := range c.cleanUpFuncs {
- f()
- }
-}
-
-// Copy data from a source to a destination CopyItem.
-func (c *Copier) Copy() error {
- defer c.cleanUp()
- return c.copyFunc()
-}
-
-// GetCopiers returns a Copier to copy the source item to destination. Use
-// extract to untar the source if it's a tar archive.
-func GetCopier(source *CopyItem, destination *CopyItem, extract bool) (*Copier, error) {
- copier := &Copier{}
-
- // First, do the man-page dance. See podman-cp(1) for details.
- if err := enforceCopyRules(source, destination); err != nil {
- return nil, err
- }
-
- // Destination is a stream (e.g., stdout or an http body).
- if destination.info.IsStream {
- // Source is a stream (e.g., stdin or an http body).
- if source.info.IsStream {
- copier.copyFunc = func() error {
- _, err := io.Copy(destination.writer, source.reader)
- return err
- }
- return copier, nil
- }
- root, glob, err := source.buildahGlobs()
- if err != nil {
- return nil, err
- }
- copier.copyFunc = func() error {
- return buildahCopiah.Get(root, "", source.getOptions(), []string{glob}, destination.writer)
- }
- return copier, nil
- }
-
- // Destination is either a file or a directory.
- if source.info.IsStream {
- copier.copyFunc = func() error {
- return buildahCopiah.Put(destination.root, destination.resolved, source.putOptions(), source.reader)
- }
- return copier, nil
- }
-
- tarOptions := &archive.TarOptions{
- Compression: archive.Uncompressed,
- CopyPass: true,
- }
-
- root := destination.root
- dir := destination.resolved
- if !source.info.IsDir {
- // When copying a file, make sure to rename the
- // destination base path.
- nameMap := make(map[string]string)
- nameMap[filepath.Base(source.resolved)] = filepath.Base(destination.resolved)
- tarOptions.RebaseNames = nameMap
- dir = filepath.Dir(dir)
- }
-
- var tarReader io.ReadCloser
- if extract && archive.IsArchivePath(source.resolved) {
- if !destination.info.IsDir {
- return nil, errors.Errorf("cannot extract archive %q to file %q", source.original, destination.original)
- }
-
- reader, err := os.Open(source.resolved)
- if err != nil {
- return nil, err
- }
- copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { reader.Close() })
-
- // The stream from stdin may be compressed (e.g., via gzip).
- decompressedStream, err := archive.DecompressStream(reader)
- if err != nil {
- return nil, err
- }
-
- copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { decompressedStream.Close() })
- tarReader = decompressedStream
- } else {
- reader, err := archive.TarWithOptions(source.resolved, tarOptions)
- if err != nil {
- return nil, err
- }
- copier.cleanUpFuncs = append(copier.cleanUpFuncs, func() { reader.Close() })
- tarReader = reader
- }
-
- copier.copyFunc = func() error {
- return buildahCopiah.Put(root, dir, source.putOptions(), tarReader)
- }
- return copier, nil
-}
-
-// enforceCopyRules enforces the rules for copying from a source to a
-// destination as mentioned in the podman-cp(1) man page. Please refer to the
-// man page and/or the inline comments for further details. Note that source
-// and destination are passed by reference and the their data may be changed.
-func enforceCopyRules(source, destination *CopyItem) error {
- if source.statError != nil {
- return source.statError
- }
-
- // We can copy everything to a stream.
- if destination.info.IsStream {
- return nil
- }
-
- if source.info.IsStream {
- if !(destination.info.IsDir || destination.info.IsStream) {
- return errors.New("destination must be a directory or stream when copying from a stream")
- }
- return nil
- }
-
- // Source is a *directory*.
- if source.info.IsDir {
- if destination.statError != nil {
- // It's okay if the destination does not exist. We
- // made sure before that it's parent exists, so it
- // would be created while copying.
- if os.IsNotExist(destination.statError) {
- return nil
- }
- // Could be a permission error.
- return destination.statError
- }
-
- // If the destination exists and is not a directory, we have a
- // problem.
- if !destination.info.IsDir {
- return errors.Errorf("cannot copy directory %q to file %q", source.original, destination.original)
- }
-
- // If the destination exists and is a directory, we need to
- // append the source base directory to it. This makes sure
- // that copying "/foo/bar" "/tmp" will copy to "/tmp/bar" (and
- // not "/tmp").
- newDestination, err := securejoin.SecureJoin(destination.resolved, filepath.Base(source.resolved))
- if err != nil {
- return err
- }
- destination.resolved = newDestination
- return nil
- }
-
- // Source is a *file*.
- if destination.statError != nil {
- // It's okay if the destination does not exist, unless it ends
- // with "/".
- if !os.IsNotExist(destination.statError) {
- return destination.statError
- } else if strings.HasSuffix(destination.resolved, "/") {
- // Note: this is practically unreachable code as the
- // existence of parent directories is enforced early
- // on. It's left here as an extra security net.
- return errors.Errorf("destination directory %q must exist (trailing %q)", destination.original, "/")
- }
- // Does not exist and does not end with "/".
- return nil
- }
-
- // If the destination is a file, we're good. We will overwrite the
- // contents while copying.
- if !destination.info.IsDir {
- return nil
- }
-
- // If the destination exists and is a directory, we need to append the
- // source base directory to it. This makes sure that copying
- // "/foo/bar" "/tmp" will copy to "/tmp/bar" (and not "/tmp").
- newDestination, err := securejoin.SecureJoin(destination.resolved, filepath.Base(source.resolved))
- if err != nil {
- return err
- }
-
- destination.resolved = newDestination
- return nil
-}
diff --git a/pkg/copy/fileinfo.go b/pkg/copy/fileinfo.go
index 08b4eb377..ddb9b629c 100644
--- a/pkg/copy/fileinfo.go
+++ b/pkg/copy/fileinfo.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"net/http"
"os"
+ "path/filepath"
"strings"
"time"
@@ -15,6 +16,10 @@ import (
// base64 encoded JSON payload of stating a path in a container.
const XDockerContainerPathStatHeader = "X-Docker-Container-Path-Stat"
+// ENOENT mimics the stdlib's ENOENT and can be used to implement custom logic
+// while preserving the user-visible error message.
+var ENOENT = errors.New("No such file or directory")
+
// FileInfo describes a file or directory and is returned by
// (*CopyItem).Stat().
type FileInfo struct {
@@ -23,7 +28,6 @@ type FileInfo struct {
Mode os.FileMode `json:"mode"`
ModTime time.Time `json:"mtime"`
IsDir bool `json:"isDir"`
- IsStream bool `json:"isStream"`
LinkTarget string `json:"linkTarget"`
}
@@ -54,3 +58,54 @@ func ExtractFileInfoFromHeader(header *http.Header) (*FileInfo, error) {
return &info, nil
}
+
+// ResolveHostPath resolves the specified, possibly relative, path on the host.
+func ResolveHostPath(path string) (*FileInfo, error) {
+ resolvedHostPath, err := filepath.Abs(path)
+ if err != nil {
+ return nil, err
+ }
+ resolvedHostPath = PreserveBasePath(path, resolvedHostPath)
+
+ statInfo, err := os.Stat(resolvedHostPath)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, ENOENT
+ }
+ return nil, err
+ }
+
+ return &FileInfo{
+ Name: statInfo.Name(),
+ Size: statInfo.Size(),
+ Mode: statInfo.Mode(),
+ ModTime: statInfo.ModTime(),
+ IsDir: statInfo.IsDir(),
+ LinkTarget: resolvedHostPath,
+ }, nil
+}
+
+// PreserveBasePath makes sure that the original base path (e.g., "/" or "./")
+// is preserved. The filepath API among tends to clean up a bit too much but
+// we *must* preserve this data by all means.
+func PreserveBasePath(original, resolved string) string {
+ // Handle "/"
+ if strings.HasSuffix(original, "/") {
+ if !strings.HasSuffix(resolved, "/") {
+ resolved += "/"
+ }
+ return resolved
+ }
+
+ // Handle "/."
+ if strings.HasSuffix(original, "/.") {
+ if strings.HasSuffix(resolved, "/") { // could be root!
+ resolved += "."
+ } else if !strings.HasSuffix(resolved, "/.") {
+ resolved += "/."
+ }
+ return resolved
+ }
+
+ return resolved
+}
diff --git a/pkg/copy/item.go b/pkg/copy/item.go
deleted file mode 100644
index df8bf30b9..000000000
--- a/pkg/copy/item.go
+++ /dev/null
@@ -1,588 +0,0 @@
-package copy
-
-import (
- "io"
- "os"
- "path/filepath"
- "strings"
-
- buildahCopiah "github.com/containers/buildah/copier"
- "github.com/containers/buildah/pkg/chrootuser"
- "github.com/containers/buildah/util"
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/cgroups"
- "github.com/containers/podman/v2/pkg/rootless"
- "github.com/containers/storage"
- "github.com/containers/storage/pkg/archive"
- "github.com/containers/storage/pkg/idtools"
- securejoin "github.com/cyphar/filepath-securejoin"
- "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// ********************************* NOTE *************************************
-//
-// Most security bugs are caused by attackers playing around with symlinks
-// trying to escape from the container onto the host and/or trick into data
-// corruption on the host. Hence, file operations on containers (including
-// *stat) should always be handled by `github.com/containers/buildah/copier`
-// which makes sure to evaluate files in a chroot'ed environment.
-//
-// Please make sure to add verbose comments when changing code to make the
-// lives of future readers easier.
-//
-// ****************************************************************************
-
-var (
- _stdin = os.Stdin.Name()
- _stdout = os.Stdout.Name()
-)
-
-// CopyItem is the source or destination of a copy operation. Use the
-// CopyItemFrom* functions to create one for the specific source/destination
-// item.
-type CopyItem struct {
- // The original path provided by the caller. Useful in error messages.
- original string
- // The resolved path on the host or container. Maybe altered at
- // multiple stages when copying.
- resolved string
- // The root for copying data in a chroot'ed environment.
- root string
-
- // IDPair of the resolved path.
- idPair *idtools.IDPair
- // Storage ID mappings.
- idMappings *storage.IDMappingOptions
-
- // Internal FileInfo. We really don't want users to mess with a
- // CopyItem but only plug and play with it.
- info FileInfo
- // Error when creating the upper FileInfo. Some errors are non-fatal,
- // for instance, when a destination *base* path does not exist.
- statError error
-
- writer io.Writer
- reader io.Reader
-
- // Needed to clean up resources (e.g., unmount a container).
- cleanUpFuncs []deferFunc
-}
-
-// deferFunc allows for returning functions that must be deferred at call sites.
-type deferFunc func()
-
-// Stat returns the FileInfo.
-func (item *CopyItem) Stat() (*FileInfo, error) {
- return &item.info, item.statError
-}
-
-// CleanUp releases resources such as the container mounts. It *must* be
-// called even in case of errors.
-func (item *CopyItem) CleanUp() {
- for _, f := range item.cleanUpFuncs {
- f()
- }
-}
-
-// CopyItemForWriter returns a CopyItem for the specified io.WriteCloser. Note
-// that the returned item can only act as a copy destination.
-func CopyItemForWriter(writer io.Writer) (item CopyItem, _ error) {
- item.writer = writer
- item.info.IsStream = true
- return item, nil
-}
-
-// CopyItemForReader returns a CopyItem for the specified io.ReaderCloser. Note
-// that the returned item can only act as a copy source.
-//
-// Note that the specified reader will be auto-decompressed if needed.
-func CopyItemForReader(reader io.Reader) (item CopyItem, _ error) {
- item.info.IsStream = true
- decompressed, err := archive.DecompressStream(reader)
- if err != nil {
- return item, err
- }
- item.reader = decompressed
- item.cleanUpFuncs = append(item.cleanUpFuncs, func() {
- if err := decompressed.Close(); err != nil {
- logrus.Errorf("Error closing decompressed reader of copy item: %v", err)
- }
- })
- return item, nil
-}
-
-// CopyItemForHost creates a CopyItem for the specified host path. It's a
-// destination by default. Use isSource to set it as a destination.
-//
-// Note that callers *must* call (CopyItem).CleanUp(), even in case of errors.
-func CopyItemForHost(hostPath string, isSource bool) (item CopyItem, _ error) {
- if hostPath == "-" {
- if isSource {
- hostPath = _stdin
- } else {
- hostPath = _stdout
- }
- }
-
- if hostPath == _stdin {
- return CopyItemForReader(os.Stdin)
- }
-
- if hostPath == _stdout {
- return CopyItemForWriter(os.Stdout)
- }
-
- // Now do the dance for the host data.
- resolvedHostPath, err := filepath.Abs(hostPath)
- if err != nil {
- return item, err
- }
-
- resolvedHostPath = preserveBasePath(hostPath, resolvedHostPath)
- item.original = hostPath
- item.resolved = resolvedHostPath
- item.root = "/"
-
- statInfo, statError := os.Stat(resolvedHostPath)
- item.statError = statError
-
- // It exists, we're done.
- if statError == nil {
- item.info.Name = statInfo.Name()
- item.info.Size = statInfo.Size()
- item.info.Mode = statInfo.Mode()
- item.info.ModTime = statInfo.ModTime()
- item.info.IsDir = statInfo.IsDir()
- item.info.LinkTarget = resolvedHostPath
- return item, nil
- }
-
- // The source must exist, but let's try to give some human-friendly
- // errors.
- if isSource {
- if os.IsNotExist(item.statError) {
- return item, errors.Wrapf(os.ErrNotExist, "%q could not be found on the host", hostPath)
- }
- return item, item.statError // could be a permission error
- }
-
- // If we're a destination, we need to make sure that the parent
- // directory exists.
- parent := filepath.Dir(resolvedHostPath)
- if _, err := os.Stat(parent); err != nil {
- if os.IsNotExist(err) {
- return item, errors.Wrapf(os.ErrNotExist, "%q could not be found on the host", parent)
- }
- return item, err
- }
-
- return item, nil
-}
-
-// CopyItemForContainer creates a CopyItem for the specified path on the
-// container. It's a destination by default. Use isSource to set it as a
-// destination. Note that the container path may resolve to a path outside of
-// the container's mount point if the path hits a volume or mount on the
-// container.
-//
-// Note that callers *must* call (CopyItem).CleanUp(), even in case of errors.
-func CopyItemForContainer(container *libpod.Container, containerPath string, pause bool, isSource bool) (item CopyItem, _ error) {
- // Mount and pause the container.
- containerMountPoint, err := item.mountAndPauseContainer(container, pause)
- if err != nil {
- return item, err
- }
-
- // Make sure that "/" copies the *contents* of the mount point and not
- // the directory.
- if containerPath == "/" {
- containerPath += "/."
- }
-
- // Now resolve the container's path. It may hit a volume, it may hit a
- // bind mount, it may be relative.
- resolvedRoot, resolvedContainerPath, err := resolveContainerPaths(container, containerMountPoint, containerPath)
- if err != nil {
- return item, err
- }
- resolvedContainerPath = preserveBasePath(containerPath, resolvedContainerPath)
-
- idMappings, idPair, err := getIDMappingsAndPair(container, containerMountPoint)
- if err != nil {
- return item, err
- }
-
- item.original = containerPath
- item.resolved = resolvedContainerPath
- item.root = resolvedRoot
- item.idMappings = idMappings
- item.idPair = idPair
-
- statInfo, statError := secureStat(resolvedRoot, resolvedContainerPath)
- item.statError = statError
-
- // It exists, we're done.
- if statError == nil {
- item.info.IsDir = statInfo.IsDir
- item.info.Name = filepath.Base(statInfo.Name)
- item.info.Size = statInfo.Size
- item.info.Mode = statInfo.Mode
- item.info.ModTime = statInfo.ModTime
- item.info.IsDir = statInfo.IsDir
- item.info.LinkTarget = resolvedContainerPath
- return item, nil
- }
-
- // The source must exist, but let's try to give some human-friendly
- // errors.
- if isSource {
- if os.IsNotExist(statError) {
- return item, errors.Wrapf(os.ErrNotExist, "%q could not be found on container %s (resolved to %q)", containerPath, container.ID(), resolvedContainerPath)
- }
- return item, item.statError // could be a permission error
- }
-
- // If we're a destination, we need to make sure that the parent
- // directory exists.
- parent := filepath.Dir(resolvedContainerPath)
- if _, err := secureStat(resolvedRoot, parent); err != nil {
- if os.IsNotExist(err) {
- return item, errors.Wrapf(os.ErrNotExist, "%q could not be found on container %s (resolved to %q)", containerPath, container.ID(), resolvedContainerPath)
- }
- return item, err
- }
-
- return item, nil
-}
-
-// putOptions returns PUT options for buildah's copier package.
-func (item *CopyItem) putOptions() buildahCopiah.PutOptions {
- options := buildahCopiah.PutOptions{}
- if item.idMappings != nil {
- options.UIDMap = item.idMappings.UIDMap
- options.GIDMap = item.idMappings.GIDMap
- }
- if item.idPair != nil {
- options.ChownDirs = item.idPair
- options.ChownFiles = item.idPair
- }
- return options
-}
-
-// getOptions returns GET options for buildah's copier package.
-func (item *CopyItem) getOptions() buildahCopiah.GetOptions {
- options := buildahCopiah.GetOptions{}
- if item.idMappings != nil {
- options.UIDMap = item.idMappings.UIDMap
- options.GIDMap = item.idMappings.GIDMap
- }
- if item.idPair != nil {
- options.ChownDirs = item.idPair
- options.ChownFiles = item.idPair
- }
- return options
-
-}
-
-// mount and pause the container. Also set the item's cleanUpFuncs. Those
-// *must* be invoked by callers, even in case of errors.
-func (item *CopyItem) mountAndPauseContainer(container *libpod.Container, pause bool) (string, error) {
- // Make sure to pause and unpause the container. We cannot pause on
- // cgroupsv1 as rootless user, in which case we turn off pausing.
- if pause && rootless.IsRootless() {
- cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
- if !cgroupv2 {
- logrus.Debugf("Cannot pause container for copying as a rootless user on cgroupsv1: default to not pause")
- pause = false
- }
- }
-
- // Mount and unmount the container.
- mountPoint, err := container.Mount()
- if err != nil {
- return "", err
- }
-
- item.cleanUpFuncs = append(item.cleanUpFuncs, func() {
- if err := container.Unmount(false); err != nil {
- logrus.Errorf("Error unmounting container after copy operation: %v", err)
- }
- })
-
- // Pause and unpause the container.
- if pause {
- if err := container.Pause(); err != nil {
- // Ignore errors when the container isn't running. No
- // need to pause.
- if errors.Cause(err) != define.ErrCtrStateInvalid {
- return "", err
- }
- } else {
- item.cleanUpFuncs = append(item.cleanUpFuncs, func() {
- if err := container.Unpause(); err != nil {
- logrus.Errorf("Error unpausing container after copy operation: %v", err)
- }
- })
- }
- }
-
- return mountPoint, nil
-}
-
-// buildahGlobs returns the root, dir and glob used in buildah's copier
-// package.
-//
-// Note that dir is always empty.
-func (item *CopyItem) buildahGlobs() (root string, glob string, err error) {
- root = item.root
-
- // If the root and the resolved path are equal, then dir must be empty
- // and the glob must be ".".
- if filepath.Clean(root) == filepath.Clean(item.resolved) {
- glob = "."
- return
- }
-
- glob, err = filepath.Rel(root, item.resolved)
- return
-}
-
-// preserveBasePath makes sure that the original base path (e.g., "/" or "./")
-// is preserved. The filepath API among tends to clean up a bit too much but
-// we *must* preserve this data by all means.
-func preserveBasePath(original, resolved string) string {
- // Handle "/"
- if strings.HasSuffix(original, "/") {
- if !strings.HasSuffix(resolved, "/") {
- resolved += "/"
- }
- return resolved
- }
-
- // Handle "/."
- if strings.HasSuffix(original, "/.") {
- if strings.HasSuffix(resolved, "/") { // could be root!
- resolved += "."
- } else if !strings.HasSuffix(resolved, "/.") {
- resolved += "/."
- }
- return resolved
- }
-
- return resolved
-}
-
-// secureStat extracts file info for path in a chroot'ed environment in root.
-func secureStat(root string, path string) (*buildahCopiah.StatForItem, error) {
- var glob string
- var err error
-
- // If root and path are equal, then dir must be empty and the glob must
- // be ".".
- if filepath.Clean(root) == filepath.Clean(path) {
- glob = "."
- } else {
- glob, err = filepath.Rel(root, path)
- if err != nil {
- return nil, err
- }
- }
-
- globStats, err := buildahCopiah.Stat(root, "", buildahCopiah.StatOptions{}, []string{glob})
- if err != nil {
- return nil, err
- }
-
- if len(globStats) != 1 {
- return nil, errors.Errorf("internal libpod error: secureStat: expected 1 item but got %d", len(globStats))
- }
-
- stat, exists := globStats[0].Results[glob] // only one glob passed, so that's okay
- if !exists {
- return stat, os.ErrNotExist
- }
-
- var statErr error
- if stat.Error != "" {
- statErr = errors.New(stat.Error)
- }
- return stat, statErr
-}
-
-// resolveContainerPaths resolves the container's mount point and the container
-// path as specified by the user. Both may resolve to paths outside of the
-// container's mount point when the container path hits a volume or bind mount.
-//
-// NOTE: We must take volumes and bind mounts into account as, regrettably, we
-// can copy to/from stopped containers. In that case, the volumes and bind
-// mounts are not present. For running containers, the runtime (e.g., runc or
-// crun) takes care of these mounts. For stopped ones, we need to do quite
-// some dance, as done below.
-func resolveContainerPaths(container *libpod.Container, mountPoint string, containerPath string) (string, string, error) {
- // Let's first make sure we have a path relative to the mount point.
- pathRelativeToContainerMountPoint := containerPath
- if !filepath.IsAbs(containerPath) {
- // If the containerPath is not absolute, it's relative to the
- // container's working dir. To be extra careful, let's first
- // join the working dir with "/", and the add the containerPath
- // to it.
- pathRelativeToContainerMountPoint = filepath.Join(filepath.Join("/", container.WorkingDir()), containerPath)
- }
- // NOTE: the secure join makes sure that we follow symlinks. This way,
- // we catch scenarios where the container path symlinks to a volume or
- // bind mount.
- resolvedPathOnTheContainerMountPoint, err := securejoin.SecureJoin(mountPoint, pathRelativeToContainerMountPoint)
- if err != nil {
- return "", "", err
- }
- pathRelativeToContainerMountPoint = strings.TrimPrefix(pathRelativeToContainerMountPoint, mountPoint)
- pathRelativeToContainerMountPoint = filepath.Join("/", pathRelativeToContainerMountPoint)
-
- // Now we have an "absolute container Path" but not yet resolved on the
- // host (e.g., "/foo/bar/file.txt"). As mentioned above, we need to
- // check if "/foo/bar/file.txt" is on a volume or bind mount. To do
- // that, we need to walk *down* the paths to the root. Assuming
- // volume-1 is mounted to "/foo" and volume-2 is mounted to "/foo/bar",
- // we must select "/foo/bar". Once selected, we need to rebase the
- // remainder (i.e, "/file.txt") on the volume's mount point on the
- // host. Same applies to bind mounts.
-
- searchPath := pathRelativeToContainerMountPoint
- for {
- volume, err := findVolume(container, searchPath)
- if err != nil {
- return "", "", err
- }
- if volume != nil {
- logrus.Debugf("Container path %q resolved to volume %q on path %q", containerPath, volume.Name(), searchPath)
- // We found a matching volume for searchPath. We now
- // need to first find the relative path of our input
- // path to the searchPath, and then join it with the
- // volume's mount point.
- pathRelativeToVolume := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
- absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(volume.MountPoint(), pathRelativeToVolume)
- if err != nil {
- return "", "", err
- }
- return volume.MountPoint(), absolutePathOnTheVolumeMount, nil
- }
-
- if mount := findBindMount(container, searchPath); mount != nil {
- logrus.Debugf("Container path %q resolved to bind mount %q:%q on path %q", containerPath, mount.Source, mount.Destination, searchPath)
- // We found a matching bind mount for searchPath. We
- // now need to first find the relative path of our
- // input path to the searchPath, and then join it with
- // the source of the bind mount.
- pathRelativeToBindMount := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
- absolutePathOnTheBindMount, err := securejoin.SecureJoin(mount.Source, pathRelativeToBindMount)
- if err != nil {
- return "", "", err
- }
- return mount.Source, absolutePathOnTheBindMount, nil
-
- }
-
- if searchPath == "/" {
- // Cannot go beyond "/", so we're done.
- break
- }
-
- // Walk *down* the path (e.g., "/foo/bar/x" -> "/foo/bar").
- searchPath = filepath.Dir(searchPath)
- }
-
- // No volume, no bind mount but just a normal path on the container.
- return mountPoint, resolvedPathOnTheContainerMountPoint, nil
-}
-
-// findVolume checks if the specified container path matches a volume inside
-// the container. It returns a matching volume or nil.
-func findVolume(c *libpod.Container, containerPath string) (*libpod.Volume, error) {
- runtime := c.Runtime()
- cleanedContainerPath := filepath.Clean(containerPath)
- for _, vol := range c.Config().NamedVolumes {
- if cleanedContainerPath == filepath.Clean(vol.Dest) {
- return runtime.GetVolume(vol.Name)
- }
- }
- return nil, nil
-}
-
-// findBindMount checks if the specified container path matches a bind mount
-// inside the container. It returns a matching mount or nil.
-func findBindMount(c *libpod.Container, containerPath string) *specs.Mount {
- cleanedPath := filepath.Clean(containerPath)
- for _, m := range c.Config().Spec.Mounts {
- if m.Type != "bind" {
- continue
- }
- if cleanedPath == filepath.Clean(m.Destination) {
- mount := m
- return &mount
- }
- }
- return nil
-}
-
-// getIDMappingsAndPair returns the ID mappings for the container and the host
-// ID pair.
-func getIDMappingsAndPair(container *libpod.Container, containerMount string) (*storage.IDMappingOptions, *idtools.IDPair, error) {
- user, err := getContainerUser(container, containerMount)
- if err != nil {
- return nil, nil, err
- }
-
- idMappingOpts, err := container.IDMappings()
- if err != nil {
- return nil, nil, err
- }
-
- hostUID, hostGID, err := util.GetHostIDs(idtoolsToRuntimeSpec(idMappingOpts.UIDMap), idtoolsToRuntimeSpec(idMappingOpts.GIDMap), user.UID, user.GID)
- if err != nil {
- return nil, nil, err
- }
-
- idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
- return &idMappingOpts, &idPair, nil
-}
-
-// getContainerUser returns the specs.User of the container.
-func getContainerUser(container *libpod.Container, mountPoint string) (specs.User, error) {
- userspec := container.Config().User
-
- uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
- u := specs.User{
- UID: uid,
- GID: gid,
- Username: userspec,
- }
-
- if !strings.Contains(userspec, ":") {
- groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
- if err2 != nil {
- if errors.Cause(err2) != chrootuser.ErrNoSuchUser && err == nil {
- err = err2
- }
- } else {
- u.AdditionalGids = groups
- }
- }
-
- return u, err
-}
-
-// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec.
-func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) {
- for _, idmap := range idMaps {
- tempIDMap := specs.LinuxIDMapping{
- ContainerID: uint32(idmap.ContainerID),
- HostID: uint32(idmap.HostID),
- Size: uint32(idmap.Size),
- }
- convertedIDMap = append(convertedIDMap, tempIDMap)
- }
- return convertedIDMap
-}
diff --git a/pkg/domain/entities/container_ps.go b/pkg/domain/entities/container_ps.go
index b4e8446cb..ff3b087ed 100644
--- a/pkg/domain/entities/container_ps.go
+++ b/pkg/domain/entities/container_ps.go
@@ -12,6 +12,8 @@ import (
// Listcontainer describes a container suitable for listing
type ListContainer struct {
+ // AutoRemove
+ AutoRemove bool
// Container command
Command []string
// Container creation time
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 39d679eaf..05b9b774e 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/copy"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/cri-o/ocicni/pkg/ocicni"
)
@@ -103,9 +104,10 @@ type TopOptions struct {
}
type KillOptions struct {
- All bool
- Latest bool
- Signal string
+ All bool
+ Latest bool
+ Signal string
+ CIDFiles []string
}
type KillReport struct {
@@ -143,6 +145,10 @@ type ContainerInspectReport struct {
*define.InspectContainerData
}
+type ContainerStatReport struct {
+ copy.FileInfo
+}
+
type CommitOptions struct {
Author string
Changes []string
@@ -227,8 +233,10 @@ type ContainerLogsOptions struct {
Tail int64
// Show timestamps in the logs.
Timestamps bool
- // Write the logs to Writer.
- Writer io.Writer
+ // Write the stdout to this Writer.
+ StdoutWriter io.Writer
+ // Write the stderr to this Writer.
+ StderrWriter io.Writer
}
// ExecOptions describes the cli values to exec into
@@ -382,13 +390,6 @@ type ContainerPruneOptions struct {
Filters url.Values `json:"filters" schema:"filters"`
}
-// ContainerPruneReport describes the results after pruning the
-// stopped containers.
-type ContainerPruneReport struct {
- ID map[string]int64
- Err map[string]error
-}
-
// ContainerPortOptions describes the options to obtain
// port information on containers
type ContainerPortOptions struct {
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 5ad475133..7d38a97f2 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -2,13 +2,17 @@ package entities
import (
"context"
+ "io"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/spf13/cobra"
)
+type ContainerCopyFunc func() error
+
type ContainerEngine interface {
AutoUpdate(ctx context.Context, options AutoUpdateOptions) (*AutoUpdateReport, []error)
Config(ctx context.Context) (*config.Config, error)
@@ -16,7 +20,8 @@ type ContainerEngine interface {
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
ContainerCleanup(ctx context.Context, namesOrIds []string, options ContainerCleanupOptions) ([]*ContainerCleanupReport, error)
ContainerCommit(ctx context.Context, nameOrID string, options CommitOptions) (*CommitReport, error)
- ContainerCp(ctx context.Context, source, dest string, options ContainerCpOptions) error
+ ContainerCopyFromArchive(ctx context.Context, nameOrID string, path string, reader io.Reader) (ContainerCopyFunc, error)
+ ContainerCopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (ContainerCopyFunc, error)
ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error)
ContainerDiff(ctx context.Context, nameOrID string, options DiffOptions) (*DiffReport, error)
ContainerExec(ctx context.Context, nameOrID string, options ExecOptions, streams define.AttachStreams) (int, error)
@@ -31,13 +36,14 @@ type ContainerEngine interface {
ContainerMount(ctx context.Context, nameOrIDs []string, options ContainerMountOptions) ([]*ContainerMountReport, error)
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error)
- ContainerPrune(ctx context.Context, options ContainerPruneOptions) (*ContainerPruneReport, error)
+ ContainerPrune(ctx context.Context, options ContainerPruneOptions) ([]*reports.PruneReport, error)
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error)
ContainerRunlabel(ctx context.Context, label string, image string, args []string, opts ContainerRunlabelOptions) error
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
+ ContainerStat(ctx context.Context, nameOrDir string, path string) (*ContainerStatReport, error)
ContainerStats(ctx context.Context, namesOrIds []string, options ContainerStatsOptions) (chan ContainerStatsReport, error)
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
@@ -80,6 +86,6 @@ type ContainerEngine interface {
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
- VolumePrune(ctx context.Context) ([]*VolumePruneReport, error)
+ VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*reports.PruneReport, error)
VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error)
}
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index 594f9617f..26a136f13 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -4,6 +4,7 @@ import (
"context"
"github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
)
type ImageEngine interface {
@@ -17,7 +18,7 @@ type ImageEngine interface {
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
Mount(ctx context.Context, images []string, options ImageMountOptions) ([]*ImageMountReport, error)
- Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
+ Prune(ctx context.Context, opts ImagePruneOptions) ([]*reports.PruneReport, error)
Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error)
Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
@@ -35,6 +36,6 @@ type ImageEngine interface {
ManifestAdd(ctx context.Context, opts ManifestAddOptions) (string, error)
ManifestAnnotate(ctx context.Context, names []string, opts ManifestAnnotateOptions) (string, error)
ManifestRemove(ctx context.Context, names []string) (string, error)
- ManifestPush(ctx context.Context, names []string, manifestPushOpts ManifestPushOptions) error
+ ManifestPush(ctx context.Context, name, destination string, manifestPushOpts ManifestPushOptions) error
Sign(ctx context.Context, names []string, options SignOptions) (*SignReport, error)
}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 81f12bff7..d5f88502a 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -222,7 +222,7 @@ type ImageSearchOptions struct {
type ImageSearchReport struct {
// Index is the image index (e.g., "docker.io" or "quay.io")
Index string
- // Name is the canoncical name of the image (e.g., "docker.io/library/alpine").
+ // Name is the canonical name of the image (e.g., "docker.io/library/alpine").
Name string
// Description of the image.
Description string
@@ -247,11 +247,6 @@ type ImagePruneOptions struct {
Filter []string `json:"filter" schema:"filter"`
}
-type ImagePruneReport struct {
- Report Report
- Size int64
-}
-
type ImageTagOptions struct{}
type ImageUntagOptions struct{}
@@ -344,6 +339,7 @@ type SignOptions struct {
Directory string
SignBy string
CertDir string
+ All bool
}
// SignReport describes the result of signing
diff --git a/pkg/domain/entities/reports/prune.go b/pkg/domain/entities/reports/prune.go
new file mode 100644
index 000000000..5494ac3ae
--- /dev/null
+++ b/pkg/domain/entities/reports/prune.go
@@ -0,0 +1,40 @@
+package reports
+
+type PruneReport struct {
+ Id string //nolint
+ Err error
+ Size uint64
+}
+
+func PruneReportsIds(r []*PruneReport) []string {
+ ids := make([]string, 0, len(r))
+ for _, v := range r {
+ if v == nil || v.Id == "" {
+ continue
+ }
+ ids = append(ids, v.Id)
+ }
+ return ids
+}
+
+func PruneReportsErrs(r []*PruneReport) []error {
+ errs := make([]error, 0, len(r))
+ for _, v := range r {
+ if v == nil || v.Err == nil {
+ continue
+ }
+ errs = append(errs, v.Err)
+ }
+ return errs
+}
+
+func PruneReportsSize(r []*PruneReport) uint64 {
+ size := uint64(0)
+ for _, v := range r {
+ if v == nil {
+ continue
+ }
+ size = size + v.Size
+ }
+ return size
+}
diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go
index bde2b6ef2..99fa947f0 100644
--- a/pkg/domain/entities/system.go
+++ b/pkg/domain/entities/system.go
@@ -4,6 +4,7 @@ import (
"time"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
)
@@ -17,16 +18,18 @@ type ServiceOptions struct {
// SystemPruneOptions provides options to prune system.
type SystemPruneOptions struct {
- All bool
- Volume bool
+ All bool
+ Volume bool
+ Filters map[string][]string `json:"filters" schema:"filters"`
}
// SystemPruneReport provides report after system prune is executed.
type SystemPruneReport struct {
- PodPruneReport []*PodPruneReport
- *ContainerPruneReport
- *ImagePruneReport
- VolumePruneReport []*VolumePruneReport
+ PodPruneReport []*PodPruneReport
+ ContainerPruneReports []*reports.PruneReport
+ ImagePruneReports []*reports.PruneReport
+ VolumePruneReports []*reports.PruneReport
+ ReclaimedSpace uint64
}
// SystemMigrateOptions describes the options needed for the
diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go
index 1bc1e4301..06438f5e9 100644
--- a/pkg/domain/entities/volumes.go
+++ b/pkg/domain/entities/volumes.go
@@ -1,6 +1,7 @@
package entities
import (
+ "net/url"
"time"
docker_api_types "github.com/docker/docker/api/types"
@@ -109,9 +110,10 @@ type VolumeInspectReport struct {
*VolumeConfigResponse
}
-type VolumePruneReport struct {
- Err error
- Id string //nolint
+// VolumePruneOptions describes the options needed
+// to prune a volume from the CLI
+type VolumePruneOptions struct {
+ Filters url.Values `json:"filters" schema:"filters"`
}
type VolumeListOptions struct {
diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go
new file mode 100644
index 000000000..ce6c12b71
--- /dev/null
+++ b/pkg/domain/filters/containers.go
@@ -0,0 +1,238 @@
+package filters
+
+import (
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/timetype"
+ "github.com/containers/podman/v2/pkg/util"
+ "github.com/pkg/errors"
+)
+
+// GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
+func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) {
+ switch filter {
+ case "id":
+ // we only have to match one ID
+ return func(c *libpod.Container) bool {
+ return util.StringMatchRegexSlice(c.ID(), filterValues)
+ }, nil
+ case "label":
+ // we have to match that all given labels exits on that container
+ return func(c *libpod.Container) bool {
+ labels := c.Labels()
+ for _, filterValue := range filterValues {
+ matched := false
+ filterArray := strings.SplitN(filterValue, "=", 2)
+ filterKey := filterArray[0]
+ if len(filterArray) > 1 {
+ filterValue = filterArray[1]
+ } else {
+ filterValue = ""
+ }
+ for labelKey, labelValue := range labels {
+ if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
+ matched = true
+ break
+ }
+ }
+ if !matched {
+ return false
+ }
+ }
+ return true
+ }, nil
+ case "name":
+ // we only have to match one name
+ return func(c *libpod.Container) bool {
+ return util.StringMatchRegexSlice(c.Name(), filterValues)
+ }, nil
+ case "exited":
+ var exitCodes []int32
+ for _, exitCode := range filterValues {
+ ec, err := strconv.ParseInt(exitCode, 10, 32)
+ if err != nil {
+ return nil, errors.Wrapf(err, "exited code out of range %q", ec)
+ }
+ exitCodes = append(exitCodes, int32(ec))
+ }
+ return func(c *libpod.Container) bool {
+ ec, exited, err := c.ExitCode()
+ if err == nil && exited {
+ for _, exitCode := range exitCodes {
+ if ec == exitCode {
+ return true
+ }
+ }
+ }
+ return false
+ }, nil
+ case "status":
+ for _, filterValue := range filterValues {
+ if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) {
+ return nil, errors.Errorf("%s is not a valid status", filterValue)
+ }
+ }
+ return func(c *libpod.Container) bool {
+ status, err := c.State()
+ if err != nil {
+ return false
+ }
+ state := status.String()
+ if status == define.ContainerStateConfigured {
+ state = "created"
+ } else if status == define.ContainerStateStopped {
+ state = "exited"
+ }
+ for _, filterValue := range filterValues {
+ if filterValue == "stopped" {
+ filterValue = "exited"
+ }
+ if state == filterValue {
+ return true
+ }
+ }
+ return false
+ }, nil
+ case "ancestor":
+ // This needs to refine to match docker
+ // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
+ return func(c *libpod.Container) bool {
+ for _, filterValue := range filterValues {
+ containerConfig := c.Config()
+ if strings.Contains(containerConfig.RootfsImageID, filterValue) || strings.Contains(containerConfig.RootfsImageName, filterValue) {
+ return true
+ }
+ }
+ return false
+ }, nil
+ case "before":
+ var createTime time.Time
+ for _, filterValue := range filterValues {
+ ctr, err := r.LookupContainer(filterValue)
+ if err != nil {
+ return nil, err
+ }
+ containerConfig := ctr.Config()
+ if createTime.IsZero() || createTime.After(containerConfig.CreatedTime) {
+ createTime = containerConfig.CreatedTime
+ }
+ }
+ return func(c *libpod.Container) bool {
+ cc := c.Config()
+ return createTime.After(cc.CreatedTime)
+ }, nil
+ case "since":
+ var createTime time.Time
+ for _, filterValue := range filterValues {
+ ctr, err := r.LookupContainer(filterValue)
+ if err != nil {
+ return nil, err
+ }
+ containerConfig := ctr.Config()
+ if createTime.IsZero() || createTime.After(containerConfig.CreatedTime) {
+ createTime = containerConfig.CreatedTime
+ }
+ }
+ return func(c *libpod.Container) bool {
+ cc := c.Config()
+ return createTime.Before(cc.CreatedTime)
+ }, nil
+ case "volume":
+ //- volume=(<volume-name>|<mount-point-destination>)
+ return func(c *libpod.Container) bool {
+ containerConfig := c.Config()
+ var dest string
+ for _, filterValue := range filterValues {
+ arr := strings.SplitN(filterValue, ":", 2)
+ source := arr[0]
+ if len(arr) == 2 {
+ dest = arr[1]
+ }
+ for _, mount := range containerConfig.Spec.Mounts {
+ if dest != "" && (mount.Source == source && mount.Destination == dest) {
+ return true
+ }
+ if dest == "" && mount.Source == source {
+ return true
+ }
+ }
+ for _, vname := range containerConfig.NamedVolumes {
+ if dest != "" && (vname.Name == source && vname.Dest == dest) {
+ return true
+ }
+ if dest == "" && vname.Name == source {
+ return true
+ }
+ }
+ }
+ return false
+ }, nil
+ case "health":
+ return func(c *libpod.Container) bool {
+ hcStatus, err := c.HealthCheckStatus()
+ if err != nil {
+ return false
+ }
+ for _, filterValue := range filterValues {
+ if hcStatus == filterValue {
+ return true
+ }
+ }
+ return false
+ }, nil
+ case "until":
+ if len(filterValues) != 1 {
+ return nil, errors.Errorf("specify exactly one timestamp for %s", filter)
+ }
+ ts, err := timetype.GetTimestamp(filterValues[0], time.Now())
+ if err != nil {
+ return nil, err
+ }
+ seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
+ if err != nil {
+ return nil, err
+ }
+ until := time.Unix(seconds, nanoseconds)
+ return func(c *libpod.Container) bool {
+ if !until.IsZero() && c.CreatedTime().After((until)) {
+ return true
+ }
+ return false
+ }, nil
+ case "pod":
+ var pods []*libpod.Pod
+ for _, podNameOrID := range filterValues {
+ p, err := r.LookupPod(podNameOrID)
+ if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchPod {
+ continue
+ }
+ return nil, err
+ }
+ pods = append(pods, p)
+ }
+ return func(c *libpod.Container) bool {
+ // if no pods match, quick out
+ if len(pods) < 1 {
+ return false
+ }
+ // if the container has no pod id, quick out
+ if len(c.PodID()) < 1 {
+ return false
+ }
+ for _, p := range pods {
+ // we already looked up by name or id, so id match
+ // here is ok
+ if p.ID() == c.PodID() {
+ return true
+ }
+ }
+ return false
+ }, nil
+ }
+ return nil, errors.Errorf("%s is an invalid filter", filter)
+}
diff --git a/pkg/domain/filters/helpers.go b/pkg/domain/filters/helpers.go
new file mode 100644
index 000000000..6a5fb68b1
--- /dev/null
+++ b/pkg/domain/filters/helpers.go
@@ -0,0 +1,20 @@
+package filters
+
+import (
+ "net/url"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+func ParseFilterArgumentsIntoFilters(filters []string) (url.Values, error) {
+ parsedFilters := make(url.Values)
+ for _, f := range filters {
+ t := strings.SplitN(f, "=", 2)
+ if len(t) < 2 {
+ return parsedFilters, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
+ }
+ parsedFilters.Add(t[0], t[1])
+ }
+ return parsedFilters, nil
+}
diff --git a/pkg/domain/filters/pods.go b/pkg/domain/filters/pods.go
new file mode 100644
index 000000000..7e6b7f2cc
--- /dev/null
+++ b/pkg/domain/filters/pods.go
@@ -0,0 +1,139 @@
+package filters
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/util"
+ "github.com/pkg/errors"
+)
+
+// GeneratePodFilterFunc takes a filter and filtervalue (key, value)
+// and generates a libpod function that can be used to filter
+// pods
+func GeneratePodFilterFunc(filter string, filterValues []string) (
+ func(pod *libpod.Pod) bool, error) {
+ switch filter {
+ case "ctr-ids":
+ return func(p *libpod.Pod) bool {
+ ctrIds, err := p.AllContainersByID()
+ if err != nil {
+ return false
+ }
+ for _, id := range ctrIds {
+ return util.StringMatchRegexSlice(id, filterValues)
+ }
+ return false
+ }, nil
+ case "ctr-names":
+ return func(p *libpod.Pod) bool {
+ ctrs, err := p.AllContainers()
+ if err != nil {
+ return false
+ }
+ for _, ctr := range ctrs {
+ return util.StringMatchRegexSlice(ctr.Name(), filterValues)
+ }
+ return false
+ }, nil
+ case "ctr-number":
+ return func(p *libpod.Pod) bool {
+ ctrIds, err := p.AllContainersByID()
+ if err != nil {
+ return false
+ }
+ for _, filterValue := range filterValues {
+ fVint, err2 := strconv.Atoi(filterValue)
+ if err2 != nil {
+ return false
+ }
+ if len(ctrIds) == fVint {
+ return true
+ }
+ }
+ return false
+ }, nil
+ case "ctr-status":
+ for _, filterValue := range filterValues {
+ if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) {
+ return nil, errors.Errorf("%s is not a valid status", filterValue)
+ }
+ }
+ return func(p *libpod.Pod) bool {
+ ctrStatuses, err := p.Status()
+ if err != nil {
+ return false
+ }
+ for _, ctrStatus := range ctrStatuses {
+ state := ctrStatus.String()
+ if ctrStatus == define.ContainerStateConfigured {
+ state = "created"
+ } else if ctrStatus == define.ContainerStateStopped {
+ state = "exited"
+ }
+ for _, filterValue := range filterValues {
+ if filterValue == "stopped" {
+ filterValue = "exited"
+ }
+ if state == filterValue {
+ return true
+ }
+ }
+ }
+ return false
+ }, nil
+ case "id":
+ return func(p *libpod.Pod) bool {
+ return util.StringMatchRegexSlice(p.ID(), filterValues)
+ }, nil
+ case "name":
+ return func(p *libpod.Pod) bool {
+ return util.StringMatchRegexSlice(p.Name(), filterValues)
+ }, nil
+ case "status":
+ for _, filterValue := range filterValues {
+ if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created", "degraded"}) {
+ return nil, errors.Errorf("%s is not a valid pod status", filterValue)
+ }
+ }
+ return func(p *libpod.Pod) bool {
+ status, err := p.GetPodStatus()
+ if err != nil {
+ return false
+ }
+ for _, filterValue := range filterValues {
+ if strings.ToLower(status) == filterValue {
+ return true
+ }
+ }
+ return false
+ }, nil
+ case "label":
+ return func(p *libpod.Pod) bool {
+ labels := p.Labels()
+ for _, filterValue := range filterValues {
+ matched := false
+ filterArray := strings.SplitN(filterValue, "=", 2)
+ filterKey := filterArray[0]
+ if len(filterArray) > 1 {
+ filterValue = filterArray[1]
+ } else {
+ filterValue = ""
+ }
+ for labelKey, labelValue := range labels {
+ if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
+ matched = true
+ break
+ }
+ }
+ if !matched {
+ return false
+ }
+ }
+ return true
+ }, nil
+ }
+ return nil, errors.Errorf("%s is an invalid filter", filter)
+}
diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go
index 7819d3cdf..69bef4961 100644
--- a/pkg/domain/filters/volumes.go
+++ b/pkg/domain/filters/volumes.go
@@ -1,13 +1,14 @@
package filters
import (
+ "net/url"
"strings"
"github.com/containers/podman/v2/libpod"
"github.com/pkg/errors"
)
-func GenerateVolumeFilters(filters map[string][]string) ([]libpod.VolumeFilter, error) {
+func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) {
var vf []libpod.VolumeFilter
for filter, v := range filters {
for _, val := range v {
diff --git a/pkg/domain/infra/abi/archive.go b/pkg/domain/infra/abi/archive.go
new file mode 100644
index 000000000..809813756
--- /dev/null
+++ b/pkg/domain/infra/abi/archive.go
@@ -0,0 +1,172 @@
+package abi
+
+import (
+ "context"
+ "io"
+ "strings"
+
+ buildahCopiah "github.com/containers/buildah/copier"
+ "github.com/containers/buildah/pkg/chrootuser"
+ "github.com/containers/buildah/util"
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/storage"
+ "github.com/containers/storage/pkg/archive"
+ "github.com/containers/storage/pkg/idtools"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// NOTE: Only the parent directory of the container path must exist. The path
+// itself may be created while copying.
+func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrID string, containerPath string, reader io.Reader) (entities.ContainerCopyFunc, error) {
+ container, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ unmount := func() {
+ if err := container.Unmount(false); err != nil {
+ logrus.Errorf("Error unmounting container: %v", err)
+ }
+ }
+
+ _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerPath)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ decompressed, err := archive.DecompressStream(reader)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ idMappings, idPair, err := getIDMappingsAndPair(container, resolvedRoot)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ logrus.Debugf("Container copy *to* %q (resolved: %q) on container %q (ID: %s)", containerPath, resolvedContainerPath, container.Name(), container.ID())
+
+ return func() error {
+ defer unmount()
+ defer decompressed.Close()
+ putOptions := buildahCopiah.PutOptions{
+ UIDMap: idMappings.UIDMap,
+ GIDMap: idMappings.GIDMap,
+ ChownDirs: idPair,
+ ChownFiles: idPair,
+ }
+ return buildahCopiah.Put(resolvedRoot, resolvedContainerPath, putOptions, decompressed)
+ }, nil
+}
+
+func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, containerPath string, writer io.Writer) (entities.ContainerCopyFunc, error) {
+ container, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ unmount := func() {
+ if err := container.Unmount(false); err != nil {
+ logrus.Errorf("Error unmounting container: %v", err)
+ }
+ }
+
+ // Make sure that "/" copies the *contents* of the mount point and not
+ // the directory.
+ if containerPath == "/" {
+ containerPath = "/."
+ }
+
+ _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerPath)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ idMappings, idPair, err := getIDMappingsAndPair(container, resolvedRoot)
+ if err != nil {
+ unmount()
+ return nil, err
+ }
+
+ logrus.Debugf("Container copy *from* %q (resolved: %q) on container %q (ID: %s)", containerPath, resolvedContainerPath, container.Name(), container.ID())
+
+ return func() error {
+ defer container.Unmount(false)
+ getOptions := buildahCopiah.GetOptions{
+ // Unless the specified path ends with ".", we want to copy the base directory.
+ KeepDirectoryNames: !strings.HasSuffix(resolvedContainerPath, "."),
+ UIDMap: idMappings.UIDMap,
+ GIDMap: idMappings.GIDMap,
+ ChownDirs: idPair,
+ ChownFiles: idPair,
+ }
+ return buildahCopiah.Get(resolvedRoot, "", getOptions, []string{resolvedContainerPath}, writer)
+ }, nil
+}
+
+// getIDMappingsAndPair returns the ID mappings for the container and the host
+// ID pair.
+func getIDMappingsAndPair(container *libpod.Container, containerMount string) (*storage.IDMappingOptions, *idtools.IDPair, error) {
+ user, err := getContainerUser(container, containerMount)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ idMappingOpts, err := container.IDMappings()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ hostUID, hostGID, err := util.GetHostIDs(idtoolsToRuntimeSpec(idMappingOpts.UIDMap), idtoolsToRuntimeSpec(idMappingOpts.GIDMap), user.UID, user.GID)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
+ return &idMappingOpts, &idPair, nil
+}
+
+// getContainerUser returns the specs.User of the container.
+func getContainerUser(container *libpod.Container, mountPoint string) (specs.User, error) {
+ userspec := container.Config().User
+
+ uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
+ u := specs.User{
+ UID: uid,
+ GID: gid,
+ Username: userspec,
+ }
+
+ if !strings.Contains(userspec, ":") {
+ groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
+ if err2 != nil {
+ if errors.Cause(err2) != chrootuser.ErrNoSuchUser && err == nil {
+ err = err2
+ }
+ } else {
+ u.AdditionalGids = groups
+ }
+ }
+
+ return u, err
+}
+
+// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec.
+func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) {
+ for _, idmap := range idMaps {
+ tempIDMap := specs.LinuxIDMapping{
+ ContainerID: uint32(idmap.ContainerID),
+ HostID: uint32(idmap.HostID),
+ Size: uint32(idmap.Size),
+ }
+ convertedIDMap = append(convertedIDMap, tempIDMap)
+ }
+ return convertedIDMap
+}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index ff4277a2e..9d7c2daea 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -16,12 +16,13 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/events"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/libpod/logs"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/checkpoint"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
+ dfilters "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/terminal"
parallelctr "github.com/containers/podman/v2/pkg/parallel/ctr"
"github.com/containers/podman/v2/pkg/ps"
@@ -204,31 +205,27 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
return reports, nil
}
-func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
+func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
for k, v := range options.Filters {
- generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
+ generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
if err != nil {
return nil, err
}
filterFuncs = append(filterFuncs, generatedFunc)
}
- return ic.pruneContainersHelper(filterFuncs)
-}
-
-func (ic *ContainerEngine) pruneContainersHelper(filterFuncs []libpod.ContainerFilter) (*entities.ContainerPruneReport, error) {
- prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs)
- if err != nil {
- return nil, err
- }
- report := entities.ContainerPruneReport{
- ID: prunedContainers,
- Err: pruneErrors,
- }
- return &report, nil
+ return ic.Libpod.PruneContainers(filterFuncs)
}
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
+ for _, cidFile := range options.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error reading CIDFile")
+ }
+ id := strings.Split(string(content), "\n")[0]
+ namesOrIds = append(namesOrIds, id)
+ }
sig, err := signal.ParseSignalNameOrNumber(options.Signal)
if err != nil {
return nil, err
@@ -246,6 +243,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
}
return reports, nil
}
+
func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
var (
ctrs []*libpod.Container
@@ -925,7 +923,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
}
func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error {
- if options.Writer == nil {
+ if options.StdoutWriter == nil && options.StderrWriter == nil {
return errors.New("no io.Writer set for container logs")
}
@@ -963,7 +961,7 @@ func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []strin
}()
for line := range logChannel {
- fmt.Fprintln(options.Writer, line.String(logOpts))
+ line.Write(options.StdoutWriter, options.StderrWriter, logOpts)
}
return nil
diff --git a/pkg/domain/infra/abi/containers_stat.go b/pkg/domain/infra/abi/containers_stat.go
new file mode 100644
index 000000000..5b43ee2f4
--- /dev/null
+++ b/pkg/domain/infra/abi/containers_stat.go
@@ -0,0 +1,251 @@
+package abi
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "strings"
+
+ buildahCopiah "github.com/containers/buildah/copier"
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/pkg/copy"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ securejoin "github.com/cyphar/filepath-securejoin"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func (ic *ContainerEngine) containerStat(container *libpod.Container, containerPath string) (*entities.ContainerStatReport, string, string, error) {
+ containerMountPoint, err := container.Mount()
+ if err != nil {
+ return nil, "", "", err
+ }
+
+ // Make sure that "/" copies the *contents* of the mount point and not
+ // the directory.
+ if containerPath == "/" {
+ containerPath += "/."
+ }
+
+ // Now resolve the container's path. It may hit a volume, it may hit a
+ // bind mount, it may be relative.
+ resolvedRoot, resolvedContainerPath, err := resolveContainerPaths(container, containerMountPoint, containerPath)
+ if err != nil {
+ return nil, "", "", err
+ }
+
+ statInfo, statInfoErr := secureStat(resolvedRoot, resolvedContainerPath)
+ if statInfoErr != nil {
+ // Not all errors from secureStat map to ErrNotExist, so we
+ // have to look into the error string. Turning it into an
+ // ENOENT let's the API handlers return the correct status code
+ // which is crucial for the remote client.
+ if os.IsNotExist(err) || strings.Contains(statInfoErr.Error(), "o such file or directory") {
+ statInfoErr = copy.ENOENT
+ }
+ // If statInfo is nil, there's nothing we can do anymore. A
+ // non-nil statInfo may indicate a symlink where we must have
+ // a closer look.
+ if statInfo == nil {
+ return nil, "", "", statInfoErr
+ }
+ }
+
+ // Now make sure that the info's LinkTarget is relative to the
+ // container's mount.
+ var absContainerPath string
+
+ if statInfo.IsSymlink {
+ // Evaluated symlinks are always relative to the container's mount point.
+ absContainerPath = statInfo.ImmediateTarget
+ } else if strings.HasPrefix(resolvedContainerPath, containerMountPoint) {
+ // If the path is on the container's mount point, strip it off.
+ absContainerPath = strings.TrimPrefix(resolvedContainerPath, containerMountPoint)
+ absContainerPath = filepath.Join("/", absContainerPath)
+ } else {
+ // No symlink and not on the container's mount point, so let's
+ // move it back to the original input. It must have evaluated
+ // to a volume or bind mount but we cannot return host paths.
+ absContainerPath = containerPath
+ }
+
+ // Now we need to make sure to preserve the base path as specified by
+ // the user. The `filepath` packages likes to remove trailing slashes
+ // and dots that are crucial to the copy logic.
+ absContainerPath = copy.PreserveBasePath(containerPath, absContainerPath)
+ resolvedContainerPath = copy.PreserveBasePath(containerPath, resolvedContainerPath)
+
+ info := copy.FileInfo{
+ IsDir: statInfo.IsDir,
+ Name: filepath.Base(absContainerPath),
+ Size: statInfo.Size,
+ Mode: statInfo.Mode,
+ ModTime: statInfo.ModTime,
+ LinkTarget: absContainerPath,
+ }
+
+ return &entities.ContainerStatReport{FileInfo: info}, resolvedRoot, resolvedContainerPath, statInfoErr
+}
+
+func (ic *ContainerEngine) ContainerStat(ctx context.Context, nameOrID string, containerPath string) (*entities.ContainerStatReport, error) {
+ container, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ defer func() {
+ if err := container.Unmount(false); err != nil {
+ logrus.Errorf("Error unmounting container: %v", err)
+ }
+ }()
+
+ statReport, _, _, err := ic.containerStat(container, containerPath)
+ return statReport, err
+}
+
+// resolveContainerPaths resolves the container's mount point and the container
+// path as specified by the user. Both may resolve to paths outside of the
+// container's mount point when the container path hits a volume or bind mount.
+//
+// NOTE: We must take volumes and bind mounts into account as, regrettably, we
+// can copy to/from stopped containers. In that case, the volumes and bind
+// mounts are not present. For running containers, the runtime (e.g., runc or
+// crun) takes care of these mounts. For stopped ones, we need to do quite
+// some dance, as done below.
+func resolveContainerPaths(container *libpod.Container, mountPoint string, containerPath string) (string, string, error) {
+ // Let's first make sure we have a path relative to the mount point.
+ pathRelativeToContainerMountPoint := containerPath
+ if !filepath.IsAbs(containerPath) {
+ // If the containerPath is not absolute, it's relative to the
+ // container's working dir. To be extra careful, let's first
+ // join the working dir with "/", and the add the containerPath
+ // to it.
+ pathRelativeToContainerMountPoint = filepath.Join(filepath.Join("/", container.WorkingDir()), containerPath)
+ }
+ resolvedPathOnTheContainerMountPoint := filepath.Join(mountPoint, pathRelativeToContainerMountPoint)
+ pathRelativeToContainerMountPoint = strings.TrimPrefix(pathRelativeToContainerMountPoint, mountPoint)
+ pathRelativeToContainerMountPoint = filepath.Join("/", pathRelativeToContainerMountPoint)
+
+ // Now we have an "absolute container Path" but not yet resolved on the
+ // host (e.g., "/foo/bar/file.txt"). As mentioned above, we need to
+ // check if "/foo/bar/file.txt" is on a volume or bind mount. To do
+ // that, we need to walk *down* the paths to the root. Assuming
+ // volume-1 is mounted to "/foo" and volume-2 is mounted to "/foo/bar",
+ // we must select "/foo/bar". Once selected, we need to rebase the
+ // remainder (i.e, "/file.txt") on the volume's mount point on the
+ // host. Same applies to bind mounts.
+
+ searchPath := pathRelativeToContainerMountPoint
+ for {
+ volume, err := findVolume(container, searchPath)
+ if err != nil {
+ return "", "", err
+ }
+ if volume != nil {
+ logrus.Debugf("Container path %q resolved to volume %q on path %q", containerPath, volume.Name(), searchPath)
+ // We found a matching volume for searchPath. We now
+ // need to first find the relative path of our input
+ // path to the searchPath, and then join it with the
+ // volume's mount point.
+ pathRelativeToVolume := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
+ absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(volume.MountPoint(), pathRelativeToVolume)
+ if err != nil {
+ return "", "", err
+ }
+ return volume.MountPoint(), absolutePathOnTheVolumeMount, nil
+ }
+
+ if mount := findBindMount(container, searchPath); mount != nil {
+ logrus.Debugf("Container path %q resolved to bind mount %q:%q on path %q", containerPath, mount.Source, mount.Destination, searchPath)
+ // We found a matching bind mount for searchPath. We
+ // now need to first find the relative path of our
+ // input path to the searchPath, and then join it with
+ // the source of the bind mount.
+ pathRelativeToBindMount := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
+ absolutePathOnTheBindMount, err := securejoin.SecureJoin(mount.Source, pathRelativeToBindMount)
+ if err != nil {
+ return "", "", err
+ }
+ return mount.Source, absolutePathOnTheBindMount, nil
+
+ }
+
+ if searchPath == "/" {
+ // Cannot go beyond "/", so we're done.
+ break
+ }
+
+ // Walk *down* the path (e.g., "/foo/bar/x" -> "/foo/bar").
+ searchPath = filepath.Dir(searchPath)
+ }
+
+ // No volume, no bind mount but just a normal path on the container.
+ return mountPoint, resolvedPathOnTheContainerMountPoint, nil
+}
+
+// findVolume checks if the specified container path matches a volume inside
+// the container. It returns a matching volume or nil.
+func findVolume(c *libpod.Container, containerPath string) (*libpod.Volume, error) {
+ runtime := c.Runtime()
+ cleanedContainerPath := filepath.Clean(containerPath)
+ for _, vol := range c.Config().NamedVolumes {
+ if cleanedContainerPath == filepath.Clean(vol.Dest) {
+ return runtime.GetVolume(vol.Name)
+ }
+ }
+ return nil, nil
+}
+
+// findBindMount checks if the specified container path matches a bind mount
+// inside the container. It returns a matching mount or nil.
+func findBindMount(c *libpod.Container, containerPath string) *specs.Mount {
+ cleanedPath := filepath.Clean(containerPath)
+ for _, m := range c.Config().Spec.Mounts {
+ if m.Type != "bind" {
+ continue
+ }
+ if cleanedPath == filepath.Clean(m.Destination) {
+ mount := m
+ return &mount
+ }
+ }
+ return nil
+}
+
+// secureStat extracts file info for path in a chroot'ed environment in root.
+func secureStat(root string, path string) (*buildahCopiah.StatForItem, error) {
+ var glob string
+ var err error
+
+ // If root and path are equal, then dir must be empty and the glob must
+ // be ".".
+ if filepath.Clean(root) == filepath.Clean(path) {
+ glob = "."
+ } else {
+ glob, err = filepath.Rel(root, path)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ globStats, err := buildahCopiah.Stat(root, "", buildahCopiah.StatOptions{}, []string{glob})
+ if err != nil {
+ return nil, err
+ }
+
+ if len(globStats) != 1 {
+ return nil, errors.Errorf("internal error: secureStat: expected 1 item but got %d", len(globStats))
+ }
+
+ stat, exists := globStats[0].Results[glob] // only one glob passed, so that's okay
+ if !exists {
+ return nil, copy.ENOENT
+ }
+
+ var statErr error
+ if stat.Error != "" {
+ statErr = errors.New(stat.Error)
+ }
+ return stat, statErr
+}
diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go
deleted file mode 100644
index 362053cce..000000000
--- a/pkg/domain/infra/abi/cp.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package abi
-
-import (
- "context"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/pkg/copy"
- "github.com/containers/podman/v2/pkg/domain/entities"
-)
-
-func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error {
- // Parse user input.
- sourceContainerStr, sourcePath, destContainerStr, destPath, err := copy.ParseSourceAndDestination(source, dest)
- if err != nil {
- return err
- }
-
- // Look up containers.
- var sourceContainer, destContainer *libpod.Container
- if len(sourceContainerStr) > 0 {
- sourceContainer, err = ic.Libpod.LookupContainer(sourceContainerStr)
- if err != nil {
- return err
- }
- }
- if len(destContainerStr) > 0 {
- destContainer, err = ic.Libpod.LookupContainer(destContainerStr)
- if err != nil {
- return err
- }
- }
-
- var sourceItem, destinationItem copy.CopyItem
-
- // Source ... container OR host.
- if sourceContainer != nil {
- sourceItem, err = copy.CopyItemForContainer(sourceContainer, sourcePath, options.Pause, true)
- defer sourceItem.CleanUp()
- if err != nil {
- return err
- }
- } else {
- sourceItem, err = copy.CopyItemForHost(sourcePath, true)
- if err != nil {
- return err
- }
- }
-
- // Destination ... container OR host.
- if destContainer != nil {
- destinationItem, err = copy.CopyItemForContainer(destContainer, destPath, options.Pause, false)
- defer destinationItem.CleanUp()
- if err != nil {
- return err
- }
- } else {
- destinationItem, err = copy.CopyItemForHost(destPath, false)
- defer destinationItem.CleanUp()
- if err != nil {
- return err
- }
- }
-
- // Copy from the host to the container.
- copier, err := copy.GetCopier(&sourceItem, &destinationItem, options.Extract)
- if err != nil {
- return err
- }
- return copier.Copy()
-}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 57a2bc4cf..19f081abb 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -24,10 +24,13 @@ import (
"github.com/containers/podman/v2/libpod/image"
libpodImage "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
domainUtils "github.com/containers/podman/v2/pkg/domain/utils"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage"
+ dockerRef "github.com/docker/distribution/reference"
+ "github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -47,19 +50,12 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo
return &entities.BoolReport{Value: err == nil}, nil
}
-func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
- results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
+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
}
-
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
- return &report, nil
+ return reports, err
}
func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
@@ -718,9 +714,9 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
logrus.Errorf("unable to close %s image source %q", srcRef.DockerReference().Name(), err)
}
}()
- getManifest, _, err := rawSource.GetManifest(ctx, nil)
+ topManifestBlob, manifestType, err := rawSource.GetManifest(ctx, nil)
if err != nil {
- return errors.Wrapf(err, "error getting getManifest")
+ return errors.Wrapf(err, "error getting manifest blob")
}
dockerReference := rawSource.Reference().DockerReference()
if dockerReference == nil {
@@ -743,34 +739,34 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
return err
}
}
- manifestDigest, err := manifest.Digest(getManifest)
+ manifestDigest, err := manifest.Digest(topManifestBlob)
if err != nil {
return err
}
- // create signature
- newSig, err := signature.SignDockerManifest(getManifest, dockerReference.String(), mech, options.SignBy)
- if err != nil {
- return errors.Wrapf(err, "error creating new signature")
- }
- // create the signstore file
- signatureDir := fmt.Sprintf("%s@%s=%s", sigStoreDir, manifestDigest.Algorithm(), manifestDigest.Hex())
- if err := os.MkdirAll(signatureDir, 0751); err != nil {
- // The directory is allowed to exist
- if !os.IsExist(err) {
- logrus.Error(err)
- return nil
+ if options.All {
+ if !manifest.MIMETypeIsMultiImage(manifestType) {
+ return errors.Errorf("%s is not a multi-architecture image (manifest type %s)", signimage, manifestType)
+ }
+ list, err := manifest.ListFromBlob(topManifestBlob, manifestType)
+ if err != nil {
+ return errors.Wrapf(err, "Error parsing manifest list %q", string(topManifestBlob))
+ }
+ instanceDigests := list.Instances()
+ for _, instanceDigest := range instanceDigests {
+ digest := instanceDigest
+ man, _, err := rawSource.GetManifest(ctx, &digest)
+ if err != nil {
+ return err
+ }
+ if err = putSignature(man, mech, sigStoreDir, instanceDigest, dockerReference, options); err != nil {
+ return errors.Wrapf(err, "error storing signature for %s, %v", dockerReference.String(), instanceDigest)
+ }
}
- }
- sigFilename, err := getSigFilename(signatureDir)
- if err != nil {
- logrus.Errorf("error creating sigstore file: %v", err)
return nil
}
- err = ioutil.WriteFile(filepath.Join(signatureDir, sigFilename), newSig, 0644)
- if err != nil {
- logrus.Errorf("error storing signature for %s", rawSource.Reference().DockerReference().String())
- return nil
+ if err = putSignature(topManifestBlob, mech, sigStoreDir, manifestDigest, dockerReference, options); err != nil {
+ return errors.Wrapf(err, "error storing signature for %s, %v", dockerReference.String(), manifestDigest)
}
return nil
}()
@@ -806,3 +802,26 @@ func localPathFromURI(url *url.URL) (string, error) {
}
return url.Path, nil
}
+
+// putSignature creates signature and saves it to the signstore file
+func putSignature(manifestBlob []byte, mech signature.SigningMechanism, sigStoreDir string, instanceDigest digest.Digest, dockerReference dockerRef.Reference, options entities.SignOptions) error {
+ newSig, err := signature.SignDockerManifest(manifestBlob, dockerReference.String(), mech, options.SignBy)
+ if err != nil {
+ return err
+ }
+ signatureDir := fmt.Sprintf("%s@%s=%s", sigStoreDir, instanceDigest.Algorithm(), instanceDigest.Hex())
+ if err := os.MkdirAll(signatureDir, 0751); err != nil {
+ // The directory is allowed to exist
+ if !os.IsExist(err) {
+ return err
+ }
+ }
+ sigFilename, err := getSigFilename(signatureDir)
+ if err != nil {
+ return err
+ }
+ if err = ioutil.WriteFile(filepath.Join(signatureDir, sigFilename), newSig, 0644); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 600d64b1d..0c734d10d 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -244,15 +244,16 @@ func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (stri
}
// ManifestPush pushes a manifest list or image index to the destination
-func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts entities.ManifestPushOptions) error {
- listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0])
+func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination string, opts entities.ManifestPushOptions) error {
+ listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(name)
if err != nil {
- return errors.Wrapf(err, "error retrieving local image from image name %s", names[0])
+ return errors.Wrapf(err, "error retrieving local image from image name %s", name)
}
- dest, err := alltransports.ParseImageName(names[1])
+ dest, err := alltransports.ParseImageName(destination)
if err != nil {
return err
}
+
var manifestType string
if opts.Format != "" {
switch opts.Format {
@@ -267,8 +268,8 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts en
// Set the system context.
sys := ir.Libpod.SystemContext()
- if sys != nil {
- sys = &types.SystemContext{}
+ if sys == nil {
+ sys = new(types.SystemContext)
}
sys.AuthFilePath = opts.Authfile
sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
@@ -296,12 +297,12 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts en
if !opts.Quiet {
options.ReportWriter = os.Stderr
}
- digest, err := listImage.PushManifest(dest, options)
+ manDigest, err := listImage.PushManifest(dest, options)
if err == nil && opts.Purge {
_, err = ir.Libpod.GetStore().DeleteImage(listImage.ID(), true)
}
if opts.DigestFile != "" {
- if err = ioutil.WriteFile(opts.DigestFile, []byte(digest.String()), 0644); err != nil {
+ if err = ioutil.WriteFile(opts.DigestFile, []byte(manDigest.String()), 0644); err != nil {
return buildahUtil.GetFailureCause(err, errors.Wrapf(err, "failed to write digest to file %q", opts.DigestFile))
}
}
diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go
index 37568ea11..6a6380e33 100644
--- a/pkg/domain/infra/abi/parse/parse.go
+++ b/pkg/domain/infra/abi/parse/parse.go
@@ -38,6 +38,9 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error)
}
logrus.Debugf("Removing uid= from options and adding WithVolumeUID for UID %d", intUID)
libpodOptions = append(libpodOptions, libpod.WithVolumeUID(intUID))
+ finalVal = append(finalVal, o)
+ // set option "UID": "$uid"
+ volumeOptions["UID"] = splitO[1]
case "gid":
if len(splitO) != 2 {
return nil, errors.Wrapf(define.ErrInvalidArg, "gid option must provide a GID")
@@ -48,6 +51,9 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error)
}
logrus.Debugf("Removing gid= from options and adding WithVolumeGID for GID %d", intGID)
libpodOptions = append(libpodOptions, libpod.WithVolumeGID(intGID))
+ finalVal = append(finalVal, o)
+ // set option "GID": "$gid"
+ volumeOptions["GID"] = splitO[1]
default:
finalVal = append(finalVal, o)
}
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 3aeb6a2ee..cbc74a2f2 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -212,8 +212,10 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
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 {
+ if tagged.Tag() == image.LatestTag && reference.Domain(named) != image.DefaultLocalRegistry {
pullPolicy = util.PullImageAlways
}
}
@@ -224,7 +226,19 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
return nil, err
}
- specGen, err := kube.ToSpecGen(ctx, container, container.Image, newImage, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths, ctrRestartPolicy)
+ specgenOpts := kube.CtrSpecGenOptions{
+ Container: container,
+ Image: newImage,
+ Volumes: volumes,
+ PodID: pod.ID(),
+ PodName: podName,
+ PodInfraID: podInfraID,
+ ConfigMaps: configMaps,
+ SeccompPaths: seccompPaths,
+ RestartPolicy: ctrRestartPolicy,
+ NetNSIsHost: p.NetNS.IsHost(),
+ }
+ specGen, err := kube.ToSpecGen(ctx, &specgenOpts)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 11374e513..f108b770c 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -5,8 +5,8 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/domain/entities"
+ dfilters "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/signal"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/containers/podman/v2/pkg/specgen/generate"
@@ -288,7 +288,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
filters := make([]libpod.PodFilter, 0, len(options.Filters))
for k, v := range options.Filters {
- f, err := lpfilters.GeneratePodFilterFunc(k, v)
+ f, err := dfilters.GeneratePodFilterFunc(k, v)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 7ed58092b..67c018122 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io/ioutil"
+ "net/url"
"os"
"os/exec"
"path/filepath"
@@ -15,6 +16,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/podman/v2/utils"
@@ -168,6 +170,8 @@ func checkInput() error { // nolint:deadcode,unused
// 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
+ reclaimedSpace := (uint64)(0)
found := true
for found {
found = false
@@ -179,51 +183,46 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
found = true
}
systemPruneReport.PodPruneReport = append(systemPruneReport.PodPruneReport, podPruneReport...)
- containerPruneReport, err := ic.pruneContainersHelper(nil)
+
+ // TODO: Figure out cleaner way to handle all of the different PruneOptions
+ containerPruneOptions := entities.ContainerPruneOptions{}
+ containerPruneOptions.Filters = (url.Values)(options.Filters)
+
+ containerPruneReports, err := ic.ContainerPrune(ctx, containerPruneOptions)
if err != nil {
return nil, err
}
- if len(containerPruneReport.ID) > 0 {
- found = true
- }
- if systemPruneReport.ContainerPruneReport == nil {
- systemPruneReport.ContainerPruneReport = containerPruneReport
- } else {
- for name, val := range containerPruneReport.ID {
- systemPruneReport.ContainerPruneReport.ID[name] = val
- }
+ 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]))
}
-
- results, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, nil)
+ imagePruneReports, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters)
+ reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(imagePruneReports)
if err != nil {
return nil, err
}
- if len(results) > 0 {
+ if len(imagePruneReports) > 0 {
found = true
}
- if systemPruneReport.ImagePruneReport == nil {
- systemPruneReport.ImagePruneReport = &entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
- } else {
- systemPruneReport.ImagePruneReport.Report.Id = append(systemPruneReport.ImagePruneReport.Report.Id, results...)
- }
+ systemPruneReport.ImagePruneReports = append(systemPruneReport.ImagePruneReports, imagePruneReports...)
if options.Volume {
- volumePruneReport, err := ic.pruneVolumesHelper(ctx)
+ volumePruneOptions := entities.VolumePruneOptions{}
+ volumePruneOptions.Filters = (url.Values)(options.Filters)
+ volumePruneReport, err := ic.VolumePrune(ctx, volumePruneOptions)
if err != nil {
return nil, err
}
if len(volumePruneReport) > 0 {
found = true
}
- systemPruneReport.VolumePruneReport = append(systemPruneReport.VolumePruneReport, volumePruneReport...)
+ reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(volumePruneReport)
+ systemPruneReport.VolumePruneReports = append(systemPruneReport.VolumePruneReports, volumePruneReport...)
}
}
+ systemPruneReport.ReclaimedSpace = reclaimedSpace
return systemPruneReport, nil
}
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index a7262f61b..3c9dd9fc0 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -6,6 +6,7 @@ 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/entities/reports"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
"github.com/pkg/errors"
@@ -127,23 +128,20 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
return reports, errs, nil
}
-func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- return ic.pruneVolumesHelper(ctx)
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*reports.PruneReport, error) {
+ filterFuncs, err := filters.GenerateVolumeFilters(options.Filters)
+ if err != nil {
+ return nil, err
+ }
+ return ic.pruneVolumesHelper(ctx, filterFuncs)
}
-func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- pruned, err := ic.Libpod.PruneVolumes(ctx)
+func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*reports.PruneReport, error) {
+ pruned, err := ic.Libpod.PruneVolumes(ctx, filterFuncs)
if err != nil {
return nil, err
}
- reports := make([]*entities.VolumePruneReport, 0, len(pruned))
- for k, v := range pruned {
- reports = append(reports, &entities.VolumePruneReport{
- Err: v,
- Id: k,
- })
- }
- return reports, nil
+ return pruned, nil
}
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go
index 3a64cb72a..a25d165c9 100644
--- a/pkg/domain/infra/runtime_abi.go
+++ b/pkg/domain/infra/runtime_abi.go
@@ -21,7 +21,7 @@ func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine,
return r, err
case entities.TunnelMode:
ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
- return &tunnel.ContainerEngine{ClientCxt: ctx}, err
+ return &tunnel.ContainerEngine{ClientCtx: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
@@ -34,7 +34,7 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error)
return r, err
case entities.TunnelMode:
ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
- return &tunnel.ImageEngine{ClientCxt: ctx}, err
+ return &tunnel.ImageEngine{ClientCtx: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
diff --git a/pkg/domain/infra/runtime_tunnel.go b/pkg/domain/infra/runtime_tunnel.go
index 6c85e837e..b8aefaa35 100644
--- a/pkg/domain/infra/runtime_tunnel.go
+++ b/pkg/domain/infra/runtime_tunnel.go
@@ -5,19 +5,39 @@ package infra
import (
"context"
"fmt"
+ "sync"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/tunnel"
)
+var (
+ connectionMutex = &sync.Mutex{}
+ connection *context.Context
+)
+
+func newConnection(uri string, identity string) (context.Context, error) {
+ connectionMutex.Lock()
+ defer connectionMutex.Unlock()
+
+ if connection == nil {
+ ctx, err := bindings.NewConnectionWithIdentity(context.Background(), uri, identity)
+ if err != nil {
+ return ctx, err
+ }
+ connection = &ctx
+ }
+ return *connection, nil
+}
+
func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine, error) {
switch facts.EngineMode {
case entities.ABIMode:
return nil, fmt.Errorf("direct runtime not supported")
case entities.TunnelMode:
- ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
- return &tunnel.ContainerEngine{ClientCxt: ctx}, err
+ ctx, err := newConnection(facts.URI, facts.Identity)
+ return &tunnel.ContainerEngine{ClientCtx: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
@@ -28,8 +48,8 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error)
case entities.ABIMode:
return nil, fmt.Errorf("direct image runtime not supported")
case entities.TunnelMode:
- ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity)
- return &tunnel.ImageEngine{ClientCxt: ctx}, err
+ ctx, err := newConnection(facts.URI, facts.Identity)
+ return &tunnel.ImageEngine{ClientCtx: ctx}, err
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index e65fef0a4..3366cb425 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -16,9 +16,9 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/events"
"github.com/containers/podman/v2/pkg/api/handlers"
- "github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/errorhandling"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/containers/podman/v2/pkg/util"
@@ -31,19 +31,20 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string,
}
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
- exists, err := containers.Exists(ic.ClientCxt, nameOrID, options.External)
+ exists, err := containers.Exists(ic.ClientCtx, nameOrID, options.External)
return &entities.BoolReport{Value: exists}, err
}
-func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
- cons, err := getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, opts entities.WaitOptions) ([]entities.WaitReport, error) {
+ cons, err := getContainersByContext(ic.ClientCtx, false, false, namesOrIds)
if err != nil {
return nil, err
}
responses := make([]entities.WaitReport, 0, len(cons))
+ options := new(containers.WaitOptions).WithCondition(opts.Condition)
for _, c := range cons {
response := entities.WaitReport{Id: c.ID}
- exitCode, err := containers.Wait(ic.ClientCxt, c.ID, &options.Condition)
+ exitCode, err := containers.Wait(ic.ClientCtx, c.ID, options)
if err != nil {
response.Error = err
} else {
@@ -55,34 +56,34 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
}
func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
- err := containers.Pause(ic.ClientCxt, c.ID)
+ err := containers.Pause(ic.ClientCtx, c.ID, nil)
reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
}
return reports, nil
}
func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
- err := containers.Unpause(ic.ClientCxt, c.ID)
+ err := containers.Unpause(ic.ClientCtx, c.ID, nil)
reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
}
return reports, nil
}
-func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
+func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, opts entities.StopOptions) ([]*entities.StopReport, error) {
reports := []*entities.StopReport{}
- for _, cidFile := range options.CIDFiles {
+ for _, cidFile := range opts.CIDFiles {
content, err := ioutil.ReadFile(cidFile)
if err != nil {
return nil, errors.Wrap(err, "error reading CIDFile")
@@ -90,19 +91,23 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
id := strings.Split(string(content), "\n")[0]
namesOrIds = append(namesOrIds, id)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, options.Ignore, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds)
if err != nil {
return nil, err
}
+ options := new(containers.StopOptions)
+ if to := opts.Timeout; to != nil {
+ options.WithTimeout(*to)
+ }
for _, c := range ctrs {
report := entities.StopReport{Id: c.ID}
- if err = containers.Stop(ic.ClientCxt, c.ID, options.Timeout); err != nil {
+ if err = containers.Stop(ic.ClientCtx, c.ID, options); err != nil {
// These first two are considered non-fatal under the right conditions
if errors.Cause(err).Error() == define.ErrCtrStopped.Error() {
logrus.Debugf("Container %s is already stopped", c.ID)
reports = append(reports, &report)
continue
- } else if options.All && errors.Cause(err).Error() == define.ErrCtrStateInvalid.Error() {
+ } else if opts.All && errors.Cause(err).Error() == define.ErrCtrStateInvalid.Error() {
logrus.Debugf("Container %s is not running, could not stop", c.ID)
reports = append(reports, &report)
continue
@@ -120,8 +125,16 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
return reports, nil
}
-func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, opts entities.KillOptions) ([]*entities.KillReport, error) {
+ for _, cidFile := range opts.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error reading CIDFile")
+ }
+ id := strings.Split(string(content), "\n")[0]
+ namesOrIds = append(namesOrIds, id)
+ }
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -129,40 +142,38 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
for _, c := range ctrs {
reports = append(reports, &entities.KillReport{
Id: c.ID,
- Err: containers.Kill(ic.ClientCxt, c.ID, options.Signal),
+ Err: containers.Kill(ic.ClientCtx, c.ID, opts.Signal, nil),
})
}
return reports, nil
}
-func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
+func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, opts entities.RestartOptions) ([]*entities.RestartReport, error) {
var (
reports = []*entities.RestartReport{}
- timeout *int
)
- if options.Timeout != nil {
- t := int(*options.Timeout)
- timeout = &t
+ options := new(containers.RestartOptions)
+ if to := opts.Timeout; to != nil {
+ options.WithTimeout(int(*to))
}
-
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, false, namesOrIds)
if err != nil {
return nil, err
}
for _, c := range ctrs {
- if options.Running && c.State != define.ContainerStateRunning.String() {
+ if opts.Running && c.State != define.ContainerStateRunning.String() {
continue
}
reports = append(reports, &entities.RestartReport{
Id: c.ID,
- Err: containers.Restart(ic.ClientCxt, c.ID, timeout),
+ Err: containers.Restart(ic.ClientCtx, c.ID, options),
})
}
return reports, nil
}
-func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
- for _, cidFile := range options.CIDFiles {
+func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*entities.RmReport, error) {
+ for _, cidFile := range opts.CIDFiles {
content, err := ioutil.ReadFile(cidFile)
if err != nil {
return nil, errors.Wrap(err, "error reading CIDFile")
@@ -170,32 +181,35 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
id := strings.Split(string(content), "\n")[0]
namesOrIds = append(namesOrIds, id)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, options.Ignore, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds)
if err != nil {
return nil, err
}
// TODO there is no endpoint for container eviction. Need to discuss
reports := make([]*entities.RmReport, 0, len(ctrs))
+ options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes)
for _, c := range ctrs {
reports = append(reports, &entities.RmReport{
Id: c.ID,
- Err: containers.Remove(ic.ClientCxt, c.ID, &options.Force, &options.Volumes),
+ Err: containers.Remove(ic.ClientCtx, c.ID, options),
})
}
return reports, nil
}
-func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
- return containers.Prune(ic.ClientCxt, options.Filters)
+func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
+ options := new(containers.PruneOptions).WithFilters(opts.Filters)
+ return containers.Prune(ic.ClientCtx, options)
}
-func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
+func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
var (
reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds))
errs = []error{}
)
+ options := new(containers.InspectOptions).WithSize(opts.Size)
for _, name := range namesOrIds {
- inspect, err := containers.Inspect(ic.ClientCxt, name, &options.Size)
+ inspect, err := containers.Inspect(ic.ClientCtx, name, options)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@@ -212,30 +226,30 @@ func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []st
return reports, errs, nil
}
-func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
+func (ic *ContainerEngine) ContainerTop(ctx context.Context, opts entities.TopOptions) (*entities.StringSliceReport, error) {
switch {
- case options.Latest:
+ case opts.Latest:
return nil, errors.New("latest is not supported")
- case options.NameOrID == "":
+ case opts.NameOrID == "":
return nil, errors.New("NameOrID must be specified")
}
-
- topOutput, err := containers.Top(ic.ClientCxt, options.NameOrID, options.Descriptors)
+ options := new(containers.TopOptions).WithDescriptors(opts.Descriptors)
+ topOutput, err := containers.Top(ic.ClientCtx, opts.NameOrID, options)
if err != nil {
return nil, err
}
return &entities.StringSliceReport{Value: topOutput}, nil
}
-func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, options entities.CommitOptions) (*entities.CommitReport, error) {
+func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string, opts entities.CommitOptions) (*entities.CommitReport, error) {
var (
repo string
tag = "latest"
)
- if len(options.ImageName) > 0 {
- ref, err := reference.Parse(options.ImageName)
+ if len(opts.ImageName) > 0 {
+ ref, err := reference.Parse(opts.ImageName)
if err != nil {
- return nil, errors.Wrapf(err, "error parsing reference %q", options.ImageName)
+ return nil, errors.Wrapf(err, "error parsing reference %q", opts.ImageName)
}
if t, ok := ref.(reference.Tagged); ok {
tag = t.Tag()
@@ -244,19 +258,12 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
repo = r.Name()
}
if len(repo) < 1 {
- return nil, errors.Errorf("invalid image name %q", options.ImageName)
+ return nil, errors.Errorf("invalid image name %q", opts.ImageName)
}
}
- commitOpts := containers.CommitOptions{
- Author: &options.Author,
- Changes: options.Changes,
- Comment: &options.Message,
- Format: &options.Format,
- Pause: &options.Pause,
- Repo: &repo,
- Tag: &tag,
- }
- response, err := containers.Commit(ic.ClientCxt, nameOrID, commitOpts)
+ options := new(containers.CommitOptions).WithAuthor(opts.Author).WithChanges(opts.Changes).WithComment(opts.Message)
+ options.WithFormat(opts.Format).WithPause(opts.Pause).WithRepo(repo).WithTag(tag)
+ response, err := containers.Commit(ic.ClientCtx, nameOrID, options)
if err != nil {
return nil, err
}
@@ -274,17 +281,17 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string,
return err
}
}
- return containers.Export(ic.ClientCxt, nameOrID, w)
+ return containers.Export(ic.ClientCtx, nameOrID, w, nil)
}
-func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
+func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, opts entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
var (
err error
ctrs = []entities.ListContainer{}
)
- if options.All {
- allCtrs, err := getContainersByContext(ic.ClientCxt, true, false, []string{})
+ if opts.All {
+ allCtrs, err := getContainersByContext(ic.ClientCtx, true, false, []string{})
if err != nil {
return nil, err
}
@@ -296,14 +303,16 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
}
} else {
- ctrs, err = getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+ ctrs, err = getContainersByContext(ic.ClientCtx, false, false, namesOrIds)
if err != nil {
return nil, err
}
}
reports := make([]*entities.CheckpointReport, 0, len(ctrs))
+ options := new(containers.CheckpointOptions).WithExport(opts.Export).WithIgnoreRootfs(opts.IgnoreRootFS).WithKeep(opts.Keep)
+ options.WithLeaveRunning(opts.LeaveRunning).WithTCPEstablished(opts.TCPEstablished)
for _, c := range ctrs {
- report, err := containers.Checkpoint(ic.ClientCxt, c.ID, &options.Keep, &options.LeaveRunning, &options.TCPEstablished, &options.IgnoreRootFS, &options.Export)
+ report, err := containers.Checkpoint(ic.ClientCtx, c.ID, options)
if err != nil {
reports = append(reports, &entities.CheckpointReport{Id: c.ID, Err: err})
}
@@ -312,13 +321,13 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
return reports, nil
}
-func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) {
+func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, opts entities.RestoreOptions) ([]*entities.RestoreReport, error) {
var (
err error
ctrs = []entities.ListContainer{}
)
- if options.All {
- allCtrs, err := getContainersByContext(ic.ClientCxt, true, false, []string{})
+ if opts.All {
+ allCtrs, err := getContainersByContext(ic.ClientCtx, true, false, []string{})
if err != nil {
return nil, err
}
@@ -330,14 +339,15 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
}
} else {
- ctrs, err = getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+ ctrs, err = getContainersByContext(ic.ClientCtx, false, false, namesOrIds)
if err != nil {
return nil, err
}
}
reports := make([]*entities.RestoreReport, 0, len(ctrs))
+ options := new(containers.RestoreOptions)
for _, c := range ctrs {
- report, err := containers.Restore(ic.ClientCxt, c.ID, &options.Keep, &options.TCPEstablished, &options.IgnoreRootFS, &options.IgnoreStaticIP, &options.IgnoreStaticMAC, &options.Name, &options.Import)
+ report, err := containers.Restore(ic.ClientCtx, c.ID, options)
if err != nil {
reports = append(reports, &entities.RestoreReport{Id: c.ID, Err: err})
}
@@ -347,7 +357,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*entities.ContainerCreateReport, error) {
- response, err := containers.CreateWithSpec(ic.ClientCxt, s)
+ response, err := containers.CreateWithSpec(ic.ClientCtx, s, nil)
if err != nil {
return nil, err
}
@@ -357,25 +367,20 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
return &entities.ContainerCreateReport{Id: response.ID}, nil
}
-func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string, options entities.ContainerLogsOptions) error {
- since := options.Since.Format(time.RFC3339)
- tail := strconv.FormatInt(options.Tail, 10)
- stdout := options.Writer != nil
- opts := containers.LogOptions{
- Follow: &options.Follow,
- Since: &since,
- Stderr: &stdout,
- Stdout: &stdout,
- Tail: &tail,
- Timestamps: &options.Timestamps,
- Until: nil,
- }
+func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string, opts entities.ContainerLogsOptions) error {
+ since := opts.Since.Format(time.RFC3339)
+ tail := strconv.FormatInt(opts.Tail, 10)
+ stdout := opts.StdoutWriter != nil
+ stderr := opts.StderrWriter != nil
+ options := new(containers.LogOptions).WithFollow(opts.Follow).WithSince(since).WithStderr(stderr)
+ options.WithStdout(stdout).WithTail(tail)
var err error
- outCh := make(chan string)
+ stdoutCh := make(chan string)
+ stderrCh := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
go func() {
- err = containers.Logs(ic.ClientCxt, nameOrIDs[0], opts, outCh, outCh)
+ err = containers.Logs(ic.ClientCtx, nameOrIDs[0], options, stdoutCh, stderrCh)
cancel()
}()
@@ -383,14 +388,20 @@ func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string,
select {
case <-ctx.Done():
return err
- case line := <-outCh:
- _, _ = io.WriteString(options.Writer, line+"\n")
+ case line := <-stdoutCh:
+ if opts.StdoutWriter != nil {
+ _, _ = io.WriteString(opts.StdoutWriter, line+"\n")
+ }
+ case line := <-stderrCh:
+ if opts.StderrWriter != nil {
+ _, _ = io.WriteString(opts.StderrWriter, line+"\n")
+ }
}
}
}
-func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, options entities.AttachOptions) error {
- ctrs, err := getContainersByContext(ic.ClientCxt, false, false, []string{nameOrID})
+func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, opts entities.AttachOptions) error {
+ ctrs, err := getContainersByContext(ic.ClientCtx, false, false, []string{nameOrID})
if err != nil {
return err
}
@@ -398,8 +409,8 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string,
if ctr.State != define.ContainerStateRunning.String() {
return errors.Errorf("you can only attach to running containers")
}
-
- return containers.Attach(ic.ClientCxt, nameOrID, &options.DetachKeys, nil, bindings.PTrue, options.Stdin, options.Stdout, options.Stderr, nil)
+ options := new(containers.AttachOptions).WithStream(true).WithDetachKeys(opts.DetachKeys)
+ return containers.Attach(ic.ClientCtx, nameOrID, opts.Stdin, opts.Stdout, opts.Stderr, nil, options)
}
func makeExecConfig(options entities.ExecOptions) *handlers.ExecCreateConfig {
@@ -427,16 +438,21 @@ func makeExecConfig(options entities.ExecOptions) *handlers.ExecCreateConfig {
func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
createConfig := makeExecConfig(options)
- sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrID, createConfig)
+ sessionID, err := containers.ExecCreate(ic.ClientCtx, nameOrID, createConfig)
if err != nil {
return 125, err
}
-
- if err := containers.ExecStartAndAttach(ic.ClientCxt, sessionID, &streams); err != nil {
+ startAndAttachOptions := new(containers.ExecStartAndAttachOptions)
+ startAndAttachOptions.WithOutputStream(streams.OutputStream).WithErrorStream(streams.ErrorStream)
+ if streams.InputStream != nil {
+ startAndAttachOptions.WithInputStream(*streams.InputStream)
+ }
+ startAndAttachOptions.WithAttachError(streams.AttachError).WithAttachOutput(streams.AttachOutput).WithAttachInput(streams.AttachInput)
+ if err := containers.ExecStartAndAttach(ic.ClientCtx, sessionID, startAndAttachOptions); err != nil {
return 125, err
}
- inspectOut, err := containers.ExecInspect(ic.ClientCxt, sessionID)
+ inspectOut, err := containers.ExecInspect(ic.ClientCtx, sessionID, nil)
if err != nil {
return 125, err
}
@@ -447,12 +463,12 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, o
func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
createConfig := makeExecConfig(options)
- sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrID, createConfig)
+ sessionID, err := containers.ExecCreate(ic.ClientCtx, nameOrID, createConfig)
if err != nil {
return "", err
}
- if err := containers.ExecStart(ic.ClientCxt, sessionID); err != nil {
+ if err := containers.ExecStart(ic.ClientCtx, sessionID, nil); err != nil {
return "", err
}
@@ -462,15 +478,23 @@ func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID s
func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input, output, errput *os.File) error { //nolint
attachErr := make(chan error)
attachReady := make(chan bool)
+ options := new(containers.AttachOptions).WithStream(true)
+ if dk := detachKeys; dk != nil {
+ options.WithDetachKeys(*dk)
+ }
go func() {
- err := containers.Attach(ic.ClientCxt, name, detachKeys, bindings.PFalse, bindings.PTrue, input, output, errput, attachReady)
+ err := containers.Attach(ic.ClientCtx, name, input, output, errput, attachReady, options)
attachErr <- err
}()
// Wait for the attach to actually happen before starting
// the container.
select {
case <-attachReady:
- if err := containers.Start(ic.ClientCxt, name, detachKeys); err != nil {
+ startOptions := new(containers.StartOptions)
+ if dk := detachKeys; dk != nil {
+ startOptions.WithDetachKeys(*dk)
+ }
+ if err := containers.Start(ic.ClientCtx, name, startOptions); err != nil {
return err
}
case err := <-attachErr:
@@ -483,10 +507,11 @@ func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input,
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
reports := []*entities.ContainerStartReport{}
var exitCode = define.ExecErrorCodeGeneric
- ctrs, err := getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, false, false, namesOrIds)
if err != nil {
return nil, err
}
+ removeOptions := new(containers.RemoveOptions).WithVolumes(true).WithForce(false)
// There can only be one container if attach was used
for i, ctr := range ctrs {
name := ctr.ID
@@ -515,7 +540,30 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
reports = append(reports, &report)
return reports, errors.Wrapf(report.Err, "unable to start container %s", name)
}
- exitCode, err := containers.Wait(ic.ClientCxt, name, nil)
+ if ctr.AutoRemove {
+ // Defer the removal, so we can return early if needed and
+ // de-spaghetti the code.
+ defer func() {
+ shouldRestart, err := containers.ShouldRestart(ic.ClientCtx, ctr.ID, nil)
+ if err != nil {
+ logrus.Errorf("Failed to check if %s should restart: %v", ctr.ID, err)
+ return
+ }
+
+ if !shouldRestart {
+ if err := containers.Remove(ic.ClientCtx, ctr.ID, removeOptions); err != nil {
+ if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
+ errorhandling.Contains(err, define.ErrCtrRemoved) {
+ logrus.Warnf("Container %s does not exist: %v", ctr.ID, err)
+ } else {
+ logrus.Errorf("Error removing container %s: %v", ctr.ID, err)
+ }
+ }
+ }
+ }()
+ }
+
+ exitCode, err := containers.Wait(ic.ClientCtx, name, nil)
if err == define.ErrNoSuchCtr {
// Check events
event, err := ic.GetLastContainerEvent(ctx, name, events.Exited)
@@ -533,8 +581,20 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
}
// Start the container if it's not running already.
if !ctrRunning {
- err = containers.Start(ic.ClientCxt, name, &options.DetachKeys)
+
+ err = containers.Start(ic.ClientCtx, name, new(containers.StartOptions).WithDetachKeys(options.DetachKeys))
if err != nil {
+ if ctr.AutoRemove {
+ rmOptions := new(containers.RemoveOptions).WithForce(false).WithVolumes(true)
+ if err := containers.Remove(ic.ClientCtx, ctr.ID, rmOptions); err != nil {
+ if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
+ errorhandling.Contains(err, define.ErrCtrRemoved) {
+ logrus.Warnf("Container %s does not exist: %v", ctr.ID, err)
+ } else {
+ logrus.Errorf("Error removing container %s: %v", ctr.ID, err)
+ }
+ }
+ }
report.Err = errors.Wrapf(err, "unable to start container %q", name)
report.ExitCode = define.ExitCode(err)
reports = append(reports, &report)
@@ -547,12 +607,14 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
return reports, nil
}
-func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
- return containers.List(ic.ClientCxt, options.Filters, &options.All, &options.Last, &options.Namespace, &options.Size, &options.Sync)
+func (ic *ContainerEngine) ContainerList(ctx context.Context, opts entities.ContainerListOptions) ([]entities.ListContainer, error) {
+ options := new(containers.ListOptions).WithFilters(opts.Filters).WithAll(opts.All).WithLast(opts.Last)
+ options.WithNamespace(opts.Namespace).WithSize(opts.Size).WithSync(opts.Sync)
+ return containers.List(ic.ClientCtx, options)
}
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
- con, err := containers.CreateWithSpec(ic.ClientCxt, opts.Spec)
+ con, err := containers.CreateWithSpec(ic.ClientCtx, opts.Spec, nil)
if err != nil {
return nil, err
}
@@ -569,7 +631,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
if opts.Detach {
// Detach and return early
- err := containers.Start(ic.ClientCxt, con.ID, nil)
+ err := containers.Start(ic.ClientCtx, con.ID, nil)
if err != nil {
report.ExitCode = define.ExitCode(err)
}
@@ -584,7 +646,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
report.ExitCode = define.ExitCode(err)
if opts.Rm {
- if rmErr := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); rmErr != nil {
+ if rmErr := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)); rmErr != nil {
logrus.Debugf("unable to remove container %s after failing to start and attach to it", con.ID)
}
}
@@ -595,14 +657,14 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
// Defer the removal, so we can return early if needed and
// de-spaghetti the code.
defer func() {
- shouldRestart, err := containers.ShouldRestart(ic.ClientCxt, con.ID)
+ shouldRestart, err := containers.ShouldRestart(ic.ClientCtx, con.ID, nil)
if err != nil {
logrus.Errorf("Failed to check if %s should restart: %v", con.ID, err)
return
}
if !shouldRestart {
- if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
+ if err := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)); err != nil {
if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
errorhandling.Contains(err, define.ErrCtrRemoved) {
logrus.Warnf("Container %s does not exist: %v", con.ID, err)
@@ -615,7 +677,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
}
// Wait
- exitCode, waitErr := containers.Wait(ic.ClientCxt, con.ID, nil)
+ exitCode, waitErr := containers.Wait(ic.ClientCtx, con.ID, nil)
if waitErr == nil {
report.ExitCode = int(exitCode)
return &report, nil
@@ -664,7 +726,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
}
func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
- changes, err := containers.Diff(ic.ClientCxt, nameOrID)
+ changes, err := containers.Diff(ic.ClientCtx, nameOrID, nil)
return &entities.DiffReport{Changes: changes}, err
}
@@ -673,13 +735,13 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.ContainerInitReport, 0, len(ctrs))
for _, ctr := range ctrs {
- err := containers.ContainerInit(ic.ClientCxt, ctr.ID)
+ err := containers.ContainerInit(ic.ClientCtx, ctr.ID, nil)
// When using all, it is NOT considered an error if a container
// has already been init'd.
if err != nil && options.All && strings.Contains(errors.Cause(err).Error(), define.ErrCtrStateInvalid.Error()) {
@@ -713,7 +775,7 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o
if len(nameOrID) > 0 {
namesOrIds = append(namesOrIds, nameOrID)
}
- ctrs, err := getContainersByContext(ic.ClientCxt, options.All, false, namesOrIds)
+ ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
@@ -731,9 +793,16 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o
return reports, nil
}
-func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error {
- return nil
- // return containers.Copy(ic.ClientCxt, source, dest, options)
+func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrID string, path string, reader io.Reader) (entities.ContainerCopyFunc, error) {
+ return containers.CopyFromArchive(ic.ClientCtx, nameOrID, path, reader)
+}
+
+func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (entities.ContainerCopyFunc, error) {
+ return containers.CopyToArchive(ic.ClientCtx, nameOrID, path, writer)
+}
+
+func (ic *ContainerEngine) ContainerStat(ctx context.Context, nameOrID string, path string) (*entities.ContainerStatReport, error) {
+ return containers.Stat(ic.ClientCtx, nameOrID, path)
}
// Shutdown Libpod engine
@@ -744,10 +813,10 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
if options.Latest {
return nil, errors.New("latest is not supported for the remote client")
}
- return containers.Stats(ic.ClientCxt, namesOrIds, &options.Stream)
+ return containers.Stats(ic.ClientCtx, namesOrIds, new(containers.StatsOptions).WithStream(options.Stream))
}
-// ShouldRestart reports back whether the containre will restart
+// ShouldRestart reports back whether the container will restart
func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
- return containers.ShouldRestart(ic.ClientCxt, id)
+ return containers.ShouldRestart(ic.ClientCtx, id, nil)
}
diff --git a/pkg/domain/infra/tunnel/events.go b/pkg/domain/infra/tunnel/events.go
index 53bae6cef..cec6c749c 100644
--- a/pkg/domain/infra/tunnel/events.go
+++ b/pkg/domain/infra/tunnel/events.go
@@ -2,7 +2,6 @@ package tunnel
import (
"context"
- // "fmt"
"strings"
"github.com/containers/podman/v2/libpod/events"
@@ -29,7 +28,8 @@ func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptio
}
close(opts.EventChan)
}()
- return system.Events(ic.ClientCxt, binChan, nil, &opts.Since, &opts.Until, filters, &opts.Stream)
+ options := new(system.EventsOptions).WithFilters(filters).WithSince(opts.Since).WithStream(opts.Stream).WithUntil(opts.Until)
+ return system.Events(ic.ClientCtx, binChan, nil, options)
}
// GetLastContainerEvent takes a container name or ID and an event status and returns
diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go
index ebbfa143f..6d68157c1 100644
--- a/pkg/domain/infra/tunnel/generate.go
+++ b/pkg/domain/infra/tunnel/generate.go
@@ -7,10 +7,16 @@ import (
"github.com/containers/podman/v2/pkg/domain/entities"
)
-func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
- return generate.Systemd(ic.ClientCxt, nameOrID, options)
+func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, opts entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
+ options := new(generate.SystemdOptions).WithUseName(opts.Name).WithContainerPrefix(opts.ContainerPrefix).WithNew(opts.New)
+ options.WithPodPrefix(opts.PodPrefix).WithRestartPolicy(opts.RestartPolicy).WithSeparator(opts.Separator)
+ if to := opts.StopTimeout; to != nil {
+ options.WithStopTimeout(*opts.StopTimeout)
+ }
+ return generate.Systemd(ic.ClientCtx, nameOrID, options)
}
-func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
- return generate.Kube(ic.ClientCxt, nameOrIDs, options)
+func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, opts entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+ options := new(generate.KubeOptions).WithService(opts.Service)
+ return generate.Kube(ic.ClientCtx, nameOrIDs, options)
}
diff --git a/pkg/domain/infra/tunnel/healthcheck.go b/pkg/domain/infra/tunnel/healthcheck.go
index ac28712ce..3daf22647 100644
--- a/pkg/domain/infra/tunnel/healthcheck.go
+++ b/pkg/domain/infra/tunnel/healthcheck.go
@@ -9,5 +9,5 @@ import (
)
func (ic *ContainerEngine) HealthCheckRun(ctx context.Context, nameOrID string, options entities.HealthCheckOptions) (*define.HealthCheckResults, error) {
- return containers.RunHealthCheck(ic.ClientCxt, nameOrID)
+ return containers.RunHealthCheck(ic.ClientCtx, nameOrID, nil)
}
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index 63f9546be..0a806d860 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -4,7 +4,6 @@ import (
"context"
"github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/pods"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -18,8 +17,8 @@ func getContainersByContext(contextWithConnection context.Context, all, ignore b
if all && len(namesOrIDs) > 0 {
return nil, errors.New("cannot lookup containers and all")
}
-
- allContainers, err := containers.List(contextWithConnection, nil, bindings.PTrue, nil, nil, nil, bindings.PTrue)
+ options := new(containers.ListOptions).WithAll(true).WithSync(true)
+ allContainers, err := containers.List(contextWithConnection, options)
if err != nil {
return nil, err
}
@@ -38,7 +37,7 @@ func getContainersByContext(contextWithConnection context.Context, all, ignore b
// First determine if the container exists by doing an inspect.
// Inspect takes supports names and IDs and let's us determine
// a containers full ID.
- inspectData, err := containers.Inspect(contextWithConnection, nameOrID, bindings.PFalse)
+ inspectData, err := containers.Inspect(contextWithConnection, nameOrID, new(containers.InspectOptions).WithSize(false))
if err != nil {
if ignore && errorhandling.Contains(err, define.ErrNoSuchCtr) {
continue
@@ -90,7 +89,7 @@ func getPodsByContext(contextWithConnection context.Context, all bool, namesOrID
// First determine if the pod exists by doing an inspect.
// Inspect takes supports names and IDs and let's us determine
// a containers full ID.
- inspectData, err := pods.Inspect(contextWithConnection, nameOrID)
+ inspectData, err := pods.Inspect(contextWithConnection, nameOrID, nil)
if err != nil {
if errorhandling.Contains(err, define.ErrNoSuchPod) {
return nil, errors.Wrapf(define.ErrNoSuchPod, "unable to find pod %q", nameOrID)
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 09931de12..fba60235e 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -4,25 +4,32 @@ import (
"context"
"io/ioutil"
"os"
+ "strconv"
"strings"
"time"
+ "github.com/containers/podman/v2/libpod/image"
+
+ "github.com/containers/image/v5/types"
+
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
images "github.com/containers/podman/v2/pkg/bindings/images"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/domain/utils"
utils2 "github.com/containers/podman/v2/utils"
"github.com/pkg/errors"
)
func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
- found, err := images.Exists(ir.ClientCxt, nameOrID)
+ found, err := images.Exists(ir.ClientCtx, nameOrID)
return &entities.BoolReport{Value: found}, err
}
func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) {
- return images.BatchRemove(ir.ClientCxt, imagesArg, opts)
+ options := new(images.RemoveOptions).WithForce(opts.Force).WithAll(opts.All)
+ return images.Remove(ir.ClientCtx, imagesArg, options)
}
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
@@ -32,13 +39,14 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
f := strings.Split(filter, "=")
filters[f[0]] = f[1:]
}
- images, err := images.List(ir.ClientCxt, &opts.All, filters)
+ options := new(images.ListOptions).WithAll(opts.All).WithFilters(filters)
+ psImages, err := images.List(ir.ClientCtx, options)
if err != nil {
return nil, err
}
- is := make([]*entities.ImageSummary, len(images))
- for i, img := range images {
+ is := make([]*entities.ImageSummary, len(psImages))
+ for i, img := range psImages {
hold := entities.ImageSummary{}
if err := utils.DeepCopy(&hold, img); err != nil {
return nil, err
@@ -57,7 +65,8 @@ func (ir *ImageEngine) Unmount(ctx context.Context, images []string, options ent
}
func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
- results, err := images.History(ir.ClientCxt, nameOrID)
+ options := new(images.HistoryOptions)
+ results, err := images.History(ir.ClientCtx, nameOrID, options)
if err != nil {
return nil, err
}
@@ -82,37 +91,41 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entiti
return &history, nil
}
-func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
+func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
filters := make(map[string][]string, len(opts.Filter))
for _, filter := range opts.Filter {
f := strings.Split(filter, "=")
filters[f[0]] = f[1:]
}
-
- results, err := images.Prune(ir.ClientCxt, &opts.All, filters)
+ options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters)
+ reports, err := images.Prune(ir.ClientCtx, options)
if err != nil {
return nil, err
}
-
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- Size: 0,
- }
- return &report, nil
+ return reports, nil
}
-func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) {
- pulledImages, err := images.Pull(ir.ClientCxt, rawImage, options)
+func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.ImagePullOptions) (*entities.ImagePullReport, error) {
+ options := new(images.PullOptions)
+ options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithCertDir(opts.CertDir).WithOverrideArch(opts.OverrideArch).WithOverrideOS(opts.OverrideOS)
+ options.WithOverrideVariant(opts.OverrideVariant).WithPassword(opts.Password).WithPullPolicy(opts.PullPolicy)
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ if s == types.OptionalBoolTrue {
+ options.WithSkipTLSVerify(true)
+ } else {
+ options.WithSkipTLSVerify(false)
+ }
+ }
+ options.WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithUsername(opts.Username)
+ pulledImages, err := images.Pull(ir.ClientCtx, rawImage, options)
if err != nil {
return nil, err
}
return &entities.ImagePullReport{Images: pulledImages}, nil
}
-func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
+func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageTagOptions) error {
+ options := new(images.TagOptions)
for _, newTag := range tags {
var (
tag, repo string
@@ -130,16 +143,17 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string,
if len(repo) < 1 {
return errors.Errorf("invalid image name %q", nameOrID)
}
- if err := images.Tag(ir.ClientCxt, nameOrID, tag, repo); err != nil {
+ if err := images.Tag(ir.ClientCtx, nameOrID, tag, repo, options); err != nil {
return err
}
}
return nil
}
-func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error {
+func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageUntagOptions) error {
+ options := new(images.UntagOptions)
if len(tags) == 0 {
- return images.Untag(ir.ClientCxt, nameOrID, "", "")
+ return images.Untag(ir.ClientCtx, nameOrID, "", "", options)
}
for _, newTag := range tags {
@@ -159,7 +173,7 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
if len(repo) < 1 {
return errors.Errorf("invalid image name %q", nameOrID)
}
- if err := images.Untag(ir.ClientCxt, nameOrID, tag, repo); err != nil {
+ if err := images.Untag(ir.ClientCtx, nameOrID, tag, repo, options); err != nil {
return err
}
}
@@ -167,10 +181,11 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
}
func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) {
+ options := new(images.GetOptions).WithSize(opts.Size)
reports := []*entities.ImageInspectReport{}
errs := []error{}
for _, i := range namesOrIDs {
- r, err := images.GetImage(ir.ClientCxt, i, &opts.Size)
+ r, err := images.GetImage(ir.ClientCtx, i, options)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@@ -204,68 +219,73 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions)
if len(opts.Tag) > 0 {
ref += ":" + opts.Tag
}
- return images.Load(ir.ClientCxt, f, &ref)
+ options := new(images.LoadOptions).WithReference(ref)
+ return images.Load(ir.ClientCtx, f, options)
}
func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOptions) (*entities.ImageImportReport, error) {
var (
- err error
- sourceURL *string
- f *os.File
+ err error
+ f *os.File
)
+ options := new(images.ImportOptions).WithChanges(opts.Changes).WithMessage(opts.Message).WithReference(opts.Reference)
if opts.SourceIsURL {
- sourceURL = &opts.Source
+ options.WithURL(opts.Source)
} else {
f, err = os.Open(opts.Source)
if err != nil {
return nil, err
}
}
- return images.Import(ir.ClientCxt, opts.Changes, &opts.Message, &opts.Reference, sourceURL, f)
+ return images.Import(ir.ClientCtx, f, options)
}
-func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
- return images.Push(ir.ClientCxt, source, destination, options)
+func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, opts entities.ImagePushOptions) error {
+ options := new(images.PushOptions)
+ options.WithUsername(opts.Username).WithSignaturePolicy(opts.SignaturePolicy).WithQuiet(opts.Quiet)
+ options.WithPassword(opts.Password).WithCertDir(opts.CertDir).WithAuthfile(opts.Authfile)
+ options.WithCompress(opts.Compress).WithDigestFile(opts.DigestFile).WithFormat(opts.Format)
+ options.WithRemoveSignatures(opts.RemoveSignatures).WithSignBy(opts.SignBy)
+
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ if s == types.OptionalBoolTrue {
+ options.WithSkipTLSVerify(true)
+ } else {
+ options.WithSkipTLSVerify(false)
+ }
+ }
+ return images.Push(ir.ClientCtx, source, destination, options)
}
-func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error {
+func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, opts entities.ImageSaveOptions) error {
var (
f *os.File
err error
)
- switch options.Format {
+ options := new(images.ExportOptions).WithFormat(opts.Format).WithCompress(opts.Compress)
+
+ switch opts.Format {
case "oci-dir", "docker-dir":
f, err = ioutil.TempFile("", "podman_save")
if err == nil {
defer func() { _ = os.Remove(f.Name()) }()
}
default:
- f, err = os.Create(options.Output)
+ f, err = os.Create(opts.Output)
}
if err != nil {
return err
}
- if options.MultiImageArchive {
- exErr := images.MultiExport(ir.ClientCxt, append([]string{nameOrID}, tags...), f, &options.Format, &options.Compress)
- if err := f.Close(); err != nil {
- return err
- }
- if exErr != nil {
- return exErr
- }
- } else {
- // FIXME: tags are entirely ignored here but shouldn't.
- exErr := images.Export(ir.ClientCxt, nameOrID, f, &options.Format, &options.Compress)
- if err := f.Close(); err != nil {
- return err
- }
- if exErr != nil {
- return exErr
- }
+ exErr := images.Export(ir.ClientCtx, append([]string{nameOrID}, tags...), f, options)
+ if err := f.Close(); err != nil {
+ return err
+ }
+ if exErr != nil {
+ return exErr
}
- if options.Format != "oci-dir" && options.Format != "docker-dir" {
+ if opts.Format != "oci-dir" && opts.Format != "docker-dir" {
return nil
}
@@ -273,25 +293,26 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string,
if err != nil {
return err
}
- info, err := os.Stat(options.Output)
+ info, err := os.Stat(opts.Output)
switch {
case err == nil:
if info.Mode().IsRegular() {
- return errors.Errorf("%q already exists as a regular file", options.Output)
+ return errors.Errorf("%q already exists as a regular file", opts.Output)
}
case os.IsNotExist(err):
- if err := os.Mkdir(options.Output, 0755); err != nil {
+ if err := os.Mkdir(opts.Output, 0755); err != nil {
return err
}
default:
return err
}
- return utils2.UntarToFileSystem(options.Output, f, nil)
+ return utils2.UntarToFileSystem(opts.Output, f, nil)
}
// Diff reports the changes to the given image
func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
- changes, err := images.Diff(ir.ClientCxt, nameOrID)
+ options := new(images.DiffOptions)
+ changes, err := images.Diff(ir.ClientCtx, nameOrID, options)
if err != nil {
return nil, err
}
@@ -299,7 +320,34 @@ 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) {
- return images.Search(ir.ClientCxt, term, opts)
+ mappedFilters := make(map[string][]string)
+ filters, err := image.ParseSearchFilter(opts.Filters)
+ if err != nil {
+ return nil, err
+ }
+ if stars := filters.Stars; stars > 0 {
+ mappedFilters["stars"] = []string{strconv.Itoa(stars)}
+ }
+
+ if official := filters.IsOfficial; official != types.OptionalBoolUndefined {
+ mappedFilters["is-official"] = []string{strconv.FormatBool(official == types.OptionalBoolTrue)}
+ }
+
+ if automated := filters.IsAutomated; automated != types.OptionalBoolUndefined {
+ mappedFilters["is-automated"] = []string{strconv.FormatBool(automated == types.OptionalBoolTrue)}
+ }
+
+ options := new(images.SearchOptions)
+ options.WithAuthfile(opts.Authfile).WithFilters(mappedFilters).WithLimit(opts.Limit)
+ options.WithListTags(opts.ListTags).WithNoTrunc(opts.NoTrunc)
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ if s == types.OptionalBoolTrue {
+ options.WithSkipTLSVerify(true)
+ } else {
+ options.WithSkipTLSVerify(false)
+ }
+ }
+ return images.Search(ir.ClientCtx, term, options)
}
func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
@@ -307,7 +355,7 @@ func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
}
func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) {
- report, err := images.Build(ir.ClientCxt, containerFiles, opts)
+ report, err := images.Build(ir.ClientCtx, containerFiles, opts)
if err != nil {
return nil, err
}
@@ -326,7 +374,8 @@ func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts en
}
func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
- return images.Tree(ir.ClientCxt, nameOrID, &opts.WhatRequires)
+ options := new(images.TreeOptions).WithWhatRequires(opts.WhatRequires)
+ return images.Tree(ir.ClientCtx, nameOrID, options)
}
// Shutdown Libpod engine
diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go
index a09b502b4..c71349fe0 100644
--- a/pkg/domain/infra/tunnel/manifest.go
+++ b/pkg/domain/infra/tunnel/manifest.go
@@ -6,7 +6,6 @@ import (
"fmt"
"strings"
- "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/bindings/manifests"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
@@ -14,7 +13,8 @@ import (
// ManifestCreate implements manifest create via ImageEngine
func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []string, opts entities.ManifestCreateOptions) (string, error) {
- imageID, err := manifests.Create(ir.ClientCxt, names, images, &opts.All)
+ options := new(manifests.CreateOptions).WithAll(opts.All)
+ imageID, err := manifests.Create(ir.ClientCtx, names, images, options)
if err != nil {
return imageID, errors.Wrapf(err, "error creating manifest")
}
@@ -23,7 +23,7 @@ func (ir *ImageEngine) ManifestCreate(ctx context.Context, names, images []strin
// ManifestInspect returns contents of manifest list with given name
func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte, error) {
- list, err := manifests.Inspect(ir.ClientCxt, name)
+ list, err := manifests.Inspect(ir.ClientCtx, name, nil)
if err != nil {
return nil, errors.Wrapf(err, "error getting content of manifest list or image %s", name)
}
@@ -37,15 +37,8 @@ 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) {
- manifestAddOpts := image.ManifestAddOpts{
- All: opts.All,
- Arch: opts.Arch,
- Features: opts.Features,
- Images: opts.Images,
- OS: opts.OS,
- OSVersion: opts.OSVersion,
- Variant: opts.Variant,
- }
+ options := new(manifests.AddOptions).WithAll(opts.All).WithArch(opts.Arch).WithVariant(opts.Variant)
+ options.WithFeatures(opts.Features).WithImages(opts.Images).WithOS(opts.OS).WithOSVersion(opts.OSVersion)
if len(opts.Annotation) != 0 {
annotations := make(map[string]string)
for _, annotationSpec := range opts.Annotation {
@@ -55,9 +48,10 @@ func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAd
}
annotations[spec[0]] = spec[1]
}
- manifestAddOpts.Annotation = annotations
+ options.WithAnnotation(annotations)
}
- listID, err := manifests.Add(ir.ClientCxt, opts.Images[1], manifestAddOpts)
+
+ listID, err := manifests.Add(ir.ClientCtx, opts.Images[1], options)
if err != nil {
return listID, errors.Wrapf(err, "error adding to manifest list %s", opts.Images[1])
}
@@ -71,7 +65,7 @@ func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opt
// ManifestRemove removes the digest from manifest list
func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (string, error) {
- updatedListID, err := manifests.Remove(ir.ClientCxt, names[0], names[1])
+ updatedListID, err := manifests.Remove(ir.ClientCtx, names[0], names[1], nil)
if err != nil {
return updatedListID, errors.Wrapf(err, "error removing from manifest %s", names[0])
}
@@ -79,7 +73,8 @@ func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (stri
}
// ManifestPush pushes a manifest list or image index to the destination
-func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts entities.ManifestPushOptions) error {
- _, err := manifests.Push(ir.ClientCxt, names[0], &names[1], &opts.All)
+func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination string, opts entities.ManifestPushOptions) error {
+ options := new(manifests.PushOptions).WithAll(opts.All)
+ _, err := manifests.Push(ir.ClientCtx, name, destination, options)
return err
}
diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go
index 4845980f6..9afb8db02 100644
--- a/pkg/domain/infra/tunnel/network.go
+++ b/pkg/domain/infra/tunnel/network.go
@@ -8,17 +8,19 @@ import (
"github.com/pkg/errors"
)
-func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
- return network.List(ic.ClientCxt, options)
+func (ic *ContainerEngine) NetworkList(ctx context.Context, opts entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
+ options := new(network.ListOptions).WithFilters(opts.Filters)
+ return network.List(ic.ClientCtx, options)
}
-func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
+func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
var (
reports = make([]entities.NetworkInspectReport, 0, len(namesOrIds))
errs = []error{}
)
+ options := new(network.InspectOptions)
for _, name := range namesOrIds {
- report, err := network.Inspect(ic.ClientCxt, name)
+ report, err := network.Inspect(ic.ClientCtx, name, options)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@@ -35,14 +37,15 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri
return reports, errs, nil
}
-func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, options entities.NetworkReloadOptions) ([]*entities.NetworkReloadReport, error) {
+func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, opts entities.NetworkReloadOptions) ([]*entities.NetworkReloadReport, error) {
return nil, errors.New("not implemented")
}
-func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
+func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, opts entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
reports := make([]*entities.NetworkRmReport, 0, len(namesOrIds))
+ options := new(network.RemoveOptions).WithForce(opts.Force)
for _, name := range namesOrIds {
- response, err := network.Remove(ic.ClientCxt, name, &options.Force)
+ response, err := network.Remove(ic.ClientCtx, name, options)
if err != nil {
report := &entities.NetworkRmReport{
Name: name,
@@ -56,16 +59,21 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o
return reports, nil
}
-func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, options entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) {
- return network.Create(ic.ClientCxt, options, &name)
+func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, opts entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) {
+ options := new(network.CreateOptions).WithName(name).WithDisableDNS(opts.DisableDNS).WithDriver(opts.Driver).WithGateway(opts.Gateway)
+ options.WithInternal(opts.Internal).WithIPRange(opts.Range).WithIPv6(opts.IPv6).WithLabels(opts.Labels).WithIPv6(opts.IPv6)
+ options.WithMacVLAN(opts.MacVLAN).WithOptions(opts.Options).WithSubnet(opts.Subnet)
+ return network.Create(ic.ClientCtx, options)
}
// NetworkDisconnect removes a container from a given network
-func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, options entities.NetworkDisconnectOptions) error {
- return network.Disconnect(ic.ClientCxt, networkname, options)
+func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, opts entities.NetworkDisconnectOptions) error {
+ options := new(network.DisconnectOptions).WithForce(opts.Force)
+ return network.Disconnect(ic.ClientCtx, networkname, opts.Container, options)
}
// NetworkConnect removes a container from a given network
-func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, options entities.NetworkConnectOptions) error {
- return network.Connect(ic.ClientCxt, networkname, options)
+func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, opts entities.NetworkConnectOptions) error {
+ options := new(network.ConnectOptions).WithAliases(opts.Aliases)
+ return network.Connect(ic.ClientCtx, networkname, opts.Container, options)
}
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
index 26f23093b..2318b9caa 100644
--- a/pkg/domain/infra/tunnel/play.go
+++ b/pkg/domain/infra/tunnel/play.go
@@ -3,10 +3,21 @@ package tunnel
import (
"context"
+ "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/bindings/play"
"github.com/containers/podman/v2/pkg/domain/entities"
)
-func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
- return play.Kube(ic.ClientCxt, path, options)
+func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+ options := new(play.KubeOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password)
+ options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps)
+ options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Network).WithSeccompProfileRoot(opts.SeccompProfileRoot)
+
+ if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
+ options.WithSkipTLSVerify(s == types.OptionalBoolTrue)
+ }
+ if start := opts.Start; start != types.OptionalBoolUndefined {
+ options.WithStart(start == types.OptionalBoolTrue)
+ }
+ return play.Kube(ic.ClientCtx, path, options)
}
diff --git a/pkg/domain/infra/tunnel/pods.go b/pkg/domain/infra/tunnel/pods.go
index ee4978787..aa7b92fa7 100644
--- a/pkg/domain/infra/tunnel/pods.go
+++ b/pkg/domain/infra/tunnel/pods.go
@@ -12,23 +12,24 @@ import (
)
func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
- exists, err := pods.Exists(ic.ClientCxt, nameOrID)
+ exists, err := pods.Exists(ic.ClientCtx, nameOrID)
return &entities.BoolReport{Value: exists}, err
}
-func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, options entities.PodKillOptions) ([]*entities.PodKillReport, error) {
- _, err := util.ParseSignal(options.Signal)
+func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opts entities.PodKillOptions) ([]*entities.PodKillReport, error) {
+ _, err := util.ParseSignal(opts.Signal)
if err != nil {
return nil, err
}
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, opts.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodKillReport, 0, len(foundPods))
+ options := new(pods.KillOptions).WithSignal(opts.Signal)
for _, p := range foundPods {
- response, err := pods.Kill(ic.ClientCxt, p.Id, &options.Signal)
+ response, err := pods.Kill(ic.ClientCtx, p.Id, options)
if err != nil {
report := entities.PodKillReport{
Errs: []error{err},
@@ -43,13 +44,13 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt
}
func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, options entities.PodPauseOptions) ([]*entities.PodPauseReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodPauseReport, 0, len(foundPods))
for _, p := range foundPods {
- response, err := pods.Pause(ic.ClientCxt, p.Id)
+ response, err := pods.Pause(ic.ClientCtx, p.Id, nil)
if err != nil {
report := entities.PodPauseReport{
Errs: []error{err},
@@ -64,13 +65,13 @@ func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, op
}
func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string, options entities.PodunpauseOptions) ([]*entities.PodUnpauseReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodUnpauseReport, 0, len(foundPods))
for _, p := range foundPods {
- response, err := pods.Unpause(ic.ClientCxt, p.Id)
+ response, err := pods.Unpause(ic.ClientCtx, p.Id, nil)
if err != nil {
report := entities.PodUnpauseReport{
Errs: []error{err},
@@ -84,18 +85,19 @@ func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string,
return reports, nil
}
-func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, options entities.PodStopOptions) ([]*entities.PodStopReport, error) {
+func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opts entities.PodStopOptions) ([]*entities.PodStopReport, error) {
timeout := -1
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
+ foundPods, err := getPodsByContext(ic.ClientCtx, opts.All, namesOrIds)
+ if err != nil && !(opts.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
}
- if options.Timeout != -1 {
- timeout = options.Timeout
+ if opts.Timeout != -1 {
+ timeout = opts.Timeout
}
reports := make([]*entities.PodStopReport, 0, len(foundPods))
+ options := new(pods.StopOptions).WithTimeout(timeout)
for _, p := range foundPods {
- response, err := pods.Stop(ic.ClientCxt, p.Id, &timeout)
+ response, err := pods.Stop(ic.ClientCtx, p.Id, options)
if err != nil {
report := entities.PodStopReport{
Errs: []error{err},
@@ -110,13 +112,13 @@ func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opt
}
func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string, options entities.PodRestartOptions) ([]*entities.PodRestartReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodRestartReport, 0, len(foundPods))
for _, p := range foundPods {
- response, err := pods.Restart(ic.ClientCxt, p.Id)
+ response, err := pods.Restart(ic.ClientCtx, p.Id, nil)
if err != nil {
report := entities.PodRestartReport{
Errs: []error{err},
@@ -131,13 +133,13 @@ func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string,
}
func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, options entities.PodStartOptions) ([]*entities.PodStartReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
+ foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds)
if err != nil {
return nil, err
}
reports := make([]*entities.PodStartReport, 0, len(foundPods))
for _, p := range foundPods {
- response, err := pods.Start(ic.ClientCxt, p.Id)
+ response, err := pods.Start(ic.ClientCtx, p.Id, nil)
if err != nil {
report := entities.PodStartReport{
Errs: []error{err},
@@ -151,14 +153,15 @@ func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, op
return reports, nil
}
-func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, options entities.PodRmOptions) ([]*entities.PodRmReport, error) {
- foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
- if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
+func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, opts entities.PodRmOptions) ([]*entities.PodRmReport, error) {
+ foundPods, err := getPodsByContext(ic.ClientCtx, opts.All, namesOrIds)
+ if err != nil && !(opts.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
}
reports := make([]*entities.PodRmReport, 0, len(foundPods))
+ options := new(pods.RemoveOptions).WithForce(opts.Force)
for _, p := range foundPods {
- response, err := pods.Remove(ic.ClientCxt, p.Id, &options.Force)
+ response, err := pods.Remove(ic.ClientCtx, p.Id, options)
if err != nil {
report := entities.PodRmReport{
Err: err,
@@ -173,32 +176,33 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
}
func (ic *ContainerEngine) PodPrune(ctx context.Context, opts entities.PodPruneOptions) ([]*entities.PodPruneReport, error) {
- return pods.Prune(ic.ClientCxt)
+ return pods.Prune(ic.ClientCtx, nil)
}
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
podSpec := specgen.NewPodSpecGenerator()
opts.ToPodSpecGen(podSpec)
- return pods.CreatePodFromSpec(ic.ClientCxt, podSpec)
+ return pods.CreatePodFromSpec(ic.ClientCtx, podSpec, nil)
}
-func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOptions) (*entities.StringSliceReport, error) {
+func (ic *ContainerEngine) PodTop(ctx context.Context, opts entities.PodTopOptions) (*entities.StringSliceReport, error) {
switch {
- case options.Latest:
+ case opts.Latest:
return nil, errors.New("latest is not supported")
- case options.NameOrID == "":
+ case opts.NameOrID == "":
return nil, errors.New("NameOrID must be specified")
}
-
- topOutput, err := pods.Top(ic.ClientCxt, options.NameOrID, options.Descriptors)
+ options := new(pods.TopOptions).WithDescriptors(opts.Descriptors)
+ topOutput, err := pods.Top(ic.ClientCtx, opts.NameOrID, options)
if err != nil {
return nil, err
}
return &entities.StringSliceReport{Value: topOutput}, nil
}
-func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOptions) ([]*entities.ListPodsReport, error) {
- return pods.List(ic.ClientCxt, options.Filters)
+func (ic *ContainerEngine) PodPs(ctx context.Context, opts entities.PodPSOptions) ([]*entities.ListPodsReport, error) {
+ options := new(pods.ListOptions).WithFilters(opts.Filters)
+ return pods.List(ic.ClientCtx, options)
}
func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodInspectOptions) (*entities.PodInspectReport, error) {
@@ -208,9 +212,10 @@ func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodI
case options.NameOrID == "":
return nil, errors.New("NameOrID must be specified")
}
- return pods.Inspect(ic.ClientCxt, options.NameOrID)
+ return pods.Inspect(ic.ClientCtx, options.NameOrID, nil)
}
-func (ic *ContainerEngine) PodStats(ctx context.Context, namesOrIds []string, options entities.PodStatsOptions) ([]*entities.PodStatsReport, error) {
- return pods.Stats(ic.ClientCxt, namesOrIds, options)
+func (ic *ContainerEngine) PodStats(ctx context.Context, namesOrIds []string, opts entities.PodStatsOptions) ([]*entities.PodStatsReport, error) {
+ options := new(pods.StatsOptions).WithAll(opts.All)
+ return pods.Stats(ic.ClientCtx, namesOrIds, options)
}
diff --git a/pkg/domain/infra/tunnel/runtime.go b/pkg/domain/infra/tunnel/runtime.go
index 357e2c390..6542ea5b7 100644
--- a/pkg/domain/infra/tunnel/runtime.go
+++ b/pkg/domain/infra/tunnel/runtime.go
@@ -6,15 +6,15 @@ import (
// Image-related runtime using an ssh-tunnel to utilize Podman service
type ImageEngine struct {
- ClientCxt context.Context
+ ClientCtx context.Context
}
// Container-related runtime using an ssh-tunnel to utilize Podman service
type ContainerEngine struct {
- ClientCxt context.Context
+ ClientCtx context.Context
}
// Container-related runtime using an ssh-tunnel to utilize Podman service
type SystemEngine struct {
- ClientCxt context.Context
+ ClientCtx context.Context
}
diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go
index f3e8fbcb1..a46b164a5 100644
--- a/pkg/domain/infra/tunnel/system.go
+++ b/pkg/domain/infra/tunnel/system.go
@@ -11,7 +11,7 @@ import (
)
func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
- return system.Info(ic.ClientCxt)
+ return system.Info(ic.ClientCtx, nil)
}
func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error {
@@ -19,12 +19,13 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
}
// SystemPrune prunes unused data from the system.
-func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
- return system.Prune(ic.ClientCxt, &options.All, &options.Volume)
+func (ic *ContainerEngine) SystemPrune(ctx context.Context, opts entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
+ options := new(system.PruneOptions).WithAll(opts.All).WithVolumes(opts.Volume).WithFilters(opts.Filters)
+ return system.Prune(ic.ClientCtx, options)
}
func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.SystemDfOptions) (*entities.SystemDfReport, error) {
- return system.DiskUsage(ic.ClientCxt)
+ return system.DiskUsage(ic.ClientCtx, nil)
}
func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error {
@@ -32,5 +33,5 @@ func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error {
}
func (ic ContainerEngine) Version(ctx context.Context) (*entities.SystemVersionReport, error) {
- return system.Version(ic.ClientCxt)
+ return system.Version(ic.ClientCtx, nil)
}
diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go
index c0df2bb7b..10e8d7da8 100644
--- a/pkg/domain/infra/tunnel/volumes.go
+++ b/pkg/domain/infra/tunnel/volumes.go
@@ -5,11 +5,12 @@ import (
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IDOrNameResponse, error) {
- response, err := volumes.Create(ic.ClientCxt, opts)
+ response, err := volumes.Create(ic.ClientCtx, opts, nil)
if err != nil {
return nil, err
}
@@ -18,7 +19,7 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum
func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) {
if opts.All {
- vols, err := volumes.List(ic.ClientCxt, nil)
+ vols, err := volumes.List(ic.ClientCtx, nil)
if err != nil {
return nil, err
}
@@ -28,8 +29,9 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
}
reports := make([]*entities.VolumeRmReport, 0, len(namesOrIds))
for _, id := range namesOrIds {
+ options := new(volumes.RemoveOptions).WithForce(opts.Force)
reports = append(reports, &entities.VolumeRmReport{
- Err: volumes.Remove(ic.ClientCxt, id, &opts.Force),
+ Err: volumes.Remove(ic.ClientCtx, id, options),
Id: id,
})
}
@@ -42,7 +44,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
errs = []error{}
)
if opts.All {
- vols, err := volumes.List(ic.ClientCxt, nil)
+ vols, err := volumes.List(ic.ClientCtx, nil)
if err != nil {
return nil, nil, err
}
@@ -51,7 +53,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
}
}
for _, id := range namesOrIds {
- data, err := volumes.Inspect(ic.ClientCxt, id)
+ data, err := volumes.Inspect(ic.ClientCtx, id, nil)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@@ -68,10 +70,12 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
return reports, errs, nil
}
-func (ic *ContainerEngine) VolumePrune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- return volumes.Prune(ic.ClientCxt)
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*reports.PruneReport, error) {
+ options := new(volumes.PruneOptions).WithFilters(opts.Filters)
+ return volumes.Prune(ic.ClientCtx, options)
}
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
- return volumes.List(ic.ClientCxt, opts.Filter)
+ options := new(volumes.ListOptions).WithFilters(opts.Filter)
+ return volumes.List(ic.ClientCtx, options)
}
diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go
index ca6b60bc5..21df261fb 100644
--- a/pkg/errorhandling/errorhandling.go
+++ b/pkg/errorhandling/errorhandling.go
@@ -19,7 +19,12 @@ func JoinErrors(errs []error) error {
// blank lines when printing the error.
var multiE *multierror.Error
multiE = multierror.Append(multiE, errs...)
- return errors.New(strings.TrimSpace(multiE.ErrorOrNil().Error()))
+
+ finalErr := multiE.ErrorOrNil()
+ if finalErr == nil {
+ return finalErr
+ }
+ return errors.New(strings.TrimSpace(finalErr.Error()))
}
// ErrorsToString converts the slice of errors into a slice of corresponding
diff --git a/pkg/hooks/README.md b/pkg/hooks/README.md
index 61fbbcac6..f6a03a775 100644
--- a/pkg/hooks/README.md
+++ b/pkg/hooks/README.md
@@ -9,7 +9,7 @@ This can cause some performance issues.
Also a lot of hooks just check if certain configuration is set and then exit early, without doing anything.
For example the [oci-systemd-hook][] only executes if the command is `init` or `systemd`, otherwise it just exits.
This means if we automatically enabled all hooks, every container would have to execute `oci-systemd-hook`, even if they don't run systemd inside of the container.
-Performance would also suffer if we exectuted each hook at each stage ([pre-start][], [post-start][], and [post-stop][]).
+Performance would also suffer if we executed each hook at each stage ([pre-start][], [post-start][], and [post-stop][]).
The hooks configuration is documented in [`oci-hooks.5`](docs/oci-hooks.5.md).
diff --git a/pkg/hooks/exec/exec.go b/pkg/hooks/exec/exec.go
index 77b350573..f6b6636ad 100644
--- a/pkg/hooks/exec/exec.go
+++ b/pkg/hooks/exec/exec.go
@@ -1,4 +1,4 @@
-// Package exec provides utilities for executing Open Container Initative runtime hooks.
+// Package exec provides utilities for executing Open Container Initiative runtime hooks.
package exec
import (
diff --git a/pkg/hooks/hooks.go b/pkg/hooks/hooks.go
index 6257529ab..6cb81e573 100644
--- a/pkg/hooks/hooks.go
+++ b/pkg/hooks/hooks.go
@@ -46,7 +46,7 @@ type namedHook struct {
//
// extensionStages allows callers to add additional stages beyond
// those specified in the OCI Runtime Specification and to control
-// OCI-defined stages instead of delagating to the OCI runtime. See
+// OCI-defined stages instead of delegating to the OCI runtime. See
// Hooks() for more information.
func New(ctx context.Context, directories []string, extensionStages []string) (manager *Manager, err error) {
manager = &Manager{
diff --git a/pkg/netns/netns_linux.go b/pkg/netns/netns_linux.go
index ff5691203..ed5241632 100644
--- a/pkg/netns/netns_linux.go
+++ b/pkg/netns/netns_linux.go
@@ -162,7 +162,7 @@ func NewNS() (ns.NetNS, error) {
// bind mount the netns from the current thread (from /proc) onto the
// mount point. This causes the namespace to persist, even when there
// are no threads in the ns. Make this a shared mount; it needs to be
- // back-propogated to the host
+ // back-propagated to the host
err = unix.Mount(threadNsPath, nsPath, "none", unix.MS_BIND|unix.MS_SHARED|unix.MS_REC, "")
if err != nil {
err = fmt.Errorf("failed to bind mount ns at %s: %v", nsPath, err)
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index cfdf3ee49..9e0dcb728 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -11,8 +11,8 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
- lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/filters"
psdefine "github.com/containers/podman/v2/pkg/ps/define"
"github.com/containers/storage"
"github.com/pkg/errors"
@@ -27,7 +27,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp
all := options.All || options.Last > 0
if len(options.Filters) > 0 {
for k, v := range options.Filters {
- generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, runtime)
+ generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime)
if err != nil {
return nil, err
}
@@ -41,7 +41,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp
all = true
}
if !all {
- runningOnly, err := lpfilters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime)
+ runningOnly, err := filters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime)
if err != nil {
return nil, err
}
@@ -179,24 +179,25 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
}
ps := entities.ListContainer{
- Command: conConfig.Command,
- Created: conConfig.CreatedTime,
- Exited: exited,
- ExitCode: exitCode,
- ExitedAt: exitedTime.Unix(),
- ID: conConfig.ID,
- Image: conConfig.RootfsImageName,
- ImageID: conConfig.RootfsImageID,
- IsInfra: conConfig.IsInfra,
- Labels: conConfig.Labels,
- Mounts: ctr.UserVolumes(),
- Names: []string{conConfig.Name},
- Pid: pid,
- Pod: conConfig.Pod,
- Ports: portMappings,
- Size: size,
- StartedAt: startedTime.Unix(),
- State: conState.String(),
+ AutoRemove: ctr.AutoRemove(),
+ Command: conConfig.Command,
+ Created: conConfig.CreatedTime,
+ Exited: exited,
+ ExitCode: exitCode,
+ ExitedAt: exitedTime.Unix(),
+ ID: conConfig.ID,
+ Image: conConfig.RootfsImageName,
+ ImageID: conConfig.RootfsImageID,
+ IsInfra: conConfig.IsInfra,
+ Labels: conConfig.Labels,
+ Mounts: ctr.UserVolumes(),
+ Names: []string{conConfig.Name},
+ Pid: pid,
+ Pod: conConfig.Pod,
+ Ports: portMappings,
+ Size: size,
+ StartedAt: startedTime.Unix(),
+ State: conState.String(),
}
if opts.Pod && len(conConfig.Pod) > 0 {
podName, err := rt.GetName(conConfig.Pod)
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index f029f24cb..d4b1a0dfd 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -257,7 +257,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
uidsMapped = err == nil
}
if !uidsMapped {
- logrus.Warnf("using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding subids")
+ logrus.Warnf("using rootless single mapping into the namespace. This might break some images. Check /etc/subuid and /etc/subgid for adding sub*ids")
setgroups := fmt.Sprintf("/proc/%d/setgroups", pid)
err = ioutil.WriteFile(setgroups, []byte("deny\n"), 0666)
if err != nil {
diff --git a/pkg/seccomp/seccomp.go b/pkg/seccomp/seccomp.go
index eeba46a72..4502c608f 100644
--- a/pkg/seccomp/seccomp.go
+++ b/pkg/seccomp/seccomp.go
@@ -30,7 +30,7 @@ var supportedPolicies = map[string]Policy{
"image": PolicyImage,
}
-// LookupPolicy looksup the corresponding Policy for the specified
+// LookupPolicy looks up the corresponding Policy for the specified
// string. If none is found, an errors is returned including the list of
// supported policies.
//
diff --git a/pkg/signal/signal_linux.go b/pkg/signal/signal_linux.go
index 72ab1b97b..305b9d21f 100644
--- a/pkg/signal/signal_linux.go
+++ b/pkg/signal/signal_linux.go
@@ -1,4 +1,5 @@
// +build linux
+// +build !mips,!mipsle,!mips64,!mips64le
// Signal handling for Linux only.
package signal
diff --git a/pkg/signal/signal_linux_mipsx.go b/pkg/signal/signal_linux_mipsx.go
new file mode 100644
index 000000000..67638e30a
--- /dev/null
+++ b/pkg/signal/signal_linux_mipsx.go
@@ -0,0 +1,106 @@
+// +build linux
+// +build mips mipsle mips64 mips64le
+
+// Special signal handling for mips architecture
+package signal
+
+// Copyright 2013-2018 Docker, Inc.
+
+// NOTE: this package has originally been copied from github.com/docker/docker.
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ sigrtmin = 34
+ sigrtmax = 127
+)
+
+// signalMap is a map of Linux signals.
+var signalMap = map[string]syscall.Signal{
+ "ABRT": unix.SIGABRT,
+ "ALRM": unix.SIGALRM,
+ "BUS": unix.SIGBUS,
+ "CHLD": unix.SIGCHLD,
+ "CLD": unix.SIGCLD,
+ "CONT": unix.SIGCONT,
+ "FPE": unix.SIGFPE,
+ "HUP": unix.SIGHUP,
+ "ILL": unix.SIGILL,
+ "INT": unix.SIGINT,
+ "IO": unix.SIGIO,
+ "IOT": unix.SIGIOT,
+ "KILL": unix.SIGKILL,
+ "PIPE": unix.SIGPIPE,
+ "POLL": unix.SIGPOLL,
+ "PROF": unix.SIGPROF,
+ "PWR": unix.SIGPWR,
+ "QUIT": unix.SIGQUIT,
+ "SEGV": unix.SIGSEGV,
+ "EMT": unix.SIGEMT,
+ "STOP": unix.SIGSTOP,
+ "SYS": unix.SIGSYS,
+ "TERM": unix.SIGTERM,
+ "TRAP": unix.SIGTRAP,
+ "TSTP": unix.SIGTSTP,
+ "TTIN": unix.SIGTTIN,
+ "TTOU": unix.SIGTTOU,
+ "URG": unix.SIGURG,
+ "USR1": unix.SIGUSR1,
+ "USR2": unix.SIGUSR2,
+ "VTALRM": unix.SIGVTALRM,
+ "WINCH": unix.SIGWINCH,
+ "XCPU": unix.SIGXCPU,
+ "XFSZ": unix.SIGXFSZ,
+ "RTMIN": sigrtmin,
+ "RTMIN+1": sigrtmin + 1,
+ "RTMIN+2": sigrtmin + 2,
+ "RTMIN+3": sigrtmin + 3,
+ "RTMIN+4": sigrtmin + 4,
+ "RTMIN+5": sigrtmin + 5,
+ "RTMIN+6": sigrtmin + 6,
+ "RTMIN+7": sigrtmin + 7,
+ "RTMIN+8": sigrtmin + 8,
+ "RTMIN+9": sigrtmin + 9,
+ "RTMIN+10": sigrtmin + 10,
+ "RTMIN+11": sigrtmin + 11,
+ "RTMIN+12": sigrtmin + 12,
+ "RTMIN+13": sigrtmin + 13,
+ "RTMIN+14": sigrtmin + 14,
+ "RTMIN+15": sigrtmin + 15,
+ "RTMAX-14": sigrtmax - 14,
+ "RTMAX-13": sigrtmax - 13,
+ "RTMAX-12": sigrtmax - 12,
+ "RTMAX-11": sigrtmax - 11,
+ "RTMAX-10": sigrtmax - 10,
+ "RTMAX-9": sigrtmax - 9,
+ "RTMAX-8": sigrtmax - 8,
+ "RTMAX-7": sigrtmax - 7,
+ "RTMAX-6": sigrtmax - 6,
+ "RTMAX-5": sigrtmax - 5,
+ "RTMAX-4": sigrtmax - 4,
+ "RTMAX-3": sigrtmax - 3,
+ "RTMAX-2": sigrtmax - 2,
+ "RTMAX-1": sigrtmax - 1,
+ "RTMAX": sigrtmax,
+}
+
+// CatchAll catches all signals and relays them to the specified channel.
+func CatchAll(sigc chan os.Signal) {
+ handledSigs := make([]os.Signal, 0, len(signalMap))
+ for _, s := range signalMap {
+ handledSigs = append(handledSigs, s)
+ }
+ signal.Notify(sigc, handledSigs...)
+}
+
+// StopCatch stops catching the signals and closes the specified channel.
+func StopCatch(sigc chan os.Signal) {
+ signal.Stop(sigc)
+ close(sigc)
+}
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index c7e62d185..42fea0277 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -163,7 +163,7 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
return nil, err
}
- // labels from the image that dont exist already
+ // labels from the image that don't exist already
if len(labels) > 0 && s.Labels == nil {
s.Labels = make(map[string]string)
}
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 5cc7891ac..e5b09dcd8 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -30,7 +30,7 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
p.Hostname = podName
}
if podYAML.Spec.HostNetwork {
- p.NetNS.Value = "host"
+ p.NetNS.NSMode = specgen.Host
}
if podYAML.Spec.HostAliases != nil {
hosts := make([]string, 0, len(podYAML.Spec.HostAliases))
@@ -47,30 +47,53 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
return p, nil
}
-func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newImage *image.Image, volumes map[string]*KubeVolume, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *KubeSeccompPaths, restartPolicy string) (*specgen.SpecGenerator, error) {
- s := specgen.NewSpecGenerator(iid, false)
+type CtrSpecGenOptions struct {
+ // Container as read from the pod yaml
+ Container v1.Container
+ // Image available to use (pulled or found local)
+ Image *image.Image
+ // Volumes for all containers
+ Volumes map[string]*KubeVolume
+ // PodID of the parent pod
+ PodID string
+ // PodName of the parent pod
+ PodName string
+ // PodInfraID as the infrastructure container id
+ PodInfraID string
+ // ConfigMaps the configuration maps for environment variables
+ ConfigMaps []v1.ConfigMap
+ // SeccompPaths for finding the seccomp profile path
+ SeccompPaths *KubeSeccompPaths
+ // RestartPolicy defines the restart policy of the container
+ RestartPolicy string
+ // NetNSIsHost tells the container to use the host netns
+ NetNSIsHost bool
+}
+
+func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) {
+ s := specgen.NewSpecGenerator(opts.Container.Image, false)
- // podName should be non-empty for Deployment objects to be able to create
+ // pod name should be non-empty for Deployment objects to be able to create
// multiple pods having containers with unique names
- if len(podName) < 1 {
- return nil, errors.Errorf("kubeContainerToCreateConfig got empty podName")
+ if len(opts.PodName) < 1 {
+ return nil, errors.Errorf("got empty pod name on container creation when playing kube")
}
- s.Name = fmt.Sprintf("%s-%s", podName, containerYAML.Name)
+ s.Name = fmt.Sprintf("%s-%s", opts.PodName, opts.Container.Name)
- s.Terminal = containerYAML.TTY
+ s.Terminal = opts.Container.TTY
- s.Pod = podID
+ s.Pod = opts.PodID
- setupSecurityContext(s, containerYAML)
+ setupSecurityContext(s, opts.Container)
// Since we prefix the container name with pod name to work-around the uniqueness requirement,
// the seccomp profile should reference the actual container name from the YAML
// but apply to the containers with the prefixed name
- s.SeccompProfilePath = seccompPaths.FindForContainer(containerYAML.Name)
+ s.SeccompProfilePath = opts.SeccompPaths.FindForContainer(opts.Container.Name)
s.ResourceLimits = &spec.LinuxResources{}
- milliCPU, err := quantityToInt64(containerYAML.Resources.Limits.Cpu())
+ milliCPU, err := quantityToInt64(opts.Container.Resources.Limits.Cpu())
if err != nil {
return nil, errors.Wrap(err, "Failed to set CPU quota")
}
@@ -82,12 +105,12 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
}
}
- limit, err := quantityToInt64(containerYAML.Resources.Limits.Memory())
+ limit, err := quantityToInt64(opts.Container.Resources.Limits.Memory())
if err != nil {
return nil, errors.Wrap(err, "Failed to set memory limit")
}
- memoryRes, err := quantityToInt64(containerYAML.Resources.Requests.Memory())
+ memoryRes, err := quantityToInt64(opts.Container.Resources.Requests.Memory())
if err != nil {
return nil, errors.Wrap(err, "Failed to set memory reservation")
}
@@ -104,19 +127,26 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
s.ResourceLimits.Memory.Reservation = &memoryRes
}
- // TODO: We dont understand why specgen does not take of this, but
+ // TODO: We don't understand why specgen does not take of this, but
// integration tests clearly pointed out that it was required.
s.Command = []string{}
- imageData, err := newImage.Inspect(ctx)
+ imageData, err := opts.Image.Inspect(ctx)
if err != nil {
return nil, err
}
s.WorkDir = "/"
+ // We will use "Docker field name" internally here to avoid confusion
+ // and reference the "Kubernetes field name" when referencing the YAML
+ // ref: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes
+ entrypoint := []string{}
+ cmd := []string{}
if imageData != nil && imageData.Config != nil {
if imageData.Config.WorkingDir != "" {
s.WorkDir = imageData.Config.WorkingDir
}
- s.Command = imageData.Config.Entrypoint
+ // Pull entrypoint and cmd from image
+ entrypoint = imageData.Config.Entrypoint
+ cmd = imageData.Config.Cmd
s.Labels = imageData.Config.Labels
if len(imageData.Config.StopSignal) > 0 {
stopSignal, err := util.ParseSignal(imageData.Config.StopSignal)
@@ -126,22 +156,27 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
s.StopSignal = &stopSignal
}
}
- if len(containerYAML.Command) != 0 {
- s.Command = containerYAML.Command
+ // If only the yaml.Command is specified, set it as the entrypoint and drop the image Cmd
+ if len(opts.Container.Command) != 0 {
+ entrypoint = opts.Container.Command
+ cmd = []string{}
}
- // doc https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes
- if len(containerYAML.Args) != 0 {
- s.Command = append(s.Command, containerYAML.Args...)
+ // Only override the cmd field if yaml.Args is specified
+ // Keep the image entrypoint, or the yaml.command if specified
+ if len(opts.Container.Args) != 0 {
+ cmd = opts.Container.Args
}
+
+ s.Command = append(entrypoint, cmd...)
// FIXME,
// we are currently ignoring imageData.Config.ExposedPorts
- if containerYAML.WorkingDir != "" {
- s.WorkDir = containerYAML.WorkingDir
+ if opts.Container.WorkingDir != "" {
+ s.WorkDir = opts.Container.WorkingDir
}
annotations := make(map[string]string)
- if infraID != "" {
- annotations[ann.SandboxID] = infraID
+ if opts.PodInfraID != "" {
+ annotations[ann.SandboxID] = opts.PodInfraID
annotations[ann.ContainerType] = ann.ContainerTypeContainer
}
s.Annotations = annotations
@@ -153,13 +188,13 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
envs[keyval[0]] = keyval[1]
}
- for _, env := range containerYAML.Env {
- value := envVarValue(env, configMaps)
+ for _, env := range opts.Container.Env {
+ value := envVarValue(env, opts.ConfigMaps)
envs[env.Name] = value
}
- for _, envFrom := range containerYAML.EnvFrom {
- cmEnvs := envVarsFromConfigMap(envFrom, configMaps)
+ for _, envFrom := range opts.Container.EnvFrom {
+ cmEnvs := envVarsFromConfigMap(envFrom, opts.ConfigMaps)
for k, v := range cmEnvs {
envs[k] = v
@@ -167,8 +202,8 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
}
s.Env = envs
- for _, volume := range containerYAML.VolumeMounts {
- volumeSource, exists := volumes[volume.Name]
+ for _, volume := range opts.Container.VolumeMounts {
+ volumeSource, exists := opts.Volumes[volume.Name]
if !exists {
return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name)
}
@@ -200,7 +235,11 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI
}
}
- s.RestartPolicy = restartPolicy
+ s.RestartPolicy = opts.RestartPolicy
+
+ if opts.NetNSIsHost {
+ s.NetNS.NSMode = specgen.Host
+ }
return s, nil
}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index c24dcf4c0..ba68de6fd 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -319,7 +319,7 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
// BIND MOUNTS
- configSpec.Mounts = SupercedeUserMounts(mounts, configSpec.Mounts)
+ configSpec.Mounts = SupersedeUserMounts(mounts, configSpec.Mounts)
// Process mounts to ensure correct options
if err := InitFSMounts(configSpec.Mounts); err != nil {
return nil, err
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index b69bd9091..9fceec7b3 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -115,7 +115,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
if err != nil {
return errors.Wrapf(err, "capabilities requested by user or image are not valid: %q", strings.Join(capsRequired, ","))
} else {
- // Verify all capRequiered are in the capList
+ // Verify all capRequired are in the capList
for _, cap := range capsRequired {
if !util.StringInSlice(cap, caplist) {
privCapsRequired = append(privCapsRequired, cap)
@@ -141,7 +141,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
configSpec.Process.Capabilities.Effective = caplist
configSpec.Process.Capabilities.Permitted = caplist
} else {
- userCaps, err := capabilities.NormalizeCapabilities(s.CapAdd)
+ userCaps, err := capabilities.MergeCapabilities(nil, s.CapAdd, nil)
if err != nil {
return errors.Wrapf(err, "capabilities requested by user are not valid: %q", strings.Join(s.CapAdd, ","))
}
@@ -172,7 +172,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
// Clear default Seccomp profile from Generator for unconfined containers
// and privileged containers which do not specify a seccomp profile.
- if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) {
+ if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == "" || s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) {
configSpec.Linux.Seccomp = nil
}
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index 331a5c5bf..f523ac5bf 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -366,7 +366,7 @@ func addContainerInitBinary(s *specgen.SpecGenerator, path string) (spec.Mount,
// TODO: Should we unmount subtree mounts? E.g., if /tmp/ is mounted by
// one mount, and we already have /tmp/a and /tmp/b, should we remove
// the /tmp/a and /tmp/b mounts in favor of the more general /tmp?
-func SupercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.Mount {
+func SupersedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.Mount {
if len(mounts) > 0 {
// If we have overlappings mounts, remove them from the spec in favor of
// the user-added volume mounts
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index a6c61a203..7c81f3f9f 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -48,7 +48,7 @@ func (p *PodSpecGenerator) Validate() error {
}
if p.NoInfra {
if p.NetNS.NSMode != Default && p.NetNS.NSMode != "" {
- return errors.New("NoInfra and network modes cannot be used toegther")
+ return errors.New("NoInfra and network modes cannot be used together")
}
if p.StaticIP != nil {
return exclusivePodOptions("NoInfra", "StaticIP")
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 964b89fa4..a6cc0a730 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -19,7 +19,7 @@ type LogConfig struct {
// Only available if LogDriver is set to "json-file" or "k8s-file".
// Optional.
Path string `json:"path,omitempty"`
- // Size is the maximimup size of the log file
+ // Size is the maximum size of the log file
// Optional.
Size int64 `json:"size,omitempty"`
// A set of options to accompany the log driver.
@@ -302,7 +302,7 @@ type ContainerSecurityConfig struct {
IDMappings *storage.IDMappingOptions `json:"idmappings,omitempty"`
// ReadOnlyFilesystem indicates that everything will be mounted
// as read-only
- ReadOnlyFilesystem bool `json:"read_only_filesystem,omittempty"`
+ ReadOnlyFilesystem bool `json:"read_only_filesystem,omitempty"`
// Umask is the umask the init process of the container will be run with.
Umask string `json:"umask,omitempty"`
// ProcOpts are the options used for the proc mount.
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
index 52a214883..fb921cd72 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -11,6 +11,11 @@ import (
// is set to the unit's (unique) name.
const EnvVariable = "PODMAN_SYSTEMD_UNIT"
+// minTimeoutStopSec is the minimal stop timeout for generated systemd units.
+// Once exceeded, processes of the services are killed and the cgroup(s) are
+// cleaned up.
+const minTimeoutStopSec = 60
+
// RestartPolicies includes all valid restart policies to be used in a unit
// file.
var RestartPolicies = []string{"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"}
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index 8090bcd3d..cfa02dc9d 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -55,6 +55,8 @@ type containerInfo struct {
ExecStartPre string
// ExecStart of the unit.
ExecStart string
+ // TimeoutStopSec of the unit.
+ TimeoutStopSec uint
// ExecStop of the unit.
ExecStop string
// ExecStopPost of the unit.
@@ -74,6 +76,7 @@ After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $v
[Service]
Environment={{.EnvVariable}}=%n
Restart={{.RestartPolicy}}
+TimeoutStopSec={{.TimeoutStopSec}}
{{- if .ExecStartPre}}
ExecStartPre={{.ExecStartPre}}
{{- end}}
@@ -81,7 +84,6 @@ ExecStart={{.ExecStart}}
ExecStop={{.ExecStop}}
ExecStopPost={{.ExecStopPost}}
PIDFile={{.PIDFile}}
-KillMode=none
Type=forking
[Install]
@@ -191,7 +193,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
return "", errors.Errorf("container's create command is too short or invalid: %v", info.CreateCommand)
}
// We're hard-coding the first five arguments and append the
- // CreateCommand with a stripped command and subcomand.
+ // CreateCommand with a stripped command and subcommand.
startCommand := []string{
info.Executable,
"run",
@@ -241,7 +243,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
}
if hasNameParam && !hasReplaceParam {
// Enforce --replace for named containers. This will
- // make systemd units more robuts as it allows them to
+ // make systemd units more robust as it allows them to
// start after system crashes (see
// github.com/containers/podman/issues/5485).
startCommand = append(startCommand, "--replace")
@@ -255,6 +257,8 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
info.ExecStopPost = "{{.Executable}} rm --ignore -f --cidfile {{.ContainerIDFile}}"
}
+ info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout
+
if info.PodmanVersion == "" {
info.PodmanVersion = version.Version.String()
}
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index d27062ef3..b9fb8fee6 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/stretchr/testify/assert"
)
func TestValidateRestartPolicyContainer(t *testing.T) {
@@ -48,11 +49,11 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=82
ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-ExecStopPost=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+ExecStop=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+ExecStopPost=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
Type=forking
[Install]
@@ -71,11 +72,11 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
ExecStopPost=/usr/bin/podman stop -t 10 foobar
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
Type=forking
[Install]
@@ -96,11 +97,11 @@ After=a.service b.service c.service pod.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
ExecStopPost=/usr/bin/podman stop -t 10 foobar
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
Type=forking
[Install]
@@ -119,12 +120,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space"
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -143,12 +144,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -167,12 +168,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --pod-id-file /tmp/pod-foobar.pod-id-file --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -191,12 +192,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --replace --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -215,12 +216,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id --cgroups=no-conmon -d awesome-image:latest
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id
PIDFile=%t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid
-KillMode=none
Type=forking
[Install]
@@ -242,7 +243,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
+ StopTimeout: 22,
PodmanVersion: "CI",
EnvVariable: EnvVariable,
},
@@ -302,7 +303,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN", "foo=arg \"with \" space"},
EnvVariable: EnvVariable,
@@ -318,7 +319,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
@@ -334,7 +335,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
@@ -353,7 +354,7 @@ WantedBy=multi-user.target default.target
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "--detach", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
@@ -390,9 +391,7 @@ WantedBy=multi-user.target default.target
t.Errorf("CreateContainerSystemdUnit() error = \n%v, wantErr \n%v", err, test.wantErr)
return
}
- if got != test.want {
- t.Errorf("CreateContainerSystemdUnit() = \n%v\n---------> want\n%v", got, test.want)
- }
+ assert.Equal(t, test.want, got)
})
}
}
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index 234a60380..fc582e42a 100644
--- a/pkg/systemd/generate/pods.go
+++ b/pkg/systemd/generate/pods.go
@@ -60,6 +60,8 @@ type podInfo struct {
ExecStartPre2 string
// ExecStart of the unit.
ExecStart string
+ // TimeoutStopSec of the unit.
+ TimeoutStopSec uint
// ExecStop of the unit.
ExecStop string
// ExecStopPost of the unit.
@@ -72,6 +74,7 @@ Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{
[Service]
Environment={{.EnvVariable}}=%n
Restart={{.RestartPolicy}}
+TimeoutStopSec={{.TimeoutStopSec}}
{{- if .ExecStartPre1}}
ExecStartPre={{.ExecStartPre1}}
{{- end}}
@@ -82,7 +85,6 @@ ExecStart={{.ExecStart}}
ExecStop={{.ExecStop}}
ExecStopPost={{.ExecStopPost}}
PIDFile={{.PIDFile}}
-KillMode=none
Type=forking
[Install]
@@ -266,7 +268,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:])
}
// We're hard-coding the first five arguments and append the
- // CreateCommand with a stripped command and subcomand.
+ // CreateCommand with a stripped command and subcommand.
startCommand := []string{info.Executable}
startCommand = append(startCommand, podRootArgs...)
startCommand = append(startCommand,
@@ -298,6 +300,8 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
info.ExecStop = "{{.Executable}} pod stop --ignore --pod-id-file {{.PodIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
info.ExecStopPost = "{{.Executable}} pod rm --ignore -f --pod-id-file {{.PodIDFile}}"
}
+ info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout
+
if info.PodmanVersion == "" {
info.PodmanVersion = version.Version.String()
}
diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go
index 7f1f63b7e..6d925ecd2 100644
--- a/pkg/systemd/generate/pods_test.go
+++ b/pkg/systemd/generate/pods_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/stretchr/testify/assert"
)
func TestValidateRestartPolicyPod(t *testing.T) {
@@ -50,11 +51,11 @@ Before=container-1.service container-2.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=102
ExecStart=/usr/bin/podman start jadda-jadda-infra
-ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra
-ExecStopPost=/usr/bin/podman stop -t 10 jadda-jadda-infra
+ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra
+ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
Type=forking
[Install]
@@ -75,13 +76,13 @@ Before=container-1.service container-2.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id
ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-123abc.pod-id -t 10
ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-id
PIDFile=%t/pod-123abc.pid
-KillMode=none
Type=forking
[Install]
@@ -102,7 +103,7 @@ WantedBy=multi-user.target default.target
InfraNameOrID: "jadda-jadda-infra",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
+ StopTimeout: 42,
PodmanVersion: "CI",
RequiredServices: []string{"container-1", "container-2"},
},
@@ -139,9 +140,7 @@ WantedBy=multi-user.target default.target
t.Errorf("CreatePodSystemdUnit() error = \n%v, wantErr \n%v", err, test.wantErr)
return
}
- if got != test.want {
- t.Errorf("CreatePodSystemdUnit() = \n%v\n---------> want\n%v", got, test.want)
- }
+ assert.Equal(t, test.want, got)
})
}
}
diff --git a/pkg/terminal/util.go b/pkg/terminal/util.go
index 169bec2af..231b47974 100644
--- a/pkg/terminal/util.go
+++ b/pkg/terminal/util.go
@@ -61,7 +61,7 @@ func ReadPassword(prompt string) (pw []byte, err error) {
}
}
-func PublicKey(path string, passphrase []byte) (ssh.AuthMethod, error) {
+func PublicKey(path string, passphrase []byte) (ssh.Signer, error) {
key, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
@@ -75,12 +75,9 @@ func PublicKey(path string, passphrase []byte) (ssh.AuthMethod, error) {
if len(passphrase) == 0 {
passphrase = ReadPassphrase()
}
- signer, err = ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
- if err != nil {
- return nil, err
- }
+ return ssh.ParsePrivateKeyWithPassphrase(key, passphrase)
}
- return ssh.PublicKeys(signer), nil
+ return signer, nil
}
func ReadPassphrase() []byte {
diff --git a/pkg/util/utils_linux.go b/pkg/util/utils_linux.go
index e4957f442..288137ca5 100644
--- a/pkg/util/utils_linux.go
+++ b/pkg/util/utils_linux.go
@@ -6,7 +6,6 @@ import (
"path/filepath"
"syscall"
- "github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/psgo"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -53,19 +52,3 @@ func FindDeviceNodes() (map[string]string, error) {
return nodes, nil
}
-
-// CheckRootlessUIDRange checks the uid within the rootless container is in the range from /etc/subuid
-func CheckRootlessUIDRange(uid int) error {
- uids, _, err := rootless.GetConfiguredMappings()
- if err != nil {
- return err
- }
- total := 0
- for _, u := range uids {
- total += u.Size
- }
- if uid > total {
- return errors.Errorf("requested user's UID %d is too large for the rootless user namespace", uid)
- }
- return nil
-}
diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go
index a63c76415..21022eb7c 100644
--- a/pkg/util/utils_supported.go
+++ b/pkg/util/utils_supported.go
@@ -114,7 +114,7 @@ func GetRootlessPauseProcessPidPath() (string, error) {
// files.
func GetRootlessPauseProcessPidPathGivenDir(libpodTmpDir string) (string, error) {
if libpodTmpDir == "" {
- return "", errors.Errorf("must provide non-empty tmporary directory")
+ return "", errors.Errorf("must provide non-empty temporary directory")
}
return filepath.Join(libpodTmpDir, "pause.pid"), nil
}
diff --git a/pkg/util/utils_unsupported.go b/pkg/util/utils_unsupported.go
index f8d5a37c1..62805d7c8 100644
--- a/pkg/util/utils_unsupported.go
+++ b/pkg/util/utils_unsupported.go
@@ -10,8 +10,3 @@ import (
func FindDeviceNodes() (map[string]string, error) {
return nil, errors.Errorf("not supported on non-Linux OSes")
}
-
-// CheckRootlessUIDRange is not implemented anywhere except Linux.
-func CheckRootlessUIDRange(uid int) error {
- return nil
-}