summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2021-08-25 14:42:12 -0400
committerGitHub <noreply@github.com>2021-08-25 14:42:12 -0400
commit49cfed756f5dfb6d9267eb29d31f651578c9037c (patch)
tree677b6acfee4b6fddc1b08d8181ce3552a5ccab68
parentfefa0b32c74fc5d394a0e2bd5b4564bedb3ed15d (diff)
parent1dc6d14735eef1e51368103aefba3d7c704dcfe3 (diff)
downloadpodman-49cfed756f5dfb6d9267eb29d31f651578c9037c.tar.gz
podman-49cfed756f5dfb6d9267eb29d31f651578c9037c.tar.bz2
podman-49cfed756f5dfb6d9267eb29d31f651578c9037c.zip
Merge pull request #11103 from jwhonce/wip/bindings
Fix file descriptor leaks in bindings and add test
-rw-r--r--cmd/podman/generate/kube.go5
-rw-r--r--pkg/bindings/connection.go7
-rw-r--r--pkg/bindings/containers/archive.go10
-rw-r--r--pkg/bindings/containers/attach.go9
-rw-r--r--pkg/bindings/containers/checkpoint.go4
-rw-r--r--pkg/bindings/containers/commit.go2
-rw-r--r--pkg/bindings/containers/containers.go33
-rw-r--r--pkg/bindings/containers/create.go2
-rw-r--r--pkg/bindings/containers/diff.go2
-rw-r--r--pkg/bindings/containers/exec.go3
-rw-r--r--pkg/bindings/containers/healthcheck.go2
-rw-r--r--pkg/bindings/containers/logs.go1
-rw-r--r--pkg/bindings/containers/mount.go6
-rw-r--r--pkg/bindings/containers/rename.go2
-rw-r--r--pkg/bindings/errors.go2
-rw-r--r--pkg/bindings/generate/generate.go5
-rw-r--r--pkg/bindings/images/diff.go2
-rw-r--r--pkg/bindings/images/images.go32
-rw-r--r--pkg/bindings/images/rm.go2
-rw-r--r--pkg/bindings/manifests/manifests.go21
-rw-r--r--pkg/bindings/network/network.go16
-rw-r--r--pkg/bindings/play/play.go2
-rw-r--r--pkg/bindings/pods/pods.go27
-rw-r--r--pkg/bindings/secrets/secrets.go8
-rw-r--r--pkg/bindings/system/info.go10
-rw-r--r--pkg/bindings/system/system.go7
-rw-r--r--pkg/bindings/test/attach_test.go5
-rw-r--r--pkg/bindings/test/common_test.go21
-rw-r--r--pkg/bindings/test/resource_test.go116
-rw-r--r--pkg/bindings/volumes/volumes.go12
-rw-r--r--pkg/domain/entities/generate.go2
-rw-r--r--pkg/domain/infra/tunnel/generate.go3
-rw-r--r--test/e2e/run_test.go14
33 files changed, 360 insertions, 35 deletions
diff --git a/cmd/podman/generate/kube.go b/cmd/podman/generate/kube.go
index b4c9f9146..60b8f0af0 100644
--- a/cmd/podman/generate/kube.go
+++ b/cmd/podman/generate/kube.go
@@ -2,6 +2,7 @@ package pods
import (
"fmt"
+ "io"
"io/ioutil"
"os"
@@ -61,6 +62,10 @@ func kube(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
+ if r, ok := report.Reader.(io.ReadCloser); ok {
+ defer r.Close()
+ }
+
if cmd.Flags().Changed("filename") {
if _, err := os.Stat(kubeFile); err == nil {
return errors.Errorf("cannot write to %q; file exists", kubeFile)
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index cd118cbb2..4127ad2f0 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -56,7 +56,7 @@ func NewConnection(ctx context.Context, uri string) (context.Context, error) {
return NewConnectionWithIdentity(ctx, uri, "")
}
-// NewConnection takes a URI as a string and returns a context with the
+// NewConnectionWithIdentity takes a URI as a string and returns a context with the
// Connection embedded as a value. This context needs to be passed to each
// endpoint to work correctly.
//
@@ -149,6 +149,7 @@ func pingNewConnection(ctx context.Context) error {
if err != nil {
return err
}
+ defer response.Body.Close()
if response.StatusCode == http.StatusOK {
versionHdr := response.Header.Get("Libpod-API-Version")
@@ -338,7 +339,7 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
req.Header.Set(key, val)
}
// Give the Do three chances in the case of a comm/service hiccup
- for i := 0; i < 3; i++ {
+ for i := 1; i <= 3; i++ {
response, err = c.Client.Do(req) // nolint
if err == nil {
break
@@ -358,7 +359,7 @@ func FiltersToString(filters map[string][]string) (string, error) {
return jsoniter.MarshalToString(lowerCaseKeys)
}
-// IsInformation returns true if the response code is 1xx
+// IsInformational returns true if the response code is 1xx
func (h *APIResponse) IsInformational() bool {
return h.Response.StatusCode/100 == 1
}
diff --git a/pkg/bindings/containers/archive.go b/pkg/bindings/containers/archive.go
index 52b73662b..876f5340b 100644
--- a/pkg/bindings/containers/archive.go
+++ b/pkg/bindings/containers/archive.go
@@ -27,6 +27,7 @@ func Stat(ctx context.Context, nameOrID string, path string) (*entities.Containe
if err != nil {
return nil, err
}
+ defer response.Body.Close()
var finalErr error
if response.StatusCode == http.StatusNotFound {
@@ -53,7 +54,9 @@ func CopyFromArchive(ctx context.Context, nameOrID string, path string, reader i
return CopyFromArchiveWithOptions(ctx, nameOrID, path, reader, nil)
}
-// CopyFromArchiveWithOptions FIXME: remove this function and make CopyFromArchive accept the option as the last parameter in podman 4.0
+// CopyFromArchiveWithOptions copy files into container
+//
+// FIXME: remove this function and make CopyFromArchive accept the option as the last parameter in podman 4.0
func CopyFromArchiveWithOptions(ctx context.Context, nameOrID string, path string, reader io.Reader, options *CopyOptions) (entities.ContainerCopyFunc, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -72,6 +75,7 @@ func CopyFromArchiveWithOptions(ctx context.Context, nameOrID string, path strin
if err != nil {
return err
}
+
if response.StatusCode != http.StatusOK {
return errors.New(response.Status)
}
@@ -79,6 +83,7 @@ func CopyFromArchiveWithOptions(ctx context.Context, nameOrID string, path strin
}, nil
}
+// CopyToArchive copy files from container
func CopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (entities.ContainerCopyFunc, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -91,11 +96,14 @@ func CopyToArchive(ctx context.Context, nameOrID string, path string, writer io.
if err != nil {
return nil, err
}
+
if response.StatusCode != http.StatusOK {
+ defer response.Body.Close()
return nil, response.Process(nil)
}
return func() error {
+ defer response.Body.Close()
_, err := io.Copy(writer, response.Body)
return err
}, nil
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index 01c14d350..6efbcb57b 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -134,7 +134,9 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri
if err != nil {
return err
}
+
if !(response.IsSuccess() || response.IsInformational()) {
+ defer response.Body.Close()
return response.Process(nil)
}
@@ -207,7 +209,7 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri
}
}
} else {
- logrus.Debugf("Copying standard streams of container in non-terminal mode")
+ logrus.Debugf("Copying standard streams of container %q in non-terminal mode", ctnr.ID)
for {
// Read multiplexed channels and write to appropriate stream
fd, l, err := DemuxHeader(socket, buffer)
@@ -324,6 +326,8 @@ func resizeTTY(ctx context.Context, endpoint string, height *int, width *int) er
if err != nil {
return err
}
+ defer rsp.Body.Close()
+
return rsp.Process(nil)
}
@@ -407,6 +411,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar
if err != nil {
return err
}
+ defer resp.Body.Close()
respStruct := new(define.InspectExecSession)
if err := resp.Process(respStruct); err != nil {
@@ -477,6 +482,8 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar
if err != nil {
return err
}
+ defer response.Body.Close()
+
if !(response.IsSuccess() || response.IsInformational()) {
return response.Process(nil)
}
diff --git a/pkg/bindings/containers/checkpoint.go b/pkg/bindings/containers/checkpoint.go
index 440bf707d..7f7080f13 100644
--- a/pkg/bindings/containers/checkpoint.go
+++ b/pkg/bindings/containers/checkpoint.go
@@ -27,6 +27,8 @@ func Checkpoint(ctx context.Context, nameOrID string, options *CheckpointOptions
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -54,5 +56,7 @@ func Restore(ctx context.Context, nameOrID string, options *RestoreOptions) (*en
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
diff --git a/pkg/bindings/containers/commit.go b/pkg/bindings/containers/commit.go
index 8ae61322e..a4adebb1f 100644
--- a/pkg/bindings/containers/commit.go
+++ b/pkg/bindings/containers/commit.go
@@ -28,5 +28,7 @@ func Commit(ctx context.Context, nameOrID string, options *CommitOptions) (handl
if err != nil {
return id, err
}
+ defer response.Body.Close()
+
return id, response.Process(&id)
}
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index bc7b0c8c9..aafb83f65 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -42,6 +42,8 @@ func List(ctx context.Context, options *ListOptions) ([]entities.ListContainer,
if err != nil {
return containers, err
}
+ defer response.Body.Close()
+
return containers, response.Process(&containers)
}
@@ -66,6 +68,8 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport,
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return reports, response.Process(&reports)
}
@@ -90,6 +94,8 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -113,6 +119,8 @@ func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*de
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
inspect := define.InspectContainerData{}
return &inspect, response.Process(&inspect)
}
@@ -136,6 +144,8 @@ func Kill(ctx context.Context, nameOrID string, options *KillOptions) error {
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -154,6 +164,8 @@ func Pause(ctx context.Context, nameOrID string, options *PauseOptions) error {
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -176,6 +188,8 @@ func Restart(ctx context.Context, nameOrID string, options *RestartOptions) erro
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -199,6 +213,8 @@ func Start(ctx context.Context, nameOrID string, options *StartOptions) error {
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -231,6 +247,7 @@ func Stats(ctx context.Context, containers []string, options *StatsOptions) (cha
go func() {
defer close(statsChan)
+ defer response.Body.Close()
dec := json.NewDecoder(response.Body)
doStream := true
@@ -245,6 +262,7 @@ func Stats(ctx context.Context, containers []string, options *StatsOptions) (cha
default:
// fall through and do some work
}
+
var report entities.ContainerStatsReport
if err := dec.Decode(&report); err != nil {
report = entities.ContainerStatsReport{Error: err}
@@ -279,6 +297,7 @@ func Top(ctx context.Context, nameOrID string, options *TopOptions) ([]string, e
if err != nil {
return nil, err
}
+ defer response.Body.Close()
body := handlers.ContainerTopOKBody{}
if err = response.Process(&body); err != nil {
@@ -311,6 +330,8 @@ func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) erro
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -334,6 +355,8 @@ func Wait(ctx context.Context, nameOrID string, options *WaitOptions) (int32, er
if err != nil {
return exitCode, err
}
+ defer response.Body.Close()
+
return exitCode, response.Process(&exitCode)
}
@@ -353,6 +376,8 @@ func Exists(ctx context.Context, nameOrID string, options *ExistsOptions) (bool,
if err != nil {
return false, err
}
+ defer response.Body.Close()
+
return response.IsSuccess(), nil
}
@@ -374,6 +399,8 @@ func Stop(ctx context.Context, nameOrID string, options *StopOptions) error {
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -393,6 +420,8 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, options *ExportOp
if err != nil {
return err
}
+ defer response.Body.Close()
+
if response.StatusCode/100 == 2 {
_, err = io.Copy(w, response.Body)
return err
@@ -416,6 +445,8 @@ func ContainerInit(ctx context.Context, nameOrID string, options *InitOptions) e
if err != nil {
return err
}
+ defer response.Body.Close()
+
if response.StatusCode == http.StatusNotModified {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s has already been created in runtime", nameOrID)
}
@@ -435,5 +466,7 @@ func ShouldRestart(ctx context.Context, nameOrID string, options *ShouldRestartO
if err != nil {
return false, err
}
+ defer response.Body.Close()
+
return response.IsSuccess(), nil
}
diff --git a/pkg/bindings/containers/create.go b/pkg/bindings/containers/create.go
index 3efa9643d..c0b9538a6 100644
--- a/pkg/bindings/containers/create.go
+++ b/pkg/bindings/containers/create.go
@@ -30,5 +30,7 @@ func CreateWithSpec(ctx context.Context, s *specgen.SpecGenerator, options *Crea
if err != nil {
return ccr, err
}
+ defer response.Body.Close()
+
return ccr, response.Process(&ccr)
}
diff --git a/pkg/bindings/containers/diff.go b/pkg/bindings/containers/diff.go
index 7d20ae530..e4ec49809 100644
--- a/pkg/bindings/containers/diff.go
+++ b/pkg/bindings/containers/diff.go
@@ -26,6 +26,8 @@ func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
var changes []archive.Change
return changes, response.Process(&changes)
}
diff --git a/pkg/bindings/containers/exec.go b/pkg/bindings/containers/exec.go
index 5ae6d1d71..12b31aba3 100644
--- a/pkg/bindings/containers/exec.go
+++ b/pkg/bindings/containers/exec.go
@@ -39,6 +39,7 @@ func ExecCreate(ctx context.Context, nameOrID string, config *handlers.ExecCreat
if err != nil {
return "", err
}
+ defer resp.Body.Close()
respStruct := new(handlers.ExecCreateResponse)
if err := resp.Process(respStruct); err != nil {
@@ -66,6 +67,7 @@ func ExecInspect(ctx context.Context, sessionID string, options *ExecInspectOpti
if err != nil {
return nil, err
}
+ defer resp.Body.Close()
respStruct := new(define.InspectExecSession)
if err := resp.Process(respStruct); err != nil {
@@ -103,6 +105,7 @@ func ExecStart(ctx context.Context, sessionID string, options *ExecStartOptions)
if err != nil {
return err
}
+ defer resp.Body.Close()
return resp.Process(nil)
}
diff --git a/pkg/bindings/containers/healthcheck.go b/pkg/bindings/containers/healthcheck.go
index d6b721615..0e65a5a46 100644
--- a/pkg/bindings/containers/healthcheck.go
+++ b/pkg/bindings/containers/healthcheck.go
@@ -26,5 +26,7 @@ func RunHealthCheck(ctx context.Context, nameOrID string, options *HealthCheckOp
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &status, response.Process(&status)
}
diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go
index a3100c697..67db94487 100644
--- a/pkg/bindings/containers/logs.go
+++ b/pkg/bindings/containers/logs.go
@@ -33,6 +33,7 @@ func Logs(ctx context.Context, nameOrID string, options *LogOptions, stdoutChan,
if err != nil {
return err
}
+ defer response.Body.Close()
buffer := make([]byte, 1024)
for {
diff --git a/pkg/bindings/containers/mount.go b/pkg/bindings/containers/mount.go
index bb5c3bd67..c07998fd3 100644
--- a/pkg/bindings/containers/mount.go
+++ b/pkg/bindings/containers/mount.go
@@ -25,6 +25,8 @@ func Mount(ctx context.Context, nameOrID string, options *MountOptions) (string,
if err != nil {
return path, err
}
+ defer response.Body.Close()
+
return path, response.Process(&path)
}
@@ -43,6 +45,8 @@ func Unmount(ctx context.Context, nameOrID string, options *UnmountOptions) erro
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -61,5 +65,7 @@ func GetMountedContainerPaths(ctx context.Context, options *MountedContainerPath
if err != nil {
return mounts, err
}
+ defer response.Body.Close()
+
return mounts, response.Process(&mounts)
}
diff --git a/pkg/bindings/containers/rename.go b/pkg/bindings/containers/rename.go
index 60d7fda73..172d7838a 100644
--- a/pkg/bindings/containers/rename.go
+++ b/pkg/bindings/containers/rename.go
@@ -24,5 +24,7 @@ func Rename(ctx context.Context, nameOrID string, options *RenameOptions) error
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
diff --git a/pkg/bindings/errors.go b/pkg/bindings/errors.go
index 3339062a5..9c311d912 100644
--- a/pkg/bindings/errors.go
+++ b/pkg/bindings/errors.go
@@ -20,6 +20,8 @@ func handleError(data []byte) error {
return e
}
+// Process drains the response body, and processes the HTTP status code
+// Note: Closing the response.Body is left to the caller
func (h APIResponse) Process(unmarshalInto interface{}) error {
data, err := ioutil.ReadAll(h.Response.Body)
if err != nil {
diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go
index 7c904a6a8..742956515 100644
--- a/pkg/bindings/generate/generate.go
+++ b/pkg/bindings/generate/generate.go
@@ -26,10 +26,15 @@ func Systemd(ctx context.Context, nameOrID string, options *SystemdOptions) (*en
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
report := &entities.GenerateSystemdReport{}
return report, response.Process(&report.Units)
}
+// Kube generate Kubernetes YAML (v1 specification)
+//
+// Note: Caller is responsible for closing returned reader
func Kube(ctx context.Context, nameOrIDs []string, options *KubeOptions) (*entities.GenerateKubeReport, error) {
if options == nil {
options = new(KubeOptions)
diff --git a/pkg/bindings/images/diff.go b/pkg/bindings/images/diff.go
index 79b0df8c9..671b73089 100644
--- a/pkg/bindings/images/diff.go
+++ b/pkg/bindings/images/diff.go
@@ -23,6 +23,8 @@ func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
var changes []archive.Change
return changes, response.Process(&changes)
}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 8680d6baa..959481e0d 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -27,6 +27,8 @@ func Exists(ctx context.Context, nameOrID string, options *ExistsOptions) (bool,
if err != nil {
return false, err
}
+ defer response.Body.Close()
+
return response.IsSuccess(), nil
}
@@ -49,6 +51,8 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.ImageSummary,
if err != nil {
return imageSummary, err
}
+ defer response.Body.Close()
+
return imageSummary, response.Process(&imageSummary)
}
@@ -71,6 +75,8 @@ func GetImage(ctx context.Context, nameOrID string, options *GetOptions) (*entit
if err != nil {
return &inspectedData, err
}
+ defer response.Body.Close()
+
return &inspectedData, response.Process(&inspectedData)
}
@@ -92,6 +98,8 @@ func Tree(ctx context.Context, nameOrID string, options *TreeOptions) (*entities
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -110,6 +118,8 @@ func History(ctx context.Context, nameOrID string, options *HistoryOptions) ([]*
if err != nil {
return history, err
}
+ defer response.Body.Close()
+
return history, response.Process(&history)
}
@@ -123,6 +133,8 @@ func Load(ctx context.Context, r io.Reader) (*entities.ImageLoadReport, error) {
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -147,6 +159,7 @@ func Export(ctx context.Context, nameOrIDs []string, w io.Writer, options *Expor
if err != nil {
return err
}
+ defer response.Body.Close()
if response.StatusCode/100 == 2 || response.StatusCode/100 == 3 {
_, err = io.Copy(w, response.Body)
@@ -176,8 +189,9 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport,
if err != nil {
return deleted, err
}
- err = response.Process(&deleted)
- return deleted, err
+ defer response.Body.Close()
+
+ return deleted, response.Process(&deleted)
}
// Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
@@ -197,6 +211,8 @@ func Tag(ctx context.Context, nameOrID, tag, repo string, options *TagOptions) e
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -217,10 +233,12 @@ func Untag(ctx context.Context, nameOrID, tag, repo string, options *UntagOption
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
-// Imports adds the given image to the local image store. This can be done by file and the given reader
+// Import adds the given image to the local image store. This can be done by file and the given reader
// or via the url parameter. Additional metadata can be associated with the image by using the changes and
// message parameters. The image can also be tagged given a reference. One of url OR r must be provided.
func Import(ctx context.Context, r io.Reader, options *ImportOptions) (*entities.ImageImportReport, error) {
@@ -243,6 +261,8 @@ func Import(ctx context.Context, r io.Reader, options *ImportOptions) (*entities
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -269,8 +289,8 @@ func Push(ctx context.Context, source string, destination string, options *PushO
if err != nil {
return err
}
- //SkipTLSVerify is special. We need to delete the param added by
- //toparams and change the key and flip the bool
+ // SkipTLSVerify is special. We need to delete the param added by
+ // toparams and change the key and flip the bool
if options.SkipTLSVerify != nil {
params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
@@ -282,6 +302,7 @@ func Push(ctx context.Context, source string, destination string, options *PushO
if err != nil {
return err
}
+ defer response.Body.Close()
return response.Process(err)
}
@@ -317,6 +338,7 @@ func Search(ctx context.Context, term string, options *SearchOptions) ([]entitie
if err != nil {
return nil, err
}
+ defer response.Body.Close()
results := []entities.ImageSearchReport{}
if err := response.Process(&results); err != nil {
diff --git a/pkg/bindings/images/rm.go b/pkg/bindings/images/rm.go
index e45e583f4..461eb7729 100644
--- a/pkg/bindings/images/rm.go
+++ b/pkg/bindings/images/rm.go
@@ -36,6 +36,8 @@ func Remove(ctx context.Context, images []string, options *RemoveOptions) (*enti
if err != nil {
return nil, []error{err}
}
+ defer response.Body.Close()
+
if err := response.Process(&report); err != nil {
return nil, []error{err}
}
diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go
index 268ce3b19..6aa4961f1 100644
--- a/pkg/bindings/manifests/manifests.go
+++ b/pkg/bindings/manifests/manifests.go
@@ -46,10 +46,12 @@ func Create(ctx context.Context, names, images []string, options *CreateOptions)
if err != nil {
return "", err
}
+ defer response.Body.Close()
+
return idr.ID, response.Process(&idr)
}
-// Exists returns true if a given maifest list exists
+// Exists returns true if a given manifest list exists
func Exists(ctx context.Context, name string, options *ExistsOptions) (bool, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
@@ -59,6 +61,8 @@ func Exists(ctx context.Context, name string, options *ExistsOptions) (bool, err
if err != nil {
return false, err
}
+ defer response.Body.Close()
+
return response.IsSuccess(), nil
}
@@ -77,6 +81,8 @@ func Inspect(ctx context.Context, name string, options *InspectOptions) (*manife
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &list, response.Process(&list)
}
@@ -100,6 +106,8 @@ func Add(ctx context.Context, name string, options *AddOptions) (string, error)
if err != nil {
return "", err
}
+ defer response.Body.Close()
+
return idr.ID, response.Process(&idr)
}
@@ -121,6 +129,8 @@ func Remove(ctx context.Context, name, digest string, options *RemoveOptions) (s
if err != nil {
return "", err
}
+ defer response.Body.Close()
+
return idr.ID, response.Process(&idr)
}
@@ -145,18 +155,20 @@ func Push(ctx context.Context, name, destination string, options *images.PushOpt
if err != nil {
return "", err
}
- //SkipTLSVerify is special. We need to delete the param added by
- //toparams and change the key and flip the bool
+ // SkipTLSVerify is special. We need to delete the param added by
+ // toparams and change the key and flip the bool
if options.SkipTLSVerify != nil {
params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
params.Set("image", name)
params.Set("destination", destination)
- _, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, nil, name)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, nil, name)
if err != nil {
return "", err
}
+ defer response.Body.Close()
+
return idr.ID, err
}
@@ -179,5 +191,6 @@ func Push(ctx context.Context, name, destination string, options *images.PushOpt
// if err != nil {
// return "", err
// }
+// defer response.Body.Close()
// return idr.ID, response.Process(&idr)
//}
diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go
index 17451c273..59207aa8d 100644
--- a/pkg/bindings/network/network.go
+++ b/pkg/bindings/network/network.go
@@ -34,6 +34,8 @@ func Create(ctx context.Context, options *CreateOptions) (*entities.NetworkCreat
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -53,6 +55,8 @@ func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) ([]e
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return reports, response.Process(&reports[0])
}
@@ -76,6 +80,8 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) ([]*en
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return reports, response.Process(&reports)
}
@@ -99,6 +105,8 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.NetworkListRep
if err != nil {
return netList, err
}
+ defer response.Body.Close()
+
return netList, response.Process(&netList)
}
@@ -133,6 +141,8 @@ func Disconnect(ctx context.Context, networkName string, ContainerNameOrID strin
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -166,6 +176,8 @@ func Connect(ctx context.Context, networkName string, ContainerNameOrID string,
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -179,6 +191,8 @@ func Exists(ctx context.Context, nameOrID string, options *ExistsOptions) (bool,
if err != nil {
return false, err
}
+ defer response.Body.Close()
+
return response.IsSuccess(), nil
}
@@ -203,5 +217,7 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*entities.NetworkPrune
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return prunedNetworks, response.Process(&prunedNetworks)
}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index 4b735c821..8451cd533 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -48,6 +48,8 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
if err := response.Process(&report); err != nil {
return nil, err
}
diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go
index eb7b273cf..9d3ff322e 100644
--- a/pkg/bindings/pods/pods.go
+++ b/pkg/bindings/pods/pods.go
@@ -34,6 +34,8 @@ func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator, options
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &pcr, response.Process(&pcr)
}
@@ -47,6 +49,8 @@ func Exists(ctx context.Context, nameOrID string, options *ExistsOptions) (bool,
if err != nil {
return false, err
}
+ defer response.Body.Close()
+
return response.IsSuccess(), nil
}
@@ -67,6 +71,8 @@ func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*en
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -91,6 +97,8 @@ func Kill(ctx context.Context, nameOrID string, options *KillOptions) (*entities
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -109,6 +117,8 @@ func Pause(ctx context.Context, nameOrID string, options *PauseOptions) (*entiti
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -128,6 +138,8 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*entities.PodPruneRepo
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return reports, response.Process(&reports)
}
@@ -152,6 +164,8 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.ListPodsReport
if err != nil {
return podsReports, err
}
+ defer response.Body.Close()
+
return podsReports, response.Process(&podsReports)
}
@@ -170,6 +184,8 @@ func Restart(ctx context.Context, nameOrID string, options *RestartOptions) (*en
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -192,6 +208,8 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) (*enti
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -210,6 +228,8 @@ func Start(ctx context.Context, nameOrID string, options *StartOptions) (*entiti
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
if response.StatusCode == http.StatusNotModified {
report.Id = nameOrID
return &report, nil
@@ -236,6 +256,8 @@ func Stop(ctx context.Context, nameOrID string, options *StopOptions) (*entities
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
if response.StatusCode == http.StatusNotModified {
report.Id = nameOrID
return &report, nil
@@ -261,6 +283,7 @@ func Top(ctx context.Context, nameOrID string, options *TopOptions) ([]string, e
if err != nil {
return nil, err
}
+ defer response.Body.Close()
body := handlers.PodTopOKBody{}
if err = response.Process(&body); err != nil {
@@ -293,6 +316,8 @@ func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) (*en
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -318,5 +343,7 @@ func Stats(ctx context.Context, namesOrIDs []string, options *StatsOptions) ([]*
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return reports, response.Process(&reports)
}
diff --git a/pkg/bindings/secrets/secrets.go b/pkg/bindings/secrets/secrets.go
index 091d38e56..b741d3e5c 100644
--- a/pkg/bindings/secrets/secrets.go
+++ b/pkg/bindings/secrets/secrets.go
@@ -22,6 +22,8 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.SecretInfoRepo
if err != nil {
return secrs, err
}
+ defer response.Body.Close()
+
return secrs, response.Process(&secrs)
}
@@ -38,6 +40,8 @@ func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*en
if err != nil {
return inspect, err
}
+ defer response.Body.Close()
+
return inspect, response.Process(&inspect)
}
@@ -52,6 +56,8 @@ func Remove(ctx context.Context, nameOrID string) error {
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -74,5 +80,7 @@ func Create(ctx context.Context, reader io.Reader, options *CreateOptions) (*ent
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return create, response.Process(&create)
}
diff --git a/pkg/bindings/system/info.go b/pkg/bindings/system/info.go
index 244f9643e..8a307a4ca 100644
--- a/pkg/bindings/system/info.go
+++ b/pkg/bindings/system/info.go
@@ -9,12 +9,7 @@ import (
)
// Info returns information about the libpod environment and its stores
-func Info(ctx context.Context, options *InfoOptions) (*define.Info, error) {
- if options == nil {
- options = new(InfoOptions)
- }
- _ = options
- info := define.Info{}
+func Info(ctx context.Context, _ *InfoOptions) (*define.Info, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -23,5 +18,8 @@ func Info(ctx context.Context, options *InfoOptions) (*define.Info, error) {
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
+ info := define.Info{}
return &info, response.Process(&info)
}
diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go
index 310bcef15..719cde52e 100644
--- a/pkg/bindings/system/system.go
+++ b/pkg/bindings/system/system.go
@@ -31,6 +31,8 @@ func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan
if err != nil {
return err
}
+ defer response.Body.Close()
+
if cancelChan != nil {
go func() {
<-cancelChan
@@ -75,6 +77,8 @@ func Prune(ctx context.Context, options *PruneOptions) (*entities.SystemPruneRep
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
@@ -101,6 +105,7 @@ func Version(ctx context.Context, options *VersionOptions) (*entities.SystemVers
if err != nil {
return nil, err
}
+ defer response.Body.Close()
if err = response.Process(&component); err != nil {
return nil, err
@@ -141,5 +146,7 @@ func DiskUsage(ctx context.Context, options *DiskOptions) (*entities.SystemDfRep
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &report, response.Process(&report)
}
diff --git a/pkg/bindings/test/attach_test.go b/pkg/bindings/test/attach_test.go
index fbdf18d44..5c3ec48e4 100644
--- a/pkg/bindings/test/attach_test.go
+++ b/pkg/bindings/test/attach_test.go
@@ -81,10 +81,9 @@ var _ = Describe("Podman containers attach", func() {
tickTock := time.NewTimer(2 * time.Second)
go func() {
<-tickTock.C
- timeout := uint(5)
- err := containers.Stop(bt.conn, ctnr.ID, new(containers.StopOptions).WithTimeout(timeout))
+ err := containers.Stop(bt.conn, ctnr.ID, new(containers.StopOptions).WithTimeout(uint(5)))
if err != nil {
- GinkgoWriter.Write([]byte(err.Error()))
+ fmt.Fprint(GinkgoWriter, err.Error())
}
}()
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index 9bac4b620..91ebe21fc 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -8,6 +8,7 @@ import (
"os/exec"
"path/filepath"
"strings"
+ "time"
"github.com/containers/podman/v3/libpod/define"
. "github.com/containers/podman/v3/pkg/bindings"
@@ -150,11 +151,21 @@ func createTempDirInTempDir() (string, error) {
}
func (b *bindingTest) startAPIService() *gexec.Session {
- var (
- cmd []string
- )
- cmd = append(cmd, "--log-level=debug", "--events-backend=file", "system", "service", "--timeout=0", b.sock)
- return b.runPodman(cmd)
+ cmd := []string{"--log-level=debug", "--events-backend=file", "system", "service", "--timeout=0", b.sock}
+ session := b.runPodman(cmd)
+
+ sock := strings.TrimPrefix(b.sock, "unix://")
+ for i := 0; i < 10; i++ {
+ if _, err := os.Stat(sock); err != nil {
+ if !os.IsNotExist(err) {
+ break
+ }
+ time.Sleep(time.Second)
+ continue
+ }
+ break
+ }
+ return session
}
func (b *bindingTest) cleanup() {
diff --git a/pkg/bindings/test/resource_test.go b/pkg/bindings/test/resource_test.go
new file mode 100644
index 000000000..b12d1ccd6
--- /dev/null
+++ b/pkg/bindings/test/resource_test.go
@@ -0,0 +1,116 @@
+package test_bindings
+
+import (
+ "context"
+ "fmt"
+ "io/fs"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "syscall"
+
+ "github.com/containers/podman/v3/pkg/bindings"
+ "github.com/containers/podman/v3/pkg/bindings/containers"
+ "github.com/containers/podman/v3/pkg/bindings/images"
+ "github.com/containers/podman/v3/pkg/bindings/pods"
+ "github.com/containers/podman/v3/pkg/bindings/system"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
+)
+
+var _ = Describe("Verify Podman resources", func() {
+ var (
+ bt *bindingTest
+ s *Session
+ )
+
+ BeforeEach(func() {
+ bt = newBindingTest()
+ s = bt.startAPIService()
+ err := bt.NewConnection()
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ AfterEach(func() {
+ s.Kill()
+ bt.cleanup()
+ })
+
+ It("no leaked connections", func() {
+ conn, err := bindings.NewConnection(context.Background(), bt.sock)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ // Record details on open file descriptors before using API
+ buffer := lsof()
+
+ // Record open fd from /proc
+ start, err := readProc()
+ Expect(err).ShouldNot(HaveOccurred())
+
+ // Run some operations
+ _, err = system.Info(conn, nil)
+ Expect(err).ShouldNot(HaveOccurred())
+ _, err = images.List(conn, nil)
+ Expect(err).ShouldNot(HaveOccurred())
+ _, err = containers.List(conn, nil)
+ Expect(err).ShouldNot(HaveOccurred())
+ _, err = pods.List(conn, nil)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ podman, _ := bindings.GetClient(conn)
+ podman.Client.CloseIdleConnections()
+
+ // Record open fd from /proc
+ finished, err := readProc()
+ Expect(err).ShouldNot(HaveOccurred())
+ if !reflect.DeepEqual(finished, start) {
+ fmt.Fprintf(GinkgoWriter, "Open FDs:\nlsof Before:\n%s\n", buffer)
+
+ // Record details on open file descriptors after using API
+ buffer := lsof()
+ fmt.Fprintf(GinkgoWriter, "lsof After:\n%s\n", buffer)
+
+ // We know test has failed. Easier to let ginkgo format output.
+ Expect(finished).Should(Equal(start))
+ }
+ })
+})
+
+func lsof() string {
+ lsof := exec.Command("lsof", "+E", "-p", strconv.Itoa(os.Getpid()))
+ buffer, err := lsof.Output()
+ Expect(err).ShouldNot(HaveOccurred())
+ return string(buffer)
+}
+
+func readProc() ([]string, error) {
+ syscall.Sync()
+
+ names := make([]string, 0)
+ err := filepath.WalkDir(fmt.Sprintf("/proc/%d/fd", os.Getpid()),
+ func(path string, d fs.DirEntry, err error) error {
+ name := path + " -> "
+
+ switch {
+ case d.IsDir():
+ return nil
+ case err != nil:
+ name += err.Error()
+ case d.Type()&fs.ModeSymlink != 0:
+ n, err := os.Readlink(path)
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ if n == "" {
+ n = d.Type().String()
+ }
+ name += n
+ }
+ names = append(names, name)
+ return nil
+ })
+ return names, err
+}
diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go
index fb58a1d1f..56cf13ade 100644
--- a/pkg/bindings/volumes/volumes.go
+++ b/pkg/bindings/volumes/volumes.go
@@ -33,6 +33,8 @@ func Create(ctx context.Context, config entities.VolumeCreateOptions, options *C
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return &v, response.Process(&v)
}
@@ -53,6 +55,8 @@ func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) (*en
if err != nil {
return &inspect, err
}
+ defer response.Body.Close()
+
return &inspect, response.Process(&inspect)
}
@@ -74,6 +78,8 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.VolumeListRepo
if err != nil {
return vols, err
}
+ defer response.Body.Close()
+
return vols, response.Process(&vols)
}
@@ -94,6 +100,8 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport,
if err != nil {
return nil, err
}
+ defer response.Body.Close()
+
return pruned, response.Process(&pruned)
}
@@ -112,6 +120,8 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error
if err != nil {
return err
}
+ defer response.Body.Close()
+
return response.Process(nil)
}
@@ -125,5 +135,7 @@ func Exists(ctx context.Context, nameOrID string, options *ExistsOptions) (bool,
if err != nil {
return false, err
}
+ defer response.Body.Close()
+
return response.IsSuccess(), nil
}
diff --git a/pkg/domain/entities/generate.go b/pkg/domain/entities/generate.go
index 3ec713edf..8a437061f 100644
--- a/pkg/domain/entities/generate.go
+++ b/pkg/domain/entities/generate.go
@@ -35,6 +35,8 @@ type GenerateKubeOptions struct {
}
// GenerateKubeReport
+//
+// FIXME: Podman4.0 should change io.Reader to io.ReaderCloser
type GenerateKubeReport struct {
// Reader - the io.Reader to reader the generated YAML file.
Reader io.Reader
diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go
index 0e768b30b..3d3cd52be 100644
--- a/pkg/domain/infra/tunnel/generate.go
+++ b/pkg/domain/infra/tunnel/generate.go
@@ -16,6 +16,9 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string,
return generate.Systemd(ic.ClientCtx, nameOrID, options)
}
+// GenerateKube Kubernetes YAML (v1 specification) for nameOrIDs
+//
+// Note: Caller is responsible for closing returned Reader
func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, opts entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
options := new(generate.KubeOptions).WithService(opts.Service)
return generate.Kube(ic.ClientCtx, nameOrIDs, options)
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 6a2e2ed8d..846da283d 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -1331,10 +1331,10 @@ USER mail`, BB)
}
curCgroupsBytes, err := ioutil.ReadFile("/proc/self/cgroup")
- Expect(err).To(BeNil())
- var curCgroups string = string(curCgroupsBytes)
+ Expect(err).ShouldNot(HaveOccurred())
+ var curCgroups = string(curCgroupsBytes)
fmt.Printf("Output:\n%s\n", curCgroups)
- Expect(curCgroups).To(Not(Equal("")))
+ Expect(curCgroups).ToNot(Equal(""))
ctrName := "testctr"
container := podmanTest.Podman([]string{"run", "--name", ctrName, "-d", "--cgroups=disabled", ALPINE, "top"})
@@ -1345,14 +1345,14 @@ USER mail`, BB)
inspectOut := podmanTest.InspectContainer(ctrName)
Expect(len(inspectOut)).To(Equal(1))
pid := inspectOut[0].State.Pid
- Expect(pid).To(Not(Equal(0)))
+ Expect(pid).ToNot(Equal(0))
Expect(inspectOut[0].HostConfig.CgroupParent).To(Equal(""))
ctrCgroupsBytes, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
- Expect(err).To(BeNil())
- var ctrCgroups string = string(ctrCgroupsBytes)
+ Expect(err).ShouldNot(HaveOccurred())
+ var ctrCgroups = string(ctrCgroupsBytes)
fmt.Printf("Output\n:%s\n", ctrCgroups)
- Expect(curCgroups).To(Equal(ctrCgroups))
+ Expect(ctrCgroups).To(Equal(curCgroups))
})
It("podman run with cgroups=enabled makes cgroups", func() {