diff options
Diffstat (limited to 'pkg/api/handlers/libpod')
-rw-r--r-- | pkg/api/handlers/libpod/containers.go | 28 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/play.go | 2 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/pods.go | 101 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/volumes.go | 17 |
4 files changed, 107 insertions, 41 deletions
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index 343c0d0b3..3aeebc334 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -214,6 +214,7 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) { TCPEstablished bool `schema:"tcpEstablished"` Export bool `schema:"export"` IgnoreRootFS bool `schema:"ignoreRootFS"` + PrintStats bool `schema:"printStats"` }{ // override any golang type defaults } @@ -248,11 +249,12 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) { KeepRunning: query.LeaveRunning, TCPEstablished: query.TCPEstablished, IgnoreRootfs: query.IgnoreRootFS, + PrintStats: query.PrintStats, } if query.Export { options.TargetFile = targetFile } - err = ctr.Checkpoint(r.Context(), options) + criuStatistics, runtimeCheckpointDuration, err := ctr.Checkpoint(r.Context(), options) if err != nil { utils.InternalServerError(w, err) return @@ -267,7 +269,15 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) { utils.WriteResponse(w, http.StatusOK, f) return } - utils.WriteResponse(w, http.StatusOK, entities.CheckpointReport{Id: ctr.ID()}) + utils.WriteResponse( + w, + http.StatusOK, + entities.CheckpointReport{ + Id: ctr.ID(), + RuntimeDuration: runtimeCheckpointDuration, + CRIUStatistics: criuStatistics, + }, + ) } func Restore(w http.ResponseWriter, r *http.Request) { @@ -284,6 +294,7 @@ func Restore(w http.ResponseWriter, r *http.Request) { IgnoreVolumes bool `schema:"ignoreVolumes"` IgnoreStaticIP bool `schema:"ignoreStaticIP"` IgnoreStaticMAC bool `schema:"ignoreStaticMAC"` + PrintStats bool `schema:"printStats"` }{ // override any golang type defaults } @@ -319,17 +330,26 @@ func Restore(w http.ResponseWriter, r *http.Request) { IgnoreRootfs: query.IgnoreRootFS, IgnoreStaticIP: query.IgnoreStaticIP, IgnoreStaticMAC: query.IgnoreStaticMAC, + PrintStats: query.PrintStats, } if query.Import { options.TargetFile = targetFile options.Name = query.Name } - err = ctr.Restore(r.Context(), options) + criuStatistics, runtimeRestoreDuration, err := ctr.Restore(r.Context(), options) if err != nil { utils.InternalServerError(w, err) return } - utils.WriteResponse(w, http.StatusOK, entities.RestoreReport{Id: ctr.ID()}) + utils.WriteResponse( + w, + http.StatusOK, + entities.RestoreReport{ + Id: ctr.ID(), + RuntimeDuration: runtimeRestoreDuration, + CRIUStatistics: criuStatistics, + }, + ) } func InitContainer(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go index 851e0f6c8..f943fc240 100644 --- a/pkg/api/handlers/libpod/play.go +++ b/pkg/api/handlers/libpod/play.go @@ -26,6 +26,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) { Network string `schema:"network"` TLSVerify bool `schema:"tlsVerify"` LogDriver string `schema:"logDriver"` + LogOptions []string `schema:"logOptions"` Start bool `schema:"start"` StaticIPs []string `schema:"staticIPs"` StaticMACs []string `schema:"staticMACs"` @@ -106,6 +107,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) { NoHosts: query.NoHosts, Quiet: true, LogDriver: query.LogDriver, + LogOptions: query.LogOptions, StaticIPs: staticIPs, StaticMACs: staticMACs, } diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index 77d026550..3d18406a5 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -1,15 +1,13 @@ package libpod import ( - "context" "encoding/json" "fmt" "net/http" "strings" + "time" - "github.com/containers/common/libimage" "github.com/containers/common/pkg/config" - "github.com/containers/image/v5/transports/alltransports" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/api/handlers" @@ -41,8 +39,10 @@ func PodCreate(w http.ResponseWriter, r *http.Request) { return } if !psg.NoInfra { - infraOptions := &entities.ContainerCreateOptions{ImageVolume: "bind", IsInfra: true, Net: &entities.NetOptions{}, Devices: psg.Devices} // options for pulling the image and FillOutSpec - err = specgenutil.FillOutSpecGen(psg.InfraContainerSpec, infraOptions, []string{}) // necessary for default values in many cases (userns, idmappings) + infraOptions := entities.NewInfraContainerCreateOptions() // options for pulling the image and FillOutSpec + infraOptions.Net = &entities.NetOptions{} + infraOptions.Devices = psg.Devices + err = specgenutil.FillOutSpecGen(psg.InfraContainerSpec, &infraOptions, []string{}) // necessary for default values in many cases (userns, idmappings) if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error filling out specgen")) return @@ -67,20 +67,6 @@ func PodCreate(w http.ResponseWriter, r *http.Request) { imageName = config.DefaultInfraImage rawImageName = config.DefaultInfraImage } - curr := infraOptions.Quiet - infraOptions.Quiet = true - pullOptions := &libimage.PullOptions{} - pulledImages, err := runtime.LibimageRuntime().Pull(context.Background(), imageName, config.PullPolicyMissing, pullOptions) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "could not pull image")) - return - } - if _, err := alltransports.ParseImageName(imageName); err == nil { - if len(pulledImages) != 0 { - imageName = pulledImages[0].ID() - } - } - infraOptions.Quiet = curr psg.InfraImage = imageName psg.InfraContainerSpec.Image = imageName psg.InfraContainerSpec.RawImageName = rawImageName @@ -380,10 +366,17 @@ func PodTop(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) + psArgs := "-ef" + if utils.IsLibpodRequest(r) { + psArgs = "" + } query := struct { + Delay int `schema:"delay"` PsArgs string `schema:"ps_args"` + Stream bool `schema:"stream"` }{ - PsArgs: "", + Delay: 5, + PsArgs: psArgs, } if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, @@ -391,6 +384,12 @@ func PodTop(w http.ResponseWriter, r *http.Request) { return } + if query.Delay < 1 { + utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, + fmt.Errorf("\"delay\" parameter of value %d < 1", query.Delay)) + return + } + name := utils.GetName(r) pod, err := runtime.LookupPod(name) if err != nil { @@ -398,24 +397,58 @@ func PodTop(w http.ResponseWriter, r *http.Request) { return } - args := []string{} - if query.PsArgs != "" { - args = append(args, query.PsArgs) - } - output, err := pod.GetPodPidInformation(args) - if err != nil { - utils.InternalServerError(w, err) - return + // We are committed now - all errors logged but not reported to client, ship has sailed + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "application/json") + if f, ok := w.(http.Flusher); ok { + f.Flush() } - var body = handlers.PodTopOKBody{} - if len(output) > 0 { - body.Titles = strings.Split(output[0], "\t") - for _, line := range output[1:] { - body.Processes = append(body.Processes, strings.Split(line, "\t")) + encoder := json.NewEncoder(w) + +loop: // break out of for/select infinite` loop + for { + select { + case <-r.Context().Done(): + break loop + default: + output, err := pod.GetPodPidInformation([]string{query.PsArgs}) + if err != nil { + logrus.Infof("Error from %s %q : %v", r.Method, r.URL, err) + break loop + } + + if len(output) > 0 { + var body = handlers.PodTopOKBody{} + body.Titles = strings.Split(output[0], "\t") + for i := range body.Titles { + body.Titles[i] = strings.TrimSpace(body.Titles[i]) + } + + for _, line := range output[1:] { + process := strings.Split(line, "\t") + for i := range process { + process[i] = strings.TrimSpace(process[i]) + } + body.Processes = append(body.Processes, process) + } + + if err := encoder.Encode(body); err != nil { + logrus.Infof("Error from %s %q : %v", r.Method, r.URL, err) + break loop + } + if f, ok := w.(http.Flusher); ok { + f.Flush() + } + } + + if query.Stream { + time.Sleep(time.Duration(query.Delay) * time.Second) + } else { + break loop + } } } - utils.WriteJSON(w, http.StatusOK, body) } func PodKill(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go index 3ba39b860..ffdb30551 100644 --- a/pkg/api/handlers/libpod/volumes.go +++ b/pkg/api/handlers/libpod/volumes.go @@ -29,12 +29,13 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { }{ // override any golang type defaults } - input := entities.VolumeCreateOptions{} if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } + + input := entities.VolumeCreateOptions{} // decode params from body if err := json.NewDecoder(r.Body).Decode(&input); err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) @@ -47,9 +48,19 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { if len(input.Driver) > 0 { volumeOptions = append(volumeOptions, libpod.WithVolumeDriver(input.Driver)) } - if len(input.Label) > 0 { - volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(input.Label)) + + // Label provided for compatibility. + labels := make(map[string]string, len(input.Label)+len(input.Labels)) + for k, v := range input.Label { + labels[k] = v } + for k, v := range input.Labels { + labels[k] = v + } + if len(labels) > 0 { + volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(labels)) + } + if len(input.Options) > 0 { parsedOptions, err := parse.VolumeOptions(input.Options) if err != nil { |