diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/containers_top.go | 81 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/pods.go | 82 | ||||
-rw-r--r-- | pkg/api/server/register_containers.go | 17 | ||||
-rw-r--r-- | pkg/api/server/register_pods.go | 15 | ||||
-rw-r--r-- | pkg/bindings/containers/attach.go | 4 | ||||
-rw-r--r-- | pkg/bindings/containers/logs.go | 2 | ||||
-rw-r--r-- | pkg/bindings/test/containers_test.go | 7 | ||||
-rw-r--r-- | pkg/domain/entities/pods.go | 4 | ||||
-rw-r--r-- | pkg/domain/entities/system.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/system.go | 10 | ||||
-rw-r--r-- | pkg/machine/qemu/machine.go | 1 | ||||
-rw-r--r-- | pkg/specgen/podspecgen.go | 2 | ||||
-rw-r--r-- | pkg/specgen/specgen.go | 2 | ||||
-rw-r--r-- | pkg/specgenutil/specgen.go | 4 |
14 files changed, 171 insertions, 62 deletions
diff --git a/pkg/api/handlers/compat/containers_top.go b/pkg/api/handlers/compat/containers_top.go index b5debd37d..545320ad9 100644 --- a/pkg/api/handlers/compat/containers_top.go +++ b/pkg/api/handlers/compat/containers_top.go @@ -1,8 +1,11 @@ package compat import ( + "encoding/json" + "fmt" "net/http" "strings" + "time" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/pkg/api/handlers" @@ -10,20 +13,24 @@ import ( api "github.com/containers/podman/v3/pkg/api/types" "github.com/gorilla/schema" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) func TopContainer(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) - defaultValue := "-ef" + psArgs := "-ef" if utils.IsLibpodRequest(r) { - defaultValue = "" + psArgs = "" } query := struct { + Delay int `schema:"delay"` PsArgs string `schema:"ps_args"` + Stream bool `schema:"stream"` }{ - PsArgs: defaultValue, + Delay: 5, + PsArgs: psArgs, } if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, @@ -31,6 +38,12 @@ func TopContainer(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) c, err := runtime.LookupContainer(name) if err != nil { @@ -38,26 +51,56 @@ func TopContainer(w http.ResponseWriter, r *http.Request) { return } - output, err := c.Top([]string{query.PsArgs}) - 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.ContainerTopOKBody{} - if len(output) > 0 { - body.Titles = strings.Split(output[0], "\t") - for i := range body.Titles { - body.Titles[i] = strings.TrimSpace(body.Titles[i]) - } + encoder := json.NewEncoder(w) + +loop: // break out of for/select infinite` loop + for { + select { + case <-r.Context().Done(): + break loop + default: + output, err := c.Top([]string{query.PsArgs}) + if err != nil { + logrus.Infof("Error from %s %q : %v", r.Method, r.URL, err) + break loop + } + + if len(output) > 0 { + body := handlers.ContainerTopOKBody{} + 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() + } + } - for _, line := range output[1:] { - process := strings.Split(line, "\t") - for i := range process { - process[i] = strings.TrimSpace(process[i]) + if query.Stream { + time.Sleep(time.Duration(query.Delay) * time.Second) + } else { + break loop } - body.Processes = append(body.Processes, process) } } - utils.WriteJSON(w, http.StatusOK, body) } diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index 1e64de0ee..2ba292579 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "strings" + "time" "github.com/containers/common/pkg/config" "github.com/containers/podman/v3/libpod" @@ -363,10 +364,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, @@ -374,31 +382,71 @@ func PodTop(w http.ResponseWriter, r *http.Request) { return } - name := utils.GetName(r) - pod, err := runtime.LookupPod(name) - if err != nil { - utils.PodNotFound(w, name, err) + if query.Delay < 1 { + utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, + fmt.Errorf("\"delay\" parameter of value %d < 1", query.Delay)) return } - args := []string{} - if query.PsArgs != "" { - args = append(args, query.PsArgs) - } - output, err := pod.GetPodPidInformation(args) + name := utils.GetName(r) + pod, err := runtime.LookupPod(name) if err != nil { - utils.InternalServerError(w, err) + utils.PodNotFound(w, name, err) return } - 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")) + // 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() + } + + 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/server/register_containers.go b/pkg/api/server/register_containers.go index 8dcea1301..c4919182b 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -442,6 +442,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // - in: query // name: ps_args // type: string + // default: -ef // description: arguments to pass to ps such as aux. Requires ps(1) to be installed in the container if no ps(1) compatible AIX descriptors are used. // produces: // - application/json @@ -1142,19 +1143,23 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // name: name // type: string // required: true - // description: | - // Name of container to query for processes - // (As of version 1.xx) + // description: Name of container to query for processes (As of version 1.xx) // - in: query // name: stream // type: boolean - // default: true - // description: Stream the output + // description: when true, repeatedly stream the latest output (As of version 4.0) + // - in: query + // name: delay + // type: integer + // description: if streaming, delay in seconds between updates. Must be >1. (As of version 4.0) + // default: 5 // - in: query // name: ps_args // type: string // default: -ef - // description: arguments to pass to ps such as aux. Requires ps(1) to be installed in the container if no ps(1) compatible AIX descriptors are used. + // description: | + // arguments to pass to ps such as aux. + // Requires ps(1) to be installed in the container if no ps(1) compatible AIX descriptors are used. // produces: // - application/json // responses: diff --git a/pkg/api/server/register_pods.go b/pkg/api/server/register_pods.go index de3669a0a..16a7bbb4c 100644 --- a/pkg/api/server/register_pods.go +++ b/pkg/api/server/register_pods.go @@ -296,18 +296,23 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // name: name // type: string // required: true - // description: | - // Name of pod to query for processes + // description: Name of pod to query for processes // - in: query // name: stream // type: boolean - // default: true - // description: Stream the output + // description: when true, repeatedly stream the latest output (As of version 4.0) + // - in: query + // name: delay + // type: integer + // description: if streaming, delay in seconds between updates. Must be >1. (As of version 4.0) + // default: 5 // - in: query // name: ps_args // type: string // default: -ef - // description: arguments to pass to ps such as aux. Requires ps(1) to be installed in the container if no ps(1) compatible AIX descriptors are used. + // description: | + // arguments to pass to ps such as aux. + // Requires ps(1) to be installed in the container if no ps(1) compatible AIX descriptors are used. // responses: // 200: // $ref: "#/responses/DocsPodTopResponse" diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go index c5f54c1af..47de89b33 100644 --- a/pkg/bindings/containers/attach.go +++ b/pkg/bindings/containers/attach.go @@ -214,7 +214,7 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri // Read multiplexed channels and write to appropriate stream fd, l, err := DemuxHeader(socket, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err @@ -531,7 +531,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar // Read multiplexed channels and write to appropriate stream fd, l, err := DemuxHeader(socket, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go index 67db94487..37ffdf0a5 100644 --- a/pkg/bindings/containers/logs.go +++ b/pkg/bindings/containers/logs.go @@ -39,7 +39,7 @@ func Logs(ctx context.Context, nameOrID string, options *LogOptions, stdoutChan, for { fd, l, err := DemuxHeader(response.Body, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index b9ed67255..0f535bc31 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -259,6 +259,7 @@ var _ = Describe("Podman containers ", func() { _, err = bt.RunTopContainer(&name, nil) Expect(err).To(BeNil()) go func() { + defer GinkgoRecover() exitCode, err = containers.Wait(bt.conn, name, nil) errChan <- err close(errChan) @@ -281,6 +282,7 @@ var _ = Describe("Podman containers ", func() { _, err := bt.RunTopContainer(&name, nil) Expect(err).To(BeNil()) go func() { + defer GinkgoRecover() exitCode, err = containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{pause})) errChan <- err close(errChan) @@ -366,7 +368,10 @@ var _ = Describe("Podman containers ", func() { opts := new(containers.LogOptions).WithStdout(true).WithFollow(true) go func() { - containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil) + defer GinkgoRecover() + err := containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil) + close(stdoutChan) + Expect(err).ShouldNot(HaveOccurred()) }() o := <-stdoutChan o = strings.TrimSpace(o) diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index 3d8579acf..1df18be58 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -7,6 +7,7 @@ import ( commonFlag "github.com/containers/common/pkg/flag" "github.com/containers/podman/v3/libpod/define" + "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/util" "github.com/opencontainers/runtime-spec/specs-go" @@ -318,7 +319,8 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod if p.Net != nil { s.NetNS = p.Net.Network s.StaticIP = p.Net.StaticIP - s.StaticMAC = p.Net.StaticMAC + // type cast to types.HardwareAddr + s.StaticMAC = (*types.HardwareAddr)(p.Net.StaticMAC) s.PortMappings = p.Net.PublishPorts s.CNINetworks = p.Net.CNINetworks s.NetworkOptions = p.Net.NetworkOptions diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go index fe041dec8..49f0c2323 100644 --- a/pkg/domain/entities/system.go +++ b/pkg/domain/entities/system.go @@ -100,7 +100,7 @@ type SystemVersionReport struct { // SystemUnshareOptions describes the options for the unshare command type SystemUnshareOptions struct { - RootlessCNI bool + RootlessNetNS bool } type ComponentVersion struct { diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index e326f26a8..7da7754f2 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -360,15 +360,15 @@ func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options e return cmd.Run() } - if options.RootlessCNI { - rootlesscni, err := ic.Libpod.GetRootlessCNINetNs(true) + if options.RootlessNetNS { + rootlessNetNS, err := ic.Libpod.GetRootlessNetNs(true) if err != nil { return err } // make sure to unlock, unshare can run for a long time - rootlesscni.Lock.Unlock() - defer rootlesscni.Cleanup(ic.Libpod) - return rootlesscni.Do(unshare) + rootlessNetNS.Lock.Unlock() + defer rootlessNetNS.Cleanup(ic.Libpod) + return rootlessNetNS.Do(unshare) } return unshare() } diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 4d8242e39..a7174aac3 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -398,7 +398,6 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error { return err } - fmt.Printf("Successfully stopped machine: %s", name) return nil } diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go index 7713ea26c..32d5be79a 100644 --- a/pkg/specgen/podspecgen.go +++ b/pkg/specgen/podspecgen.go @@ -99,7 +99,7 @@ type PodNetworkConfig struct { // Only available if NetNS is set to Bridge (the default for root). // As such, conflicts with NoInfra=true by proxy. // Optional. - StaticMAC *net.HardwareAddr `json:"static_mac,omitempty"` + StaticMAC *types.HardwareAddr `json:"static_mac,omitempty"` // PortMappings is a set of ports to map into the infra container. // As, by default, containers share their network with the infra // container, this will forward the ports to the entire pod. diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index 5a07af0f9..593d91c64 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -401,7 +401,7 @@ type ContainerNetworkConfig struct { // StaticMAC is a static MAC address to set in the container. // Only available if NetNS is set to bridge. // Optional. - StaticMAC *net.HardwareAddr `json:"static_mac,omitempty"` + StaticMAC *nettypes.HardwareAddr `json:"static_mac,omitempty"` // PortBindings is a set of ports to map into the container. // Only available if NetNS is set to bridge or slirp. // Optional. diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 683cd2918..4e8f954fb 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -11,6 +11,7 @@ import ( "github.com/containers/image/v5/manifest" "github.com/containers/podman/v3/cmd/podman/parse" "github.com/containers/podman/v3/libpod/define" + "github.com/containers/podman/v3/libpod/network/types" ann "github.com/containers/podman/v3/pkg/annotations" "github.com/containers/podman/v3/pkg/domain/entities" envLib "github.com/containers/podman/v3/pkg/env" @@ -457,7 +458,8 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions s.DNSSearch = c.Net.DNSSearch s.DNSOptions = c.Net.DNSOptions s.StaticIP = c.Net.StaticIP - s.StaticMAC = c.Net.StaticMAC + // type cast to types.HardwareAddr + s.StaticMAC = (*types.HardwareAddr)(c.Net.StaticMAC) s.NetworkOptions = c.Net.NetworkOptions s.UseImageHosts = c.Net.NoHosts } |