From efcffde620f74316492fe08f71f022e1cfab2351 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Mon, 18 Jan 2021 14:49:53 -0500 Subject: Fix handling of container remove I found several problems with container remove podman-remote rm --all Was not handled podman-remote rm --ignore Was not handled Return better errors when attempting to remove an --external container. Currently we return the container does not exists, as opposed to container is an external container that is being used. This patch also consolidates the tunnel code to use the same code for removing the container, as the local API, removing duplication of code and potential problems. Signed-off-by: Daniel J Walsh --- cmd/podman/containers/rm.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index ee9dc4c78..ea616b6e5 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -3,6 +3,7 @@ package containers import ( "context" "fmt" + "io/ioutil" "strings" "github.com/containers/common/pkg/completion" @@ -54,6 +55,7 @@ var ( var ( rmOptions = entities.RmOptions{} + cidFiles = []string{} ) func rmFlags(cmd *cobra.Command) { @@ -65,7 +67,7 @@ func rmFlags(cmd *cobra.Command) { flags.BoolVarP(&rmOptions.Volumes, "volumes", "v", false, "Remove anonymous volumes associated with the container") cidfileFlagName := "cidfile" - flags.StringArrayVarP(&rmOptions.CIDFiles, cidfileFlagName, "", nil, "Read the container ID from the file") + flags.StringArrayVar(&cidFiles, cidfileFlagName, nil, "Read the container ID from the file") _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) if !registry.IsRemote() { @@ -92,7 +94,16 @@ func init() { validate.AddLatestFlag(containerRmCommand, &rmOptions.Latest) } -func rm(_ *cobra.Command, args []string) error { +func rm(cmd *cobra.Command, args []string) error { + for _, cidFile := range cidFiles { + content, err := ioutil.ReadFile(string(cidFile)) + if err != nil { + return errors.Wrap(err, "error reading CIDFile") + } + id := strings.Split(string(content), "\n")[0] + args = append(args, id) + } + return removeContainers(args, rmOptions, true) } -- cgit v1.2.3-54-g00ecf From 7c05d5292b326f6faa0acbe1d7600336f62951c1 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Wed, 20 Jan 2021 17:13:54 -0500 Subject: Switch podman stop/kill/wait handlers to use abi Change API Handlers to use the same functions that the local podman uses. At the same time: implement remote API for --all and --ignore flags for podman stop implement remote API for --all flags for podman stop Signed-off-by: Daniel J Walsh --- cmd/podman/containers/kill.go | 15 +++- cmd/podman/containers/stop.go | 14 +++- cmd/podman/containers/wait.go | 2 +- pkg/api/handlers/compat/containers.go | 92 ++++++++++++++----------- pkg/api/handlers/compat/containers_restart.go | 42 +++++++---- pkg/api/handlers/compat/containers_stop.go | 44 +++++++++--- pkg/api/handlers/libpod/containers.go | 6 ++ pkg/api/handlers/utils/containers.go | 33 +++++---- pkg/api/server/register_containers.go | 23 ++++++- pkg/bindings/containers/containers.go | 31 +++------ pkg/bindings/containers/types.go | 4 +- pkg/bindings/containers/types_kill_options.go | 16 +++++ pkg/bindings/containers/types_remove_options.go | 16 ----- pkg/bindings/containers/types_stop_options.go | 16 +++++ pkg/bindings/containers/types_wait_options.go | 16 +++++ pkg/bindings/test/containers_test.go | 12 ++-- pkg/domain/entities/containers.go | 16 ++--- pkg/domain/infra/abi/containers.go | 17 ----- pkg/domain/infra/tunnel/containers.go | 24 ++----- test/e2e/kill_test.go | 16 +++++ test/e2e/restart_test.go | 22 ++++++ test/e2e/stop_test.go | 41 ++++++++++- 22 files changed, 344 insertions(+), 174 deletions(-) (limited to 'cmd') diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go index 28040e08a..36e3e5f59 100644 --- a/cmd/podman/containers/kill.go +++ b/cmd/podman/containers/kill.go @@ -2,8 +2,9 @@ package containers import ( "context" - "errors" "fmt" + "io/ioutil" + "strings" "github.com/containers/common/pkg/completion" "github.com/containers/podman/v2/cmd/podman/common" @@ -12,6 +13,7 @@ import ( "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/signal" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -59,7 +61,7 @@ func killFlags(cmd *cobra.Command) { flags.StringVarP(&killOptions.Signal, signalFlagName, "s", "KILL", "Signal to send to the container") _ = cmd.RegisterFlagCompletionFunc(signalFlagName, common.AutocompleteStopSignal) cidfileFlagName := "cidfile" - flags.StringArrayVar(&killOptions.CIDFiles, cidfileFlagName, []string{}, "Read the container ID from the file") + flags.StringArrayVar(&cidFiles, cidfileFlagName, []string{}, "Read the container ID from the file") _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) } @@ -94,6 +96,15 @@ func kill(_ *cobra.Command, args []string) error { if sig < 1 || sig > 64 { return errors.New("valid signals are 1 through 64") } + for _, cidFile := range cidFiles { + content, err := ioutil.ReadFile(string(cidFile)) + if err != nil { + return errors.Wrap(err, "error reading CIDFile") + } + id := strings.Split(string(content), "\n")[0] + args = append(args, id) + } + responses, err := registry.ContainerEngine().ContainerKill(context.Background(), args, killOptions) if err != nil { return err diff --git a/cmd/podman/containers/stop.go b/cmd/podman/containers/stop.go index 3a4211357..7338c8d98 100644 --- a/cmd/podman/containers/stop.go +++ b/cmd/podman/containers/stop.go @@ -3,6 +3,8 @@ package containers import ( "context" "fmt" + "io/ioutil" + "strings" "github.com/containers/common/pkg/completion" "github.com/containers/podman/v2/cmd/podman/common" @@ -10,6 +12,7 @@ import ( "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -58,7 +61,7 @@ func stopFlags(cmd *cobra.Command) { flags.BoolVarP(&stopOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing") cidfileFlagName := "cidfile" - flags.StringArrayVarP(&stopOptions.CIDFiles, cidfileFlagName, "", nil, "Read the container ID from the file") + flags.StringArrayVar(&cidFiles, cidfileFlagName, nil, "Read the container ID from the file") _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) timeFlagName := "time" @@ -97,6 +100,15 @@ func stop(cmd *cobra.Command, args []string) error { stopOptions.Timeout = &stopTimeout } + for _, cidFile := range cidFiles { + content, err := ioutil.ReadFile(string(cidFile)) + if err != nil { + return errors.Wrap(err, "error reading CIDFile") + } + id := strings.Split(string(content), "\n")[0] + args = append(args, id) + } + responses, err := registry.ContainerEngine().ContainerStop(context.Background(), args, stopOptions) if err != nil { return err diff --git a/cmd/podman/containers/wait.go b/cmd/podman/containers/wait.go index 2bbfbccc9..14d660678 100644 --- a/cmd/podman/containers/wait.go +++ b/cmd/podman/containers/wait.go @@ -50,7 +50,7 @@ func waitFlags(cmd *cobra.Command) { flags := cmd.Flags() intervalFlagName := "interval" - flags.StringVarP(&waitInterval, intervalFlagName, "i", "250ns", "Time Interval to wait before polling for completion") + flags.StringVarP(&waitInterval, intervalFlagName, "i", "250ms", "Time Interval to wait before polling for completion") _ = cmd.RegisterFlagCompletionFunc(intervalFlagName, completion.AutocompleteNone) conditionFlagName := "condition" diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index de8366587..c174dc9dd 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -32,11 +32,11 @@ import ( func RemoveContainer(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - All bool `schema:"all"` - Force bool `schema:"force"` - Ignore bool `schema:"ignore"` - Link bool `schema:"link"` - Volumes bool `schema:"v"` + Force bool `schema:"force"` + Ignore bool `schema:"ignore"` + Link bool `schema:"link"` + DockerVolumes bool `schema:"v"` + LibpodVolumes bool `schema:"volumes"` }{ // override any golang type defaults } @@ -47,10 +47,19 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) { return } - if query.Link && !utils.IsLibpodRequest(r) { - utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, - utils.ErrLinkNotSupport) - return + options := entities.RmOptions{ + Force: query.Force, + Ignore: query.Ignore, + } + if utils.IsLibpodRequest(r) { + options.Volumes = query.LibpodVolumes + } else { + if query.Link { + utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, + utils.ErrLinkNotSupport) + return + } + options.Volumes = query.DockerVolumes } runtime := r.Context().Value("runtime").(*libpod.Runtime) @@ -58,12 +67,6 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) { // code. containerEngine := abi.ContainerEngine{Libpod: runtime} name := utils.GetName(r) - options := entities.RmOptions{ - All: query.All, - Force: query.Force, - Volumes: query.Volumes, - Ignore: query.Ignore, - } report, err := containerEngine.ContainerRm(r.Context(), []string{name}, options) if err != nil { if errors.Cause(err) == define.ErrNoSuchCtr { @@ -194,45 +197,48 @@ func KillContainer(w http.ResponseWriter, r *http.Request) { return } - sig, err := signal.ParseSignalNameOrNumber(query.Signal) - if err != nil { - utils.InternalServerError(w, err) - return - } + // Now use the ABI implementation to prevent us from having duplicate + // code. + containerEngine := abi.ContainerEngine{Libpod: runtime} name := utils.GetName(r) - con, err := runtime.LookupContainer(name) - if err != nil { - utils.ContainerNotFound(w, name, err) - return + options := entities.KillOptions{ + Signal: query.Signal, } - - state, err := con.State() + report, err := containerEngine.ContainerKill(r.Context(), []string{name}, options) if err != nil { - utils.InternalServerError(w, err) - return - } + if errors.Cause(err) == define.ErrCtrStateInvalid || + errors.Cause(err) == define.ErrCtrStopped { + utils.Error(w, fmt.Sprintf("Container %s is not running", name), http.StatusConflict, err) + return + } + if errors.Cause(err) == define.ErrNoSuchCtr { + utils.ContainerNotFound(w, name, err) + return + } - // If the Container is stopped already, send a 409 - if state == define.ContainerStateStopped || state == define.ContainerStateExited { - utils.Error(w, fmt.Sprintf("Container %s is not running", name), http.StatusConflict, errors.New(fmt.Sprintf("Cannot kill Container %s, it is not running", name))) + utils.InternalServerError(w, err) return } - signal := uint(sig) - - err = con.Kill(signal) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "unable to kill Container %s", name)) + if len(report) > 0 && report[0].Err != nil { + utils.InternalServerError(w, report[0].Err) return } - // Docker waits for the container to stop if the signal is 0 or // SIGKILL. - if !utils.IsLibpodRequest(r) && (signal == 0 || syscall.Signal(signal) == syscall.SIGKILL) { - if _, err = con.Wait(); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to wait for Container %s", con.ID())) + if !utils.IsLibpodRequest(r) { + sig, err := signal.ParseSignalNameOrNumber(query.Signal) + if err != nil { + utils.InternalServerError(w, err) return } + if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL { + var opts entities.WaitOptions + if _, err := containerEngine.ContainerWait(r.Context(), []string{name}, opts); err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + } } // Success utils.WriteResponse(w, http.StatusNoContent, nil) @@ -243,6 +249,10 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) { // /{version}/containers/(name)/wait exitCode, err := utils.WaitContainer(w, r) if err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr { + logrus.Warnf("container not found %q: %v", utils.GetName(r), err) + return + } logrus.Warnf("failed to wait on container %q: %v", mux.Vars(r)["name"], err) return } diff --git a/pkg/api/handlers/compat/containers_restart.go b/pkg/api/handlers/compat/containers_restart.go index e8928596a..70edfcbb3 100644 --- a/pkg/api/handlers/compat/containers_restart.go +++ b/pkg/api/handlers/compat/containers_restart.go @@ -4,7 +4,10 @@ import ( "net/http" "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers/utils" + "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/infra/abi" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -12,34 +15,49 @@ import ( func RestartContainer(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) + // Now use the ABI implementation to prevent us from having duplicate + // code. + containerEngine := abi.ContainerEngine{Libpod: runtime} + // /{version}/containers/(name)/restart query := struct { - Timeout int `schema:"t"` + All bool `schema:"all"` + DockerTimeout uint `schema:"t"` + LibpodTimeout uint `schema:"timeout"` }{ - // Override golang default values for types + // override any golang type defaults } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.BadRequest(w, "url", r.URL.String(), errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, + errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } name := utils.GetName(r) - con, err := runtime.LookupContainer(name) - if err != nil { - utils.ContainerNotFound(w, name, err) - return - } - timeout := con.StopTimeout() - if _, found := r.URL.Query()["t"]; found { - timeout = uint(query.Timeout) + options := entities.RestartOptions{ + All: query.All, + Timeout: &query.DockerTimeout, + } + if utils.IsLibpodRequest(r) { + options.Timeout = &query.LibpodTimeout } + report, err := containerEngine.ContainerRestart(r.Context(), []string{name}, options) + if err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr { + utils.ContainerNotFound(w, name, err) + return + } - if err := con.RestartWithTimeout(r.Context(), timeout); err != nil { utils.InternalServerError(w, err) return } + if len(report) > 0 && report[0].Err != nil { + utils.InternalServerError(w, report[0].Err) + return + } + // Success utils.WriteResponse(w, http.StatusNoContent, nil) } diff --git a/pkg/api/handlers/compat/containers_stop.go b/pkg/api/handlers/compat/containers_stop.go index 8bc58cf59..000685aa0 100644 --- a/pkg/api/handlers/compat/containers_stop.go +++ b/pkg/api/handlers/compat/containers_stop.go @@ -6,6 +6,8 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers/utils" + "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/infra/abi" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -13,10 +15,15 @@ import ( func StopContainer(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) + // Now use the ABI implementation to prevent us from having duplicate + // code. + containerEngine := abi.ContainerEngine{Libpod: runtime} // /{version}/containers/(name)/stop query := struct { - Timeout int `schema:"t"` + Ignore bool `schema:"ignore"` + DockerTimeout uint `schema:"t"` + LibpodTimeout uint `schema:"timeout"` }{ // override any golang type defaults } @@ -27,31 +34,46 @@ func StopContainer(w http.ResponseWriter, r *http.Request) { } name := utils.GetName(r) + + options := entities.StopOptions{ + Ignore: query.Ignore, + } + if utils.IsLibpodRequest(r) { + if query.LibpodTimeout > 0 { + options.Timeout = &query.LibpodTimeout + } + } else { + if query.DockerTimeout > 0 { + options.Timeout = &query.DockerTimeout + } + } con, err := runtime.LookupContainer(name) if err != nil { utils.ContainerNotFound(w, name, err) return } - state, err := con.State() if err != nil { - utils.InternalServerError(w, errors.Wrapf(err, "unable to get state for Container %s", name)) + utils.InternalServerError(w, err) return } - // If the Container is stopped already, send a 304 if state == define.ContainerStateStopped || state == define.ContainerStateExited { utils.WriteResponse(w, http.StatusNotModified, nil) return } + report, err := containerEngine.ContainerStop(r.Context(), []string{name}, options) + if err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr { + utils.ContainerNotFound(w, name, err) + return + } - var stopError error - if query.Timeout > 0 { - stopError = con.StopWithTimeout(uint(query.Timeout)) - } else { - stopError = con.Stop() + utils.InternalServerError(w, err) + return } - if stopError != nil { - utils.InternalServerError(w, errors.Wrapf(stopError, "failed to stop %s", name)) + + if len(report) > 0 && report[0].Err != nil { + utils.InternalServerError(w, report[0].Err) return } diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index 6b07b1cc5..fcfa0476f 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -143,6 +143,12 @@ func GetContainer(w http.ResponseWriter, r *http.Request) { func WaitContainer(w http.ResponseWriter, r *http.Request) { exitCode, err := utils.WaitContainer(w, r) if err != nil { + name := utils.GetName(r) + if errors.Cause(err) == define.ErrNoSuchCtr { + utils.ContainerNotFound(w, name, err) + return + } + logrus.Warnf("failed to wait on container %q: %v", name, err) return } utils.WriteResponse(w, http.StatusOK, strconv.Itoa(int(exitCode))) diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go index 1439a3a75..fac237f87 100644 --- a/pkg/api/handlers/utils/containers.go +++ b/pkg/api/handlers/utils/containers.go @@ -6,6 +6,8 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" + "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/infra/abi" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -16,10 +18,13 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) { interval time.Duration ) runtime := r.Context().Value("runtime").(*libpod.Runtime) + // Now use the ABI implementation to prevent us from having duplicate + // code. + containerEngine := abi.ContainerEngine{Libpod: runtime} decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Interval string `schema:"interval"` - Condition string `schema:"condition"` + Interval string `schema:"interval"` + Condition define.ContainerStatus `schema:"condition"` }{ // Override golang default values for types } @@ -27,6 +32,10 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) { Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return 0, err } + options := entities.WaitOptions{ + Condition: define.ContainerStateStopped, + } + name := GetName(r) if _, found := r.URL.Query()["interval"]; found { interval, err = time.ParseDuration(query.Interval) if err != nil { @@ -40,19 +49,19 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) { return 0, err } } - condition := define.ContainerStateStopped + options.Interval = interval + if _, found := r.URL.Query()["condition"]; found { - condition, err = define.StringToContainerStatus(query.Condition) - if err != nil { - InternalServerError(w, err) - return 0, err - } + options.Condition = query.Condition } - name := GetName(r) - con, err := runtime.LookupContainer(name) + + report, err := containerEngine.ContainerWait(r.Context(), []string{name}, options) if err != nil { - ContainerNotFound(w, name, err) return 0, err } - return con.WaitForConditionWithInterval(interval, condition) + if len(report) == 0 { + InternalServerError(w, errors.New("No reports returned")) + return 0, err + } + return report[0].ExitCode, report[0].Error } diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index 74a04b2e6..f73238384 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -194,6 +194,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // required: true // description: the name or ID of the container // - in: query + // name: all + // type: boolean + // default: false + // description: Send kill signal to all containers + // - in: query // name: signal // type: string // default: TERM @@ -481,6 +486,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - paused // - running // - stopped + // - in: query + // name: interval + // type: string + // default: "250ms" + // description: Time Interval to wait before polling for completion. // produces: // - application/json // responses: @@ -1214,9 +1224,20 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // required: true // description: the name or ID of the container // - in: query - // name: t + // name: all + // type: boolean + // default: false + // description: Stop all containers + // - in: query + // name: timeout // type: integer + // default: 10 // description: number of seconds to wait before killing container + // - in: query + // name: Ignore + // type: boolean + // default: false + // description: do not return error if container is already stopped // produces: // - application/json // responses: diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 40fcfbded..8e644b712 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -5,7 +5,6 @@ import ( "io" "net/http" "net/url" - "strconv" "strings" "github.com/containers/podman/v2/libpod/define" @@ -83,18 +82,9 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error if err != nil { return err } - params := url.Values{} - if v := options.GetVolumes(); options.Changed("Volumes") { - params.Set("v", strconv.FormatBool(v)) - } - if all := options.GetAll(); options.Changed("All") { - params.Set("all", strconv.FormatBool(all)) - } - if force := options.GetForce(); options.Changed("Force") { - params.Set("force", strconv.FormatBool(force)) - } - if ignore := options.GetIgnore(); options.Changed("Ignore") { - params.Set("ignore", strconv.FormatBool(ignore)) + params, err := options.ToParams() + if err != nil { + return err } response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID) if err != nil { @@ -130,7 +120,7 @@ func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*de // 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, options *KillOptions) error { +func Kill(ctx context.Context, nameOrID string, options *KillOptions) error { if options == nil { options = new(KillOptions) } @@ -142,7 +132,6 @@ func Kill(ctx context.Context, nameOrID string, sig string, options *KillOptions 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 { return err @@ -180,9 +169,9 @@ func Restart(ctx context.Context, nameOrID string, options *RestartOptions) erro if err != nil { return err } - params := url.Values{} - if options.Changed("Timeout") { - params.Set("t", strconv.Itoa(options.GetTimeout())) + params, err := options.ToParams() + if err != nil { + return err } response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nil, nameOrID) if err != nil { @@ -335,9 +324,9 @@ func Wait(ctx context.Context, nameOrID string, options *WaitOptions) (int32, er if err != nil { return exitCode, err } - params := url.Values{} - if options.Changed("Condition") { - params.Set("condition", options.GetCondition().String()) + params, err := options.ToParams() + if err != nil { + return exitCode, err } response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nil, nameOrID) if err != nil { diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index 24604fa83..a7130809e 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -122,7 +122,6 @@ type PruneOptions struct { //go:generate go run ../generator/generator.go RemoveOptions // RemoveOptions are optional options for removing containers type RemoveOptions struct { - All *bool Ignore *bool Force *bool Volumes *bool @@ -137,6 +136,7 @@ type InspectOptions struct { //go:generate go run ../generator/generator.go KillOptions // KillOptions are optional options for killing containers type KillOptions struct { + Signal *string } //go:generate go run ../generator/generator.go PauseOptions @@ -176,11 +176,13 @@ type UnpauseOptions struct{} // WaitOptions are optional options for waiting on containers type WaitOptions struct { Condition *define.ContainerStatus + Interval *string } //go:generate go run ../generator/generator.go StopOptions // StopOptions are optional options for stopping containers type StopOptions struct { + Ignore *bool Timeout *uint } diff --git a/pkg/bindings/containers/types_kill_options.go b/pkg/bindings/containers/types_kill_options.go index dd84f0d9f..c5d5a3c6a 100644 --- a/pkg/bindings/containers/types_kill_options.go +++ b/pkg/bindings/containers/types_kill_options.go @@ -86,3 +86,19 @@ func (o *KillOptions) ToParams() (url.Values, error) { } 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/containers/types_remove_options.go b/pkg/bindings/containers/types_remove_options.go index 3ef32fa03..ffe1488c1 100644 --- a/pkg/bindings/containers/types_remove_options.go +++ b/pkg/bindings/containers/types_remove_options.go @@ -87,22 +87,6 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { 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 -} - // WithIgnore func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions { v := &value diff --git a/pkg/bindings/containers/types_stop_options.go b/pkg/bindings/containers/types_stop_options.go index db692dbf0..940ec5832 100644 --- a/pkg/bindings/containers/types_stop_options.go +++ b/pkg/bindings/containers/types_stop_options.go @@ -87,6 +87,22 @@ func (o *StopOptions) ToParams() (url.Values, error) { return params, nil } +// WithIgnore +func (o *StopOptions) WithIgnore(value bool) *StopOptions { + v := &value + o.Ignore = v + return o +} + +// GetIgnore +func (o *StopOptions) GetIgnore() bool { + var ignore bool + if o.Ignore == nil { + return ignore + } + return *o.Ignore +} + // WithTimeout func (o *StopOptions) WithTimeout(value uint) *StopOptions { v := &value diff --git a/pkg/bindings/containers/types_wait_options.go b/pkg/bindings/containers/types_wait_options.go index 470d67611..2f5aa983e 100644 --- a/pkg/bindings/containers/types_wait_options.go +++ b/pkg/bindings/containers/types_wait_options.go @@ -103,3 +103,19 @@ func (o *WaitOptions) GetCondition() define.ContainerStatus { } return *o.Condition } + +// WithInterval +func (o *WaitOptions) WithInterval(value string) *WaitOptions { + v := &value + o.Interval = v + return o +} + +// GetInterval +func (o *WaitOptions) GetInterval() string { + var interval string + if o.Interval == nil { + return interval + } + return *o.Interval +} diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index 3d7526cb8..9b9f98047 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -443,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", nil) + err := containers.Kill(bt.conn, "foobar", new(containers.KillOptions).WithSignal("SIGTERM")) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) @@ -454,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", nil) + err = containers.Kill(bt.conn, name, new(containers.KillOptions).WithSignal("SIGINT")) Expect(err).To(BeNil()) _, err = containers.Exists(bt.conn, name, nil) Expect(err).To(BeNil()) @@ -465,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", nil) + err = containers.Kill(bt.conn, cid, new(containers.KillOptions).WithSignal("SIGTERM")) Expect(err).To(BeNil()) _, err = containers.Exists(bt.conn, cid, nil) Expect(err).To(BeNil()) @@ -476,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", nil) + err = containers.Kill(bt.conn, cid, new(containers.KillOptions).WithSignal("SIGKILL")) Expect(err).To(BeNil()) }) @@ -485,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", nil) + err = containers.Kill(bt.conn, cid, new(containers.KillOptions).WithSignal("foobar")) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -501,7 +501,7 @@ var _ = Describe("Podman containers ", func() { Expect(err).To(BeNil()) 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", nil) + err = containers.Kill(bt.conn, containerLatestList[0].Names[0], new(containers.KillOptions).WithSignal("SIGTERM")) Expect(err).To(BeNil()) }) diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 4c1bd6a7d..573185c7b 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -81,11 +81,10 @@ type PauseUnpauseReport struct { } type StopOptions struct { - All bool - CIDFiles []string - Ignore bool - Latest bool - Timeout *uint + All bool + Ignore bool + Latest bool + Timeout *uint } type StopReport struct { @@ -104,10 +103,9 @@ type TopOptions struct { } type KillOptions struct { - All bool - Latest bool - Signal string - CIDFiles []string + All bool + Latest bool + Signal string } type KillReport struct { diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 48a32817d..d0599a595 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -6,7 +6,6 @@ import ( "io/ioutil" "os" "strconv" - "strings" "sync" "time" @@ -139,14 +138,6 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st } func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) { names := namesOrIds - 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] - names = append(names, id) - } ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod) if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { return nil, err @@ -202,14 +193,6 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities. } 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 diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 524b29553..09bc7eede 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "os" "strconv" "strings" @@ -41,7 +40,7 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin return nil, err } responses := make([]entities.WaitReport, 0, len(cons)) - options := new(containers.WaitOptions).WithCondition(opts.Condition) + options := new(containers.WaitOptions).WithCondition(opts.Condition).WithInterval(opts.Interval.String()) for _, c := range cons { response := entities.WaitReport{Id: c.ID} exitCode, err := containers.Wait(ic.ClientCtx, c.ID, options) @@ -83,19 +82,11 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, opts entities.StopOptions) ([]*entities.StopReport, error) { reports := []*entities.StopReport{} - 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, opts.Ignore, namesOrIds) if err != nil { return nil, err } - options := new(containers.StopOptions) + options := new(containers.StopOptions).WithIgnore(opts.Ignore) if to := opts.Timeout; to != nil { options.WithTimeout(*to) } @@ -126,23 +117,16 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin } 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 } + options := new(containers.KillOptions).WithSignal(opts.Signal) reports := make([]*entities.KillReport, 0, len(ctrs)) for _, c := range ctrs { reports = append(reports, &entities.KillReport{ Id: c.ID, - Err: containers.Kill(ic.ClientCtx, c.ID, opts.Signal, nil), + Err: containers.Kill(ic.ClientCtx, c.ID, options), }) } return reports, nil diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go index 8b31cae72..c1c1b003e 100644 --- a/test/e2e/kill_test.go +++ b/test/e2e/kill_test.go @@ -167,4 +167,20 @@ var _ = Describe("Podman kill", func() { Expect(wait.ExitCode()).To(BeZero()) }) + It("podman stop --all", func() { + session := podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + + session = podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) + + session = podmanTest.Podman([]string{"kill", "--all"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) }) diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go index 76362dcbf..bfe9563ea 100644 --- a/test/e2e/restart_test.go +++ b/test/e2e/restart_test.go @@ -225,4 +225,26 @@ var _ = Describe("Podman restart", func() { // line count should be equal Expect(beforeRestart.OutputToString()).To(Equal(afterRestart.OutputToString())) }) + + It("podman restart --all", func() { + session := podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + + session = podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) + + session = podmanTest.Podman([]string{"stop", "--all"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + + session = podmanTest.Podman([]string{"restart", "--all"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) + }) }) diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go index c25709a63..750d38ffb 100644 --- a/test/e2e/stop_test.go +++ b/test/e2e/stop_test.go @@ -164,13 +164,14 @@ var _ = Describe("Podman stop", func() { }) It("podman stop container --timeout", func() { - session := podmanTest.RunTopContainer("test5") + session := podmanTest.Podman([]string{"run", "-d", "--name", "test5", ALPINE, "sleep", "100"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) cid1 := session.OutputToString() - session = podmanTest.Podman([]string{"stop", "--timeout", "1", "test5"}) - session.WaitWithDefaultTimeout() + // Without timeout container stops in 10 seconds + // If not stopped in 5 seconds, then --timeout did not work + session.Wait(5) Expect(session.ExitCode()).To(Equal(0)) output := session.OutputToString() Expect(output).To(ContainSubstring(cid1)) @@ -307,4 +308,38 @@ var _ = Describe("Podman stop", func() { result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(125)) }) + + It("podman stop --all", func() { + session := podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + + session = podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) + + session = podmanTest.Podman([]string{"stop", "--all"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) + + It("podman stop --ignore", func() { + session := podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToString() + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + + session = podmanTest.Podman([]string{"stop", "bogus", cid}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(125)) + + session = podmanTest.Podman([]string{"stop", "--ignore", "bogus", cid}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) }) -- cgit v1.2.3-54-g00ecf From 5da474dec055a678a2870e54f017c022ba4bf71a Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Mon, 25 Jan 2021 09:41:55 -0500 Subject: Fix --arch and --os flags to work correctly Currently podman implements --override-arch and --overide-os But Podman has made these aliases for --arch and --os. No reason to have to specify --override, since it is clear what the user intends. Currently if the user specifies an --override-arch field but the image was previously pulled for a different Arch, podman run uses the different arch. This PR also fixes this issue. Fixes: https://github.com/containers/podman/issues/8001 Signed-off-by: Daniel J Walsh --- cmd/podman/common/create.go | 26 +++++++-------- cmd/podman/common/create_opts.go | 12 +++---- cmd/podman/containers/create.go | 27 +++++++++------- cmd/podman/images/pull.go | 28 ++++++++-------- cmd/podman/manifest/add.go | 4 +-- cmd/podman/manifest/annotate.go | 4 +-- cmd/podman/utils/alias.go | 6 ++++ docs/source/markdown/podman-create.1.md | 16 ++++----- docs/source/markdown/podman-pull.1.md | 22 ++++++------- docs/source/markdown/podman-run.1.md | 16 ++++----- pkg/api/handlers/libpod/images_pull.go | 18 +++++------ pkg/api/server/register_images.go | 6 ++-- pkg/bindings/images/types.go | 12 +++---- pkg/bindings/images/types_pull_options.go | 54 +++++++++++++++---------------- pkg/domain/entities/images.go | 12 +++---- pkg/domain/infra/abi/images.go | 6 ++-- pkg/domain/infra/tunnel/images.go | 4 +-- test/e2e/create_test.go | 12 +++---- test/e2e/pull_test.go | 10 +++--- 19 files changed, 152 insertions(+), 143 deletions(-) (limited to 'cmd') diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 17fba5427..915ff63b6 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -474,29 +474,29 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { ) _ = cmd.RegisterFlagCompletionFunc(oomScoreAdjFlagName, completion.AutocompleteNone) - overrideArchFlagName := "override-arch" + archFlagName := "arch" createFlags.StringVar( - &cf.OverrideArch, - overrideArchFlagName, "", + &cf.Arch, + archFlagName, "", "use `ARCH` instead of the architecture of the machine for choosing images", ) - _ = cmd.RegisterFlagCompletionFunc(overrideArchFlagName, completion.AutocompleteNone) + _ = cmd.RegisterFlagCompletionFunc(archFlagName, completion.AutocompleteArch) - overrideOSFlagName := "override-os" + osFlagName := "os" createFlags.StringVar( - &cf.OverrideOS, - overrideOSFlagName, "", + &cf.OS, + osFlagName, "", "use `OS` instead of the running OS for choosing images", ) - _ = cmd.RegisterFlagCompletionFunc(overrideOSFlagName, completion.AutocompleteNone) + _ = cmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS) - overrideVariantFlagName := "override-variant" + variantFlagName := "variant" createFlags.StringVar( - &cf.OverrideVariant, - overrideVariantFlagName, "", + &cf.Variant, + variantFlagName, "", "Use _VARIANT_ instead of the running architecture variant for choosing images", ) - _ = cmd.RegisterFlagCompletionFunc(overrideVariantFlagName, completion.AutocompleteNone) + _ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone) pidFlagName := "pid" createFlags.String( @@ -516,7 +516,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { createFlags.StringVar( &cf.Platform, platformFlagName, "", - "Specify the platform for selecting the image. (Conflicts with override-arch and override-os)", + "Specify the platform for selecting the image. (Conflicts with --arch and --os)", ) _ = cmd.RegisterFlagCompletionFunc(platformFlagName, completion.AutocompleteNone) diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index f3918d233..d86a6d364 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -74,9 +74,9 @@ type ContainerCLIOpts struct { NoHealthCheck bool OOMKillDisable bool OOMScoreAdj int - OverrideArch string - OverrideOS string - OverrideVariant string + Arch string + OS string + Variant string PID string PIDsLimit *int64 Platform string @@ -347,9 +347,9 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup LogOptions: stringMaptoArray(cc.HostConfig.LogConfig.Config), Name: cc.Name, OOMScoreAdj: cc.HostConfig.OomScoreAdj, - OverrideArch: "", - OverrideOS: "", - OverrideVariant: "", + Arch: "", + OS: "", + Variant: "", PID: string(cc.HostConfig.PidMode), PIDsLimit: cc.HostConfig.PidsLimit, Privileged: cc.HostConfig.Privileged, diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index 420813ba9..5c6c773eb 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -237,17 +237,20 @@ func pullImage(imageName string) (string, error) { imageMissing = !br.Value } - if cliVals.Platform != "" { - if cliVals.OverrideArch != "" || cliVals.OverrideOS != "" { - return "", errors.Errorf("--platform option can not be specified with --override-arch or --override-os") - } - split := strings.SplitN(cliVals.Platform, "/", 2) - cliVals.OverrideOS = split[0] - if len(split) > 1 { - cliVals.OverrideArch = split[1] + if cliVals.Platform != "" || cliVals.Arch != "" || cliVals.OS != "" { + if cliVals.Platform != "" { + if cliVals.Arch != "" || cliVals.OS != "" { + return "", errors.Errorf("--platform option can not be specified with --arch or --os") + } + split := strings.SplitN(cliVals.Platform, "/", 2) + cliVals.OS = split[0] + if len(split) > 1 { + cliVals.Arch = split[1] + } } + if pullPolicy != config.PullImageAlways { - logrus.Info("--platform causes the pull policy to be \"always\"") + logrus.Info("--platform --arch and --os causes the pull policy to be \"always\"") pullPolicy = config.PullImageAlways } } @@ -259,9 +262,9 @@ func pullImage(imageName string) (string, error) { pullReport, pullErr := registry.ImageEngine().Pull(registry.GetContext(), imageName, entities.ImagePullOptions{ Authfile: cliVals.Authfile, Quiet: cliVals.Quiet, - OverrideArch: cliVals.OverrideArch, - OverrideOS: cliVals.OverrideOS, - OverrideVariant: cliVals.OverrideVariant, + Arch: cliVals.Arch, + OS: cliVals.OS, + Variant: cliVals.Variant, SignaturePolicy: cliVals.SignaturePolicy, PullPolicy: pullPolicy, }) diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index 2d881a906..fe92baebe 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -84,20 +84,20 @@ func pullFlags(cmd *cobra.Command) { flags.StringVar(&pullOptions.CredentialsCLI, credsFlagName, "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") _ = cmd.RegisterFlagCompletionFunc(credsFlagName, completion.AutocompleteNone) - overrideArchFlagName := "override-arch" - flags.StringVar(&pullOptions.OverrideArch, overrideArchFlagName, "", "Use `ARCH` instead of the architecture of the machine for choosing images") - _ = cmd.RegisterFlagCompletionFunc(overrideArchFlagName, completion.AutocompleteNone) + archFlagName := "arch" + flags.StringVar(&pullOptions.Arch, archFlagName, "", "Use `ARCH` instead of the architecture of the machine for choosing images") + _ = cmd.RegisterFlagCompletionFunc(archFlagName, completion.AutocompleteArch) - overrideOsFlagName := "override-os" - flags.StringVar(&pullOptions.OverrideOS, overrideOsFlagName, "", "Use `OS` instead of the running OS for choosing images") - _ = cmd.RegisterFlagCompletionFunc(overrideOsFlagName, completion.AutocompleteNone) + osFlagName := "os" + flags.StringVar(&pullOptions.OS, osFlagName, "", "Use `OS` instead of the running OS for choosing images") + _ = cmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS) - overrideVariantFlagName := "override-variant" - flags.StringVar(&pullOptions.OverrideVariant, overrideVariantFlagName, "", " use VARIANT instead of the running architecture variant for choosing images") - _ = cmd.RegisterFlagCompletionFunc(overrideVariantFlagName, completion.AutocompleteNone) + variantFlagName := "variant" + flags.StringVar(&pullOptions.Variant, variantFlagName, "", " use VARIANT instead of the running architecture variant for choosing images") + _ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone) platformFlagName := "platform" - flags.String(platformFlagName, "", "Specify the platform for selecting the image. (Conflicts with override-arch and override-os)") + flags.String(platformFlagName, "", "Specify the platform for selecting the image. (Conflicts with arch and os)") _ = cmd.RegisterFlagCompletionFunc(platformFlagName, completion.AutocompleteNone) flags.Bool("disable-content-trust", false, "This is a Docker specific option and is a NOOP") @@ -138,13 +138,13 @@ func imagePull(cmd *cobra.Command, args []string) error { return err } if platform != "" { - if pullOptions.OverrideArch != "" || pullOptions.OverrideOS != "" { - return errors.Errorf("--platform option can not be specified with --override-arch or --override-os") + if pullOptions.Arch != "" || pullOptions.OS != "" { + return errors.Errorf("--platform option can not be specified with --arch or --os") } split := strings.SplitN(platform, "/", 2) - pullOptions.OverrideOS = split[0] + pullOptions.OS = split[0] if len(split) > 1 { - pullOptions.OverrideArch = split[1] + pullOptions.Arch = split[1] } } diff --git a/cmd/podman/manifest/add.go b/cmd/podman/manifest/add.go index cb0838eeb..b33f01c10 100644 --- a/cmd/podman/manifest/add.go +++ b/cmd/podman/manifest/add.go @@ -52,7 +52,7 @@ func init() { archFlagName := "arch" flags.StringVar(&manifestAddOpts.Arch, archFlagName, "", "override the `architecture` of the specified image") - _ = addCmd.RegisterFlagCompletionFunc(archFlagName, completion.AutocompleteNone) + _ = addCmd.RegisterFlagCompletionFunc(archFlagName, completion.AutocompleteArch) authfileFlagName := "authfile" flags.StringVar(&manifestAddOpts.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") @@ -72,7 +72,7 @@ func init() { osFlagName := "os" flags.StringVar(&manifestAddOpts.OS, osFlagName, "", "override the `OS` of the specified image") - _ = addCmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteNone) + _ = addCmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS) osVersionFlagName := "os-version" flags.StringVar(&manifestAddOpts.OSVersion, osVersionFlagName, "", "override the OS `version` of the specified image") diff --git a/cmd/podman/manifest/annotate.go b/cmd/podman/manifest/annotate.go index 71017e0ec..7c4f5ad01 100644 --- a/cmd/podman/manifest/annotate.go +++ b/cmd/podman/manifest/annotate.go @@ -39,7 +39,7 @@ func init() { archFlagName := "arch" flags.StringVar(&manifestAnnotateOpts.Arch, archFlagName, "", "override the `architecture` of the specified image") - _ = annotateCmd.RegisterFlagCompletionFunc(archFlagName, completion.AutocompleteNone) + _ = annotateCmd.RegisterFlagCompletionFunc(archFlagName, completion.AutocompleteArch) featuresFlagName := "features" flags.StringSliceVar(&manifestAnnotateOpts.Features, featuresFlagName, nil, "override the `features` of the specified image") @@ -47,7 +47,7 @@ func init() { osFlagName := "os" flags.StringVar(&manifestAnnotateOpts.OS, osFlagName, "", "override the `OS` of the specified image") - _ = annotateCmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteNone) + _ = annotateCmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS) osFeaturesFlagName := "os-features" flags.StringSliceVar(&manifestAnnotateOpts.OSFeatures, osFeaturesFlagName, nil, "override the OS `features` of the specified image") diff --git a/cmd/podman/utils/alias.go b/cmd/podman/utils/alias.go index 469233b59..8d089920b 100644 --- a/cmd/podman/utils/alias.go +++ b/cmd/podman/utils/alias.go @@ -25,6 +25,12 @@ func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName { name = "external" case "purge": name = "rm" + case "override-arch": + name = "arch" + case "override-os": + name = "os" + case "override-variant": + name = "variant" } return pflag.NormalizedName(name) } diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 02eeb557c..d89dba647 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -77,6 +77,9 @@ option can be set multiple times. Add an annotation to the container. The format is key=value. The **--annotation** option can be set multiple times. +#### **--arch**=*ARCH* +Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. + #### **--attach**, **-a**=*location* Attach to STDIN, STDOUT or STDERR. @@ -668,15 +671,9 @@ Whether to disable OOM Killer for the container or not. Tune the host's OOM preferences for containers (accepts -1000 to 1000) -#### **--override-arch**=*ARCH* -Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. - -#### **--override-os**=*OS* +#### **--os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. -#### **--override-variant**=*VARIANT* -Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. - #### **--pid**=*pid* Set the PID mode for the container @@ -692,7 +689,7 @@ Tune the container's pids limit. Set `0` to have unlimited pids for the containe #### **--platform**=*OS/ARCH* -Specify the platform for selecting the image. (Conflicts with override-arch and override-os) +Specify the platform for selecting the image. (Conflicts with --arch and --os) The `--platform` option can be used to override the current architecture and operating system. #### **--pod**=*name* @@ -1008,6 +1005,9 @@ Set the UTS namespace mode for the container. The following values are supported - **ns:[path]**: run the container in the given existing UTS namespace. - **container:[container]**: join the UTS namespace of the specified container. +#### **--variant**=*VARIANT* +Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. + #### **--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*] Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, Podman diff --git a/docs/source/markdown/podman-pull.1.md b/docs/source/markdown/podman-pull.1.md index 44a7e83b6..af91a59e9 100644 --- a/docs/source/markdown/podman-pull.1.md +++ b/docs/source/markdown/podman-pull.1.md @@ -71,6 +71,9 @@ All tagged images in the repository will be pulled. Note: When using the all-tags flag, Podman will not iterate over the search registries in the containers-registries.conf(5) but will always use docker.io for unqualified image names. +#### **--arch**=*ARCH* +Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. + #### **--authfile**=*path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. @@ -96,19 +99,16 @@ This is a Docker specific option to disable image verification to a Docker registry and is not supported by Podman. This flag is a NOOP and provided solely for scripting compatibility. -#### **--override-arch**=*ARCH* -Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. - -#### **--override-os**=*OS* -Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. +#### **--help**, **-h** -#### **--override-variant**=*VARIANT* +Print usage statement -Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. +#### **--os**=*OS* +Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. #### **--platform**=*OS/ARCH* -Specify the platform for selecting the image. (Conflicts with override-arch and override-os) +Specify the platform for selecting the image. (Conflicts with --arch and --os) The `--platform` option can be used to override the current architecture and operating system. #### **--quiet**, **-q** @@ -121,9 +121,9 @@ Require HTTPS and verify certificates when contacting registries (default: true) then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified, TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf. -#### **--help**, **-h** +#### **--variant**=*VARIANT* -Print usage statement +Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. ## EXAMPLES @@ -189,7 +189,7 @@ Storing signatures ``` ``` -$ podman pull --override-arch=arm arm32v7/debian:stretch +$ podman pull --arch=arm arm32v7/debian:stretch Trying to pull docker.io/arm32v7/debian:stretch... Getting image source signatures Copying blob b531ae4a3925 done diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index edcd63935..60d6ec598 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -93,6 +93,9 @@ This option can be set multiple times. Add an annotation to the container. This option can be set multiple times. +#### **--arch**=*ARCH* +Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. + #### **--attach**, **-a**=**stdin**|**stdout**|**stderr** Attach to STDIN, STDOUT or STDERR. @@ -705,15 +708,9 @@ Whether to disable OOM Killer for the container or not. Tune the host's OOM preferences for containers (accepts values from **-1000** to **1000**). -#### **--override-arch**=*ARCH* -Override the architecture, defaults to hosts, of the image to be pulled. For example, `arm`. - -#### **--override-os**=*OS* +#### **--os**=*OS* Override the OS, defaults to hosts, of the image to be pulled. For example, `windows`. -#### **--override-variant**=*VARIANT* -Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. - #### **--pid**=*mode* Set the PID namespace mode for the container. @@ -730,7 +727,7 @@ Tune the container's pids limit. Set to **0** to have unlimited pids for the con #### **--platform**=*OS/ARCH* -Specify the platform for selecting the image. (Conflicts with override-arch and override-os) +Specify the platform for selecting the image. (Conflicts with --arch and --os) The `--platform` option can be used to override the current architecture and operating system. #### **--pod**=*name* @@ -1083,6 +1080,9 @@ Set the UTS namespace mode for the container. The following values are supported - **ns:[path]**: run the container in the given existing UTS namespace. - **container:[container]**: join the UTS namespace of the specified container. +#### **--variant**=*VARIANT* +Use _VARIANT_ instead of the default architecture variant of the container image. Some images can use multiple variants of the arm architectures, such as arm/v5 and arm/v7. + #### **--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*] Create a bind mount. If you specify _/HOST-DIR_:_/CONTAINER-DIR_, Podman diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index bacba006d..efb15b14d 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -30,12 +30,12 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Reference string `schema:"reference"` - OverrideOS string `schema:"overrideOS"` - OverrideArch string `schema:"overrideArch"` - OverrideVariant string `schema:"overrideVariant"` - TLSVerify bool `schema:"tlsVerify"` - AllTags bool `schema:"allTags"` + Reference string `schema:"reference"` + OS string `schema:"OS"` + Arch string `schema:"Arch"` + Variant string `schema:"Variant"` + TLSVerify bool `schema:"tlsVerify"` + AllTags bool `schema:"allTags"` }{ TLSVerify: true, } @@ -83,9 +83,9 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { // Setup the registry options dockerRegistryOptions := image.DockerRegistryOptions{ DockerRegistryCreds: authConf, - OSChoice: query.OverrideOS, - ArchitectureChoice: query.OverrideArch, - VariantChoice: query.OverrideVariant, + OSChoice: query.OS, + ArchitectureChoice: query.Arch, + VariantChoice: query.Variant, } if _, found := r.URL.Query()["tlsVerify"]; found { dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 8d0c0800b..8f072c427 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -930,15 +930,15 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // description: "username:password for the registry" // type: string // - in: query - // name: overrideArch + // name: Arch // description: Pull image for the specified architecture. // type: string // - in: query - // name: overrideOS + // name: OS // description: Pull image for the specified operating system. // type: string // - in: query - // name: overrideVariant + // name: Variant // description: Pull image for the specified variant. // type: string // - in: query diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go index f216dd073..0248f2fa6 100644 --- a/pkg/bindings/images/types.go +++ b/pkg/bindings/images/types.go @@ -171,13 +171,13 @@ type PullOptions struct { 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 + // Arch will overwrite the local architecture for image pulls. + Arch *string + // OS will overwrite the local operating system (OS) for image // pulls. - OverrideOS *string - // OverrideVariant will overwrite the local variant for image pulls. - OverrideVariant *string + OS *string + // Variant will overwrite the local variant for image pulls. + Variant *string // Quiet can be specified to suppress pull progress when pulling. Ignored // for remote calls. Quiet *bool diff --git a/pkg/bindings/images/types_pull_options.go b/pkg/bindings/images/types_pull_options.go index 5163a6341..2bdf2b66e 100644 --- a/pkg/bindings/images/types_pull_options.go +++ b/pkg/bindings/images/types_pull_options.go @@ -168,52 +168,52 @@ func (o *PullOptions) GetPassword() string { return *o.Password } -// WithOverrideArch -func (o *PullOptions) WithOverrideArch(value string) *PullOptions { +// WithArch +func (o *PullOptions) WithArch(value string) *PullOptions { v := &value - o.OverrideArch = v + o.Arch = v return o } -// GetOverrideArch -func (o *PullOptions) GetOverrideArch() string { - var overrideArch string - if o.OverrideArch == nil { - return overrideArch +// GetArch +func (o *PullOptions) GetArch() string { + var arch string + if o.Arch == nil { + return arch } - return *o.OverrideArch + return *o.Arch } -// WithOverrideOS -func (o *PullOptions) WithOverrideOS(value string) *PullOptions { +// WithOS +func (o *PullOptions) WithOS(value string) *PullOptions { v := &value - o.OverrideOS = v + o.OS = v return o } -// GetOverrideOS -func (o *PullOptions) GetOverrideOS() string { - var overrideOS string - if o.OverrideOS == nil { - return overrideOS +// GetOS +func (o *PullOptions) GetOS() string { + var oS string + if o.OS == nil { + return oS } - return *o.OverrideOS + return *o.OS } -// WithOverrideVariant -func (o *PullOptions) WithOverrideVariant(value string) *PullOptions { +// WithVariant +func (o *PullOptions) WithVariant(value string) *PullOptions { v := &value - o.OverrideVariant = v + o.Variant = v return o } -// GetOverrideVariant -func (o *PullOptions) GetOverrideVariant() string { - var overrideVariant string - if o.OverrideVariant == nil { - return overrideVariant +// GetVariant +func (o *PullOptions) GetVariant() string { + var variant string + if o.Variant == nil { + return variant } - return *o.OverrideVariant + return *o.Variant } // WithQuiet diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 78a7d8aa7..ef40d5490 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -133,13 +133,13 @@ type ImagePullOptions struct { 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 + // Arch will overwrite the local architecture for image pulls. + Arch string + // OS will overwrite the local operating system (OS) for image // pulls. - OverrideOS string - // OverrideVariant will overwrite the local variant for image pulls. - OverrideVariant string + OS string + // Variant will overwrite the local variant for image pulls. + Variant string // Quiet can be specified to suppress pull progress when pulling. Ignored // for remote calls. Quiet bool diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 1288ab09b..8ca93e770 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -241,9 +241,9 @@ func pull(ctx context.Context, runtime *image.Runtime, rawImage string, options dockerRegistryOptions := image.DockerRegistryOptions{ DockerRegistryCreds: registryCreds, DockerCertPath: options.CertDir, - OSChoice: options.OverrideOS, - ArchitectureChoice: options.OverrideArch, - VariantChoice: options.OverrideVariant, + OSChoice: options.OS, + ArchitectureChoice: options.Arch, + VariantChoice: options.Variant, DockerInsecureSkipTLSVerify: options.SkipTLSVerify, } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 2d686b2aa..0de756756 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -106,8 +106,8 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption 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) + options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithCertDir(opts.CertDir).WithArch(opts.Arch).WithOS(opts.OS) + options.WithVariant(opts.Variant).WithPassword(opts.Password).WithPullPolicy(opts.PullPolicy) if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { if s == types.OptionalBoolTrue { options.WithSkipTLSVerify(true) diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 2e9f5455d..67c08ac09 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -282,7 +282,7 @@ var _ = Describe("Podman create", func() { }) It("podman create using image list by tag", func() { - session := podmanTest.Podman([]string{"create", "--pull=always", "--override-arch=arm64", "--name=foo", ALPINELISTTAG}) + session := podmanTest.Podman([]string{"create", "--pull=always", "--arch=arm64", "--name=foo", ALPINELISTTAG}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To((Equal(0))) session = podmanTest.Podman([]string{"inspect", "--format", "{{.Image}}", "foo"}) @@ -296,7 +296,7 @@ var _ = Describe("Podman create", func() { }) It("podman create using image list by digest", func() { - session := podmanTest.Podman([]string{"create", "--pull=always", "--override-arch=arm64", "--name=foo", ALPINELISTDIGEST}) + session := podmanTest.Podman([]string{"create", "--pull=always", "--arch=arm64", "--name=foo", ALPINELISTDIGEST}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To((Equal(0))) session = podmanTest.Podman([]string{"inspect", "--format", "{{.Image}}", "foo"}) @@ -310,7 +310,7 @@ var _ = Describe("Podman create", func() { }) It("podman create using image list instance by digest", func() { - session := podmanTest.Podman([]string{"create", "--pull=always", "--override-arch=arm64", "--name=foo", ALPINEARM64DIGEST}) + session := podmanTest.Podman([]string{"create", "--pull=always", "--arch=arm64", "--name=foo", ALPINEARM64DIGEST}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To((Equal(0))) session = podmanTest.Podman([]string{"inspect", "--format", "{{.Image}}", "foo"}) @@ -324,7 +324,7 @@ var _ = Describe("Podman create", func() { }) It("podman create using cross-arch image list instance by digest", func() { - session := podmanTest.Podman([]string{"create", "--pull=always", "--override-arch=arm64", "--name=foo", ALPINEARM64DIGEST}) + session := podmanTest.Podman([]string{"create", "--pull=always", "--arch=arm64", "--name=foo", ALPINEARM64DIGEST}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To((Equal(0))) session = podmanTest.Podman([]string{"inspect", "--format", "{{.Image}}", "foo"}) @@ -652,10 +652,10 @@ var _ = Describe("Podman create", func() { expectedError := "no image found in manifest list for architecture bogus" Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) - session = podmanTest.Podman([]string{"create", "--platform=linux/arm64", "--override-os", "windows", ALPINE}) + session = podmanTest.Podman([]string{"create", "--platform=linux/arm64", "--os", "windows", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(125)) - expectedError = "--platform option can not be specified with --override-arch or --override-os" + expectedError = "--platform option can not be specified with --arch or --os" Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) session = podmanTest.Podman([]string{"create", "-q", "--platform=linux/arm64", ALPINE}) diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go index 7099a2904..4b73004da 100644 --- a/test/e2e/pull_test.go +++ b/test/e2e/pull_test.go @@ -92,7 +92,7 @@ var _ = Describe("Podman pull", func() { }) It("podman pull by digest (image list)", func() { - session := podmanTest.Podman([]string{"pull", "--override-arch=arm64", ALPINELISTDIGEST}) + session := podmanTest.Podman([]string{"pull", "--arch=arm64", ALPINELISTDIGEST}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) // inspect using the digest of the list @@ -135,7 +135,7 @@ var _ = Describe("Podman pull", func() { }) It("podman pull by instance digest (image list)", func() { - session := podmanTest.Podman([]string{"pull", "--override-arch=arm64", ALPINEARM64DIGEST}) + session := podmanTest.Podman([]string{"pull", "--arch=arm64", ALPINEARM64DIGEST}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) // inspect using the digest of the list @@ -175,7 +175,7 @@ var _ = Describe("Podman pull", func() { }) It("podman pull by tag (image list)", func() { - session := podmanTest.Podman([]string{"pull", "--override-arch=arm64", ALPINELISTTAG}) + session := podmanTest.Podman([]string{"pull", "--arch=arm64", ALPINELISTTAG}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) // inspect using the tag we used for pulling @@ -503,10 +503,10 @@ var _ = Describe("Podman pull", func() { expectedError := "no image found in manifest list for architecture bogus" Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) - session = podmanTest.Podman([]string{"pull", "--platform=linux/arm64", "--override-os", "windows", ALPINE}) + session = podmanTest.Podman([]string{"pull", "--platform=linux/arm64", "--os", "windows", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(125)) - expectedError = "--platform option can not be specified with --override-arch or --override-os" + expectedError = "--platform option can not be specified with --arch or --os" Expect(session.ErrorToString()).To(ContainSubstring(expectedError)) session = podmanTest.Podman([]string{"pull", "-q", "--platform=linux/arm64", ALPINE}) -- cgit v1.2.3-54-g00ecf From 0838a9414d8949cd4b30bb2574c0994eb2e0b8cf Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Mon, 25 Jan 2021 17:49:44 -0500 Subject: podman-remote ps --external --pod --sort do not work. Fixup the bindings and the handling of the --external --por and --sort flags. The --storage option was renamed --external, make sure we use external up and down the stack. Signed-off-by: Daniel J Walsh --- cmd/podman/containers/ps.go | 8 +++---- cmd/podman/containers/rm.go | 4 ++++ pkg/api/handlers/compat/containers.go | 2 +- pkg/api/handlers/libpod/containers.go | 17 +++++++++----- pkg/api/server/register_containers.go | 5 ++++ pkg/bindings/containers/types.go | 1 + pkg/bindings/containers/types_list_options.go | 16 +++++++++++++ pkg/domain/entities/containers.go | 2 +- pkg/domain/infra/tunnel/containers.go | 33 +++++++++++++++++++-------- pkg/ps/ps.go | 2 +- test/e2e/ps_test.go | 7 ++++-- test/e2e/rm_test.go | 2 +- test/system/040-ps.bats | 17 +++++++------- 13 files changed, 81 insertions(+), 35 deletions(-) (limited to 'cmd') diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go index d23771fc5..31f44d92f 100644 --- a/cmd/podman/containers/ps.go +++ b/cmd/podman/containers/ps.go @@ -78,7 +78,7 @@ func listFlagSet(cmd *cobra.Command) { flags := cmd.Flags() flags.BoolVarP(&listOpts.All, "all", "a", false, "Show all the containers, default is only running containers") - flags.BoolVar(&listOpts.Storage, "external", false, "Show containers in storage not controlled by Podman") + flags.BoolVar(&listOpts.External, "external", false, "Show containers in storage not controlled by Podman") filterFlagName := "filter" flags.StringSliceVarP(&filters, filterFlagName, "f", []string{}, "Filter output based on conditions given") @@ -132,10 +132,10 @@ func checkFlags(c *cobra.Command) error { } cfg := registry.PodmanConfig() if cfg.Engine.Namespace != "" { - if c.Flag("storage").Changed && listOpts.Storage { - return errors.New("--namespace and --storage flags can not both be set") + if c.Flag("storage").Changed && listOpts.External { + return errors.New("--namespace and --external flags can not both be set") } - listOpts.Storage = false + listOpts.External = false } return nil diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index ea616b6e5..884ad05f4 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -140,6 +140,10 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit } func setExitCode(err error) { + // If error is set to no such container, do not reset + if registry.GetExitCode() == 1 { + return + } cause := errors.Cause(err) switch { case cause == define.ErrNoSuchCtr: diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index c174dc9dd..b41987800 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -77,7 +77,7 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - if report[0].Err != nil { + if len(report) > 0 && report[0].Err != nil { utils.InternalServerError(w, report[0].Err) return } diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index fcfa0476f..f6e348cef 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -12,7 +12,6 @@ import ( "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/infra/abi" - "github.com/containers/podman/v2/pkg/ps" "github.com/gorilla/schema" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -63,6 +62,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { All bool `schema:"all"` + External bool `schema:"external"` Filters map[string][]string `schema:"filters"` Last int `schema:"last"` // alias for limit Limit int `schema:"limit"` @@ -90,17 +90,22 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { } runtime := r.Context().Value("runtime").(*libpod.Runtime) + // Now use the ABI implementation to prevent us from having duplicate + // code. + containerEngine := abi.ContainerEngine{Libpod: runtime} opts := entities.ContainerListOptions{ All: query.All, + External: query.External, Filters: query.Filters, Last: limit, - Size: query.Size, - Sort: "", Namespace: query.Namespace, - Pod: true, - Sync: query.Sync, + // Always return Pod, should not be part of the API. + // https://github.com/containers/podman/pull/7223 + Pod: true, + Size: query.Size, + Sync: query.Sync, } - pss, err := ps.GetContainerLists(runtime, opts) + pss, err := containerEngine.ContainerList(r.Context(), opts) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index f73238384..ff1781d1e 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -48,6 +48,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // default: false // description: Return all containers. By default, only running containers are shown // - in: query + // name: external + // type: boolean + // default: false + // description: Return containers in storage not controlled by Podman + // - in: query // name: limit // description: Return this number of most recently created containers, including non-running ones. // type: integer diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index a7130809e..771cde72c 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -106,6 +106,7 @@ type MountedContainerPathsOptions struct{} // ListOptions are optional options for listing containers type ListOptions struct { All *bool + External *bool Filters map[string][]string Last *int Namespace *bool diff --git a/pkg/bindings/containers/types_list_options.go b/pkg/bindings/containers/types_list_options.go index 43326fa59..c363dcd32 100644 --- a/pkg/bindings/containers/types_list_options.go +++ b/pkg/bindings/containers/types_list_options.go @@ -103,6 +103,22 @@ func (o *ListOptions) GetAll() bool { return *o.All } +// WithExternal +func (o *ListOptions) WithExternal(value bool) *ListOptions { + v := &value + o.External = v + return o +} + +// GetExternal +func (o *ListOptions) GetExternal() bool { + var external bool + if o.External == nil { + return external + } + return *o.External +} + // WithFilters func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions { v := value diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 573185c7b..63be5578f 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -295,8 +295,8 @@ type ContainerListOptions struct { Pod bool Quiet bool Size bool + External bool Sort string - Storage bool Sync bool Watch uint } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 09bc7eede..e9c513f8e 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -157,19 +157,32 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st } func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*entities.RmReport, error) { - 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 { + options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes).WithIgnore(opts.Ignore) + + if opts.All { + ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds) + if err != nil { + return nil, err + } + reports := make([]*entities.RmReport, 0, len(ctrs)) + for _, c := range ctrs { + reports = append(reports, &entities.RmReport{ + Id: c.ID, + Err: containers.Remove(ic.ClientCtx, c.ID, options), + }) + } + return reports, nil + } + + reports := make([]*entities.RmReport, 0, len(namesOrIds)) + for _, name := range namesOrIds { reports = append(reports, &entities.RmReport{ - Id: c.ID, - Err: containers.Remove(ic.ClientCtx, c.ID, options), + Id: name, + Err: containers.Remove(ic.ClientCtx, name, options), }) } + return reports, nil } @@ -585,7 +598,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri 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) + options.WithNamespace(opts.Namespace).WithSize(opts.Size).WithSync(opts.Sync).WithExternal(opts.External) return containers.List(ic.ClientCtx, options) } diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go index dc577890a..42f9e1d39 100644 --- a/pkg/ps/ps.go +++ b/pkg/ps/ps.go @@ -69,7 +69,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp pss = append(pss, listCon) } - if options.All && options.Storage { + if options.All && options.External { externCons, err := runtime.StorageContainers() if err != nil { return nil, err diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index 1b3dca7b7..db3f7a36b 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -396,11 +396,14 @@ var _ = Describe("Podman ps", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"ps", "--pod", "--no-trunc"}) - + session = podmanTest.Podman([]string{"ps", "--no-trunc"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Not(ContainSubstring(podid))) + session = podmanTest.Podman([]string{"ps", "--pod", "--no-trunc"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring(podid)) }) diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go index ca142d7f3..4c50a61ef 100644 --- a/test/e2e/rm_test.go +++ b/test/e2e/rm_test.go @@ -132,7 +132,7 @@ var _ = Describe("Podman rm", func() { latest := "-l" if IsRemote() { - latest = "test1" + latest = cid } result := podmanTest.Podman([]string{"rm", latest}) result.WaitWithDefaultTimeout() diff --git a/test/system/040-ps.bats b/test/system/040-ps.bats index 0ae8b0ce0..ae27c479f 100644 --- a/test/system/040-ps.bats +++ b/test/system/040-ps.bats @@ -82,11 +82,10 @@ load helpers run_podman rm -a } -@test "podman ps -a --storage" { - skip_if_remote "ps --storage does not work over remote" +@test "podman ps -a --external" { # Setup: ensure that we have no hidden storage containers - run_podman ps --storage -a + run_podman ps --external -a is "${#lines[@]}" "1" "setup check: no storage containers at start of test" # Force a buildah timeout; this leaves a buildah container behind @@ -98,18 +97,18 @@ EOF run_podman ps -a is "${#lines[@]}" "1" "podman ps -a does not see buildah container" - run_podman ps --storage -a - is "${#lines[@]}" "2" "podman ps -a --storage sees buildah container" + run_podman ps --external -a + is "${#lines[@]}" "2" "podman ps -a --external sees buildah container" is "${lines[1]}" \ "[0-9a-f]\{12\} \+$IMAGE *buildah .* seconds ago .* storage .* ${PODMAN_TEST_IMAGE_NAME}-working-container" \ - "podman ps --storage" + "podman ps --external" cid="${lines[1]:0:12}" # 'rm -a' should be a NOP run_podman rm -a - run_podman ps --storage -a - is "${#lines[@]}" "2" "podman ps -a --storage sees buildah container" + run_podman ps --external -a + is "${#lines[@]}" "2" "podman ps -a --external sees buildah container" # We can't rm it without -f, but podman should issue a helpful message run_podman 2 rm "$cid" @@ -118,7 +117,7 @@ EOF # With -f, we can remove it. run_podman rm -f "$cid" - run_podman ps --storage -a + run_podman ps --external -a is "${#lines[@]}" "1" "storage container has been removed" } -- cgit v1.2.3-54-g00ecf From 7819e49353b58fe87bdb74c33b2d999e3a7b563e Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Wed, 20 Jan 2021 17:13:54 -0500 Subject: Switch podman image push handlers to use abi Change API Handlers to use the same functions that the local podman uses. At the same time: Cleanup and pass proper bindings. Remove cli options from podman-remote push. Cleanup manifest push. Signed-off-by: Daniel J Walsh --- cmd/podman/images/push.go | 4 + docs/source/markdown/podman-push.1.md | 6 +- pkg/api/handlers/compat/images_push.go | 58 ++++++------ pkg/api/handlers/libpod/manifests.go | 12 +-- pkg/api/server/register_images.go | 12 +++ pkg/bindings/images/types.go | 29 +----- pkg/bindings/images/types_push_options.go | 144 ++++-------------------------- pkg/bindings/manifests/manifests.go | 1 - pkg/domain/infra/tunnel/images.go | 5 +- pkg/domain/infra/tunnel/manifest.go | 6 +- test/e2e/push_test.go | 20 +++-- test/system/150-login.bats | 1 + 12 files changed, 89 insertions(+), 209 deletions(-) (limited to 'cmd') diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go index d53a9c066..56f618539 100644 --- a/cmd/podman/images/push.go +++ b/cmd/podman/images/push.go @@ -114,7 +114,11 @@ func pushFlags(cmd *cobra.Command) { if registry.IsRemote() { _ = flags.MarkHidden("cert-dir") _ = flags.MarkHidden("compress") + _ = flags.MarkHidden("digestfile") + _ = flags.MarkHidden("format") _ = flags.MarkHidden("quiet") + _ = flags.MarkHidden("remove-signatures") + _ = flags.MarkHidden("sign-by") } _ = flags.MarkHidden("signature-policy") } diff --git a/docs/source/markdown/podman-push.1.md b/docs/source/markdown/podman-push.1.md index f7624ed5f..9e5a57962 100644 --- a/docs/source/markdown/podman-push.1.md +++ b/docs/source/markdown/podman-push.1.md @@ -91,7 +91,7 @@ solely for scripting compatibility. #### **--format**, **-f**=*format* Manifest Type (oci, v2s1, or v2s2) to use when pushing an image to a directory using the 'dir:' transport (default is manifest type of source) -Note: This flag can only be set when using the **dir** transport +Note: This flag can only be set when using the **dir** transport. (Not available for remote commands) #### **--quiet**, **-q** @@ -99,11 +99,11 @@ When writing the output image, suppress progress output #### **--remove-signatures** -Discard any pre-existing signatures in the image +Discard any pre-existing signatures in the image. (Not available for remote commands) #### **--sign-by**=*key* -Add a signature at the destination using the specified key +Add a signature at the destination using the specified key. (Not available for remote commands) #### **--tls-verify**=*true|false* diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go index 0f3da53e8..4a8fcdff3 100644 --- a/pkg/api/handlers/compat/images_push.go +++ b/pkg/api/handlers/compat/images_push.go @@ -3,13 +3,14 @@ package compat import ( "context" "net/http" - "os" "strings" "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/auth" + "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/infra/abi" + "github.com/containers/storage" "github.com/gorilla/schema" "github.com/pkg/errors" ) @@ -18,11 +19,19 @@ import ( func PushImage(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) runtime := r.Context().Value("runtime").(*libpod.Runtime) + // Now use the ABI implementation to prevent us from having duplicate + // code. + imageEngine := abi.ImageEngine{Libpod: runtime} query := struct { - Tag string `schema:"tag"` + All bool `schema:"all"` + Compress bool `schema:"compress"` + Destination string `schema:"destination"` + Tag string `schema:"tag"` + TLSVerify bool `schema:"tlsVerify"` }{ // This is where you can override the golang default value for one of fields + TLSVerify: true, } if err := decoder.Decode(&query, r.URL.Query()); err != nil { @@ -43,39 +52,30 @@ func PushImage(w http.ResponseWriter, r *http.Request) { return } - newImage, err := runtime.ImageRuntime().NewFromLocal(imageName) - if err != nil { - utils.ImageNotFound(w, imageName, errors.Wrapf(err, "failed to find image %s", imageName)) - return - } - - authConf, authfile, key, err := auth.GetCredentials(r) + authconf, authfile, key, err := auth.GetCredentials(r) if err != nil { utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String())) return } defer auth.RemoveAuthfile(authfile) - - dockerRegistryOptions := &image.DockerRegistryOptions{DockerRegistryCreds: authConf} - if sys := runtime.SystemContext(); sys != nil { - dockerRegistryOptions.DockerCertPath = sys.DockerCertPath - dockerRegistryOptions.RegistriesConfPath = sys.SystemRegistriesConfPath + var username, password string + if authconf != nil { + username = authconf.Username + password = authconf.Password + } + options := entities.ImagePushOptions{ + All: query.All, + Authfile: authfile, + Compress: query.Compress, + Username: username, + Password: password, } + if err := imageEngine.Push(context.Background(), imageName, query.Destination, options); err != nil { + if errors.Cause(err) != storage.ErrImageUnknown { + utils.ImageNotFound(w, imageName, errors.Wrapf(err, "failed to find image %s", imageName)) + return + } - err = newImage.PushImageToHeuristicDestination( - context.Background(), - imageName, - "", // manifest type - authfile, - "", // digest file - "", // signature policy - os.Stderr, - false, // force compression - image.SigningOptions{}, - dockerRegistryOptions, - nil, // additional tags - ) - if err != nil { utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "error pushing image %q", imageName)) return } diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go index dce861f6f..0f202efb5 100644 --- a/pkg/api/handlers/libpod/manifests.go +++ b/pkg/api/handlers/libpod/manifests.go @@ -129,7 +129,6 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) { query := struct { All bool `schema:"all"` Destination string `schema:"destination"` - Format string `schema:"format"` TLSVerify bool `schema:"tlsVerify"` }{ // Add defaults here once needed. @@ -145,24 +144,21 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) { } source := utils.GetName(r) - authConf, authfile, key, err := auth.GetCredentials(r) + authconf, authfile, key, err := auth.GetCredentials(r) if err != nil { utils.Error(w, "failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String())) return } defer auth.RemoveAuthfile(authfile) var username, password string - if authConf != nil { - username = authConf.Username - password = authConf.Password - + if authconf != nil { + username = authconf.Username + password = authconf.Password } - options := entities.ImagePushOptions{ Authfile: authfile, Username: username, Password: password, - Format: query.Format, All: query.All, } if sys := runtime.SystemContext(); sys != nil { diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 8f072c427..b973095a4 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -235,6 +235,18 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // name: tag // type: string // description: The tag to associate with the image on the registry. + // - in: query + // name: all + // type: boolean + // description: All indicates whether to push all images related to the image list + // - in: query + // name: compress + // type: boolean + // description: use compression on image + // - in: query + // name: destination + // type: string + // description: destination name for the image being pushed // - in: header // name: X-Registry-Auth // type: string diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go index 0248f2fa6..75f1a2f81 100644 --- a/pkg/bindings/images/types.go +++ b/pkg/bindings/images/types.go @@ -104,37 +104,14 @@ 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 tarball image layers when pushing to a directory using the 'dir' transport. 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 + // Username for authenticating against the registry. + Username *string } //go:generate go run ../generator/generator.go SearchOptions diff --git a/pkg/bindings/images/types_push_options.go b/pkg/bindings/images/types_push_options.go index 0c12ce4ac..7f9bb1064 100644 --- a/pkg/bindings/images/types_push_options.go +++ b/pkg/bindings/images/types_push_options.go @@ -119,22 +119,6 @@ func (o *PushOptions) GetAuthfile() string { 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 @@ -151,22 +135,6 @@ func (o *PushOptions) GetCompress() bool { 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 @@ -183,102 +151,6 @@ func (o *PushOptions) GetPassword() string { 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 @@ -294,3 +166,19 @@ func (o *PushOptions) GetSkipTLSVerify() bool { } return *o.SkipTLSVerify } + +// 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 +} diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go index b6db64b02..5f046176f 100644 --- a/pkg/bindings/manifests/manifests.go +++ b/pkg/bindings/manifests/manifests.go @@ -140,7 +140,6 @@ func Push(ctx context.Context, name, destination string, options *images.PushOpt } params.Set("image", name) params.Set("destination", destination) - params.Set("format", *options.Format) _, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, nil, name) if err != nil { return "", err diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 0de756756..878e7b999 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -236,10 +236,7 @@ func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOpti 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) + options.WithAll(opts.All).WithCompress(opts.Compress).WithUsername(opts.Username).WithPassword(opts.Password).WithAuthfile(opts.Authfile) if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { if s == types.OptionalBoolTrue { diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go index 22ca44165..8be110d74 100644 --- a/pkg/domain/infra/tunnel/manifest.go +++ b/pkg/domain/infra/tunnel/manifest.go @@ -77,10 +77,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, name, destination string, opts entities.ImagePushOptions) (string, 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) + options.WithUsername(opts.Username).WithPassword(opts.Password).WithAuthfile(opts.Authfile) + options.WithAll(opts.All) if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { if s == types.OptionalBoolTrue { diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go index 922995060..10120751f 100644 --- a/test/e2e/push_test.go +++ b/test/e2e/push_test.go @@ -54,10 +54,16 @@ var _ = Describe("Podman push", func() { fmt.Sprintf("dir:%s", bbdir)}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + + bbdir = filepath.Join(podmanTest.TempDir, "busybox") + session = podmanTest.Podman([]string{"push", "--format", "oci", ALPINE, + fmt.Sprintf("dir:%s", bbdir)}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) }) It("podman push to local registry", func() { - SkipIfRemote("FIXME: This should work") + SkipIfRemote("Remote does not support --digestfile or --remove-sginatures") if podmanTest.Host.Arch == "ppc64le" { Skip("No registry image for ppc64le") } @@ -74,7 +80,7 @@ var _ = Describe("Podman push", func() { Skip("Cannot start docker registry.") } - push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"}) + push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) @@ -88,7 +94,6 @@ var _ = Describe("Podman push", func() { }) It("podman push to local registry with authorization", func() { - SkipIfRemote("FIXME: This does not seem to be returning an error") SkipIfRootless("FIXME: Creating content in certs.d we use directories in homedir") if podmanTest.Host.Arch == "ppc64le" { Skip("No registry image for ppc64le") @@ -155,9 +160,12 @@ var _ = Describe("Podman push", func() { push.WaitWithDefaultTimeout() Expect(push).To(ExitWithError()) - push = podmanTest.Podman([]string{"push", "--creds=podmantest:test", "--cert-dir=fakedir", ALPINE, "localhost:5000/certdirtest"}) - push.WaitWithDefaultTimeout() - Expect(push).To(ExitWithError()) + if !IsRemote() { + // remote does not support --cert-dir + push = podmanTest.Podman([]string{"push", "--creds=podmantest:test", "--cert-dir=fakedir", ALPINE, "localhost:5000/certdirtest"}) + push.WaitWithDefaultTimeout() + Expect(push).To(ExitWithError()) + } push = podmanTest.Podman([]string{"push", "--creds=podmantest:test", ALPINE, "localhost:5000/defaultflags"}) push.WaitWithDefaultTimeout() diff --git a/test/system/150-login.bats b/test/system/150-login.bats index 5151ab0e1..c3af63348 100644 --- a/test/system/150-login.bats +++ b/test/system/150-login.bats @@ -197,6 +197,7 @@ EOF destname=ok-$(random_string 10 | tr A-Z a-z)-ok # Use command-line credentials run_podman push --tls-verify=false \ + --format docker \ --creds ${PODMAN_LOGIN_USER}:${PODMAN_LOGIN_PASS} \ $IMAGE localhost:${PODMAN_LOGIN_REGISTRY_PORT}/$destname -- cgit v1.2.3-54-g00ecf From d6625f2948f182bfe01ec81d95f9865973f3ad3b Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Mon, 1 Feb 2021 21:23:44 +0100 Subject: Improve ContainerEngine.ContainerWait() Signed-off-by: Matej Vasek --- cmd/podman/containers/wait.go | 3 ++- pkg/api/handlers/utils/containers.go | 6 +++--- pkg/bindings/containers/types.go | 2 +- pkg/bindings/containers/types_wait_options.go | 10 +++++----- pkg/bindings/test/attach_test.go | 2 +- pkg/bindings/test/common_test.go | 2 +- pkg/bindings/test/containers_test.go | 4 ++-- pkg/domain/entities/containers.go | 2 +- pkg/domain/infra/abi/containers.go | 2 +- 9 files changed, 17 insertions(+), 16 deletions(-) (limited to 'cmd') diff --git a/cmd/podman/containers/wait.go b/cmd/podman/containers/wait.go index 14d660678..7a531b98a 100644 --- a/cmd/podman/containers/wait.go +++ b/cmd/podman/containers/wait.go @@ -95,10 +95,11 @@ func wait(cmd *cobra.Command, args []string) error { return errors.New("--latest and containers cannot be used together") } - waitOptions.Condition, err = define.StringToContainerStatus(waitCondition) + cond, err := define.StringToContainerStatus(waitCondition) if err != nil { return err } + waitOptions.Condition = []define.ContainerStatus{cond} responses, err := registry.ContainerEngine().ContainerWait(context.Background(), args, waitOptions) if err != nil { diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go index fac237f87..7443f9b46 100644 --- a/pkg/api/handlers/utils/containers.go +++ b/pkg/api/handlers/utils/containers.go @@ -23,8 +23,8 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) { containerEngine := abi.ContainerEngine{Libpod: runtime} decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Interval string `schema:"interval"` - Condition define.ContainerStatus `schema:"condition"` + Interval string `schema:"interval"` + Condition []define.ContainerStatus `schema:"condition"` }{ // Override golang default values for types } @@ -33,7 +33,7 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) { return 0, err } options := entities.WaitOptions{ - Condition: define.ContainerStateStopped, + Condition: []define.ContainerStatus{define.ContainerStateStopped}, } name := GetName(r) if _, found := r.URL.Query()["interval"]; found { diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index 771cde72c..4889b444a 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -176,7 +176,7 @@ 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 + Condition []define.ContainerStatus Interval *string } diff --git a/pkg/bindings/containers/types_wait_options.go b/pkg/bindings/containers/types_wait_options.go index 005cc38cb..a3f1e3b8c 100644 --- a/pkg/bindings/containers/types_wait_options.go +++ b/pkg/bindings/containers/types_wait_options.go @@ -76,19 +76,19 @@ func (o *WaitOptions) ToParams() (url.Values, error) { } // WithCondition -func (o *WaitOptions) WithCondition(value define.ContainerStatus) *WaitOptions { - v := &value +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 +func (o *WaitOptions) GetCondition() []define.ContainerStatus { + var condition []define.ContainerStatus if o.Condition == nil { return condition } - return *o.Condition + return o.Condition } // WithInterval diff --git a/pkg/bindings/test/attach_test.go b/pkg/bindings/test/attach_test.go index 9a46f6309..771b2d528 100644 --- a/pkg/bindings/test/attach_test.go +++ b/pkg/bindings/test/attach_test.go @@ -75,7 +75,7 @@ var _ = Describe("Podman containers attach", func() { Expect(err).ShouldNot(HaveOccurred()) wait := define.ContainerStateRunning - _, err = containers.Wait(bt.conn, ctnr.ID, new(containers.WaitOptions).WithCondition(wait)) + _, err = containers.Wait(bt.conn, ctnr.ID, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{wait})) Expect(err).ShouldNot(HaveOccurred()) tickTock := time.NewTimer(2 * time.Second) diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go index c2b1347d2..8fbc631d8 100644 --- a/pkg/bindings/test/common_test.go +++ b/pkg/bindings/test/common_test.go @@ -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, new(containers.WaitOptions).WithCondition(wait)) + _, err = containers.Wait(b.conn, ctr.ID, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{wait})) return ctr.ID, err } diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index 9b9f98047..14eb1ffc6 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -281,7 +281,7 @@ var _ = Describe("Podman containers ", func() { _, err := bt.RunTopContainer(&name, nil, nil) Expect(err).To(BeNil()) go func() { - exitCode, err = containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition(pause)) + exitCode, err = containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{pause})) errChan <- err close(errChan) }() @@ -295,7 +295,7 @@ var _ = Describe("Podman containers ", func() { go func() { defer GinkgoRecover() - _, waitErr := containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition(running)) + _, waitErr := containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{running})) unpauseErrChan <- waitErr close(unpauseErrChan) }() diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 63be5578f..2d50d6826 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -51,7 +51,7 @@ type ContainerRunlabelReport struct { } type WaitOptions struct { - Condition define.ContainerStatus + Condition []define.ContainerStatus Interval time.Duration Latest bool } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index cfd3d7272..7a672d863 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -100,7 +100,7 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin responses := make([]entities.WaitReport, 0, len(ctrs)) for _, c := range ctrs { response := entities.WaitReport{Id: c.ID()} - exitCode, err := c.WaitForConditionWithInterval(ctx, options.Interval, options.Condition) + exitCode, err := c.WaitForConditionWithInterval(ctx, options.Interval, options.Condition...) if err != nil { response.Error = err } else { -- cgit v1.2.3-54-g00ecf