mirror of
https://github.com/containers/podman.git
synced 2025-10-19 20:23:08 +08:00
Fix file descriptor leaks and add test
* Add response.Body.Close() where needed to release HTTP connections to API server. * Add tests to ensure no general leaks occur. 100% coverage would be required to ensure no leaks on any call. * Update code comments to be godoc correct Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
@ -228,6 +244,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
|
||||
@ -242,6 +259,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}
|
||||
@ -276,6 +294,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 {
|
||||
@ -308,6 +327,8 @@ func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
return response.Process(nil)
|
||||
}
|
||||
|
||||
@ -331,6 +352,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)
|
||||
}
|
||||
|
||||
@ -350,6 +373,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
|
||||
}
|
||||
|
||||
@ -371,6 +396,8 @@ func Stop(ctx context.Context, nameOrID string, options *StopOptions) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
return response.Process(nil)
|
||||
}
|
||||
|
||||
@ -390,6 +417,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
|
||||
@ -413,6 +442,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)
|
||||
}
|
||||
@ -432,5 +463,7 @@ func ShouldRestart(ctx context.Context, nameOrID string, options *ShouldRestartO
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
return response.IsSuccess(), nil
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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}
|
||||
}
|
||||
|
@ -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)
|
||||
//}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -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() {
|
||||
|
116
pkg/bindings/test/resource_test.go
Normal file
116
pkg/bindings/test/resource_test.go
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -1315,10 +1315,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"})
|
||||
@ -1329,14 +1329,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() {
|
||||
|
Reference in New Issue
Block a user