aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_top.go81
-rw-r--r--pkg/api/handlers/libpod/pods.go82
-rw-r--r--pkg/api/server/register_containers.go17
-rw-r--r--pkg/api/server/register_pods.go15
-rw-r--r--pkg/bindings/containers/attach.go4
-rw-r--r--pkg/bindings/containers/logs.go2
-rw-r--r--pkg/bindings/test/containers_test.go7
-rw-r--r--pkg/domain/entities/pods.go4
-rw-r--r--pkg/domain/entities/system.go2
-rw-r--r--pkg/domain/infra/abi/system.go10
-rw-r--r--pkg/machine/qemu/machine.go1
-rw-r--r--pkg/specgen/podspecgen.go2
-rw-r--r--pkg/specgen/specgen.go2
-rw-r--r--pkg/specgenutil/specgen.go4
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
}