diff options
Diffstat (limited to 'pkg/bindings')
-rw-r--r-- | pkg/bindings/containers/containers.go | 21 | ||||
-rw-r--r-- | pkg/bindings/containers/logs.go | 77 | ||||
-rw-r--r-- | pkg/bindings/images/images.go | 109 | ||||
-rw-r--r-- | pkg/bindings/manifests/manifests.go | 6 | ||||
-rw-r--r-- | pkg/bindings/system/system.go | 25 | ||||
-rw-r--r-- | pkg/bindings/test/attach_test.go | 4 | ||||
-rw-r--r-- | pkg/bindings/test/containers_test.go | 4 | ||||
-rw-r--r-- | pkg/bindings/test/system_test.go | 42 |
8 files changed, 155 insertions, 133 deletions
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index f0984b8e3..39a077f36 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -11,19 +11,19 @@ import ( "os/signal" "strconv" "strings" - "syscall" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/api/handlers" "github.com/containers/libpod/pkg/bindings" "github.com/containers/libpod/pkg/domain/entities" + sig "github.com/containers/libpod/pkg/signal" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh/terminal" ) var ( - ErrLostSync = errors.New("lost synchronization with attach multiplexed result") + ErrLostSync = errors.New("lost synchronization with multiplexed stream") ) // List obtains a list of containers in local storage. All parameters to this method are optional. @@ -346,7 +346,7 @@ func ContainerInit(ctx context.Context, nameOrID string) error { } // Attach attaches to a running container -func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stream *bool, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { +func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stream *bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool) error { conn, err := bindings.GetClient(ctx) if err != nil { return err @@ -397,13 +397,13 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre }() winChange := make(chan os.Signal, 1) - signal.Notify(winChange, syscall.SIGWINCH) + signal.Notify(winChange, sig.SIGWINCH) winCtx, winCancel := context.WithCancel(ctx) defer winCancel() go func() { // Prime the pump, we need one reset to ensure everything is ready - winChange <- syscall.SIGWINCH + winChange <- sig.SIGWINCH for { select { case <-winCtx.Done(): @@ -427,6 +427,12 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre return err } defer response.Body.Close() + // If we are attaching around a start, we need to "signal" + // back that we are in fact attached so that started does + // not execute before we can attach. + if attachReady != nil { + attachReady <- true + } if !(response.IsSuccess() || response.IsInformational()) { return response.Process(nil) } @@ -479,7 +485,7 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre return err } case fd == 3: - return fmt.Errorf("error from daemon in stream: %s", frame) + return errors.New("error from service in stream: " + string(frame)) default: return fmt.Errorf("unrecognized input header: %d", fd) } @@ -501,7 +507,7 @@ func DemuxHeader(r io.Reader, buffer []byte) (fd, sz int, err error) { fd = int(buffer[0]) if fd < 0 || fd > 3 { - err = ErrLostSync + err = errors.Wrapf(ErrLostSync, fmt.Sprintf(`channel "%d" found, 0-3 supported`, fd)) return } @@ -522,7 +528,6 @@ func DemuxFrame(r io.Reader, buffer []byte, length int) (frame []byte, err error err = io.ErrUnexpectedEOF return } - return buffer[0:length], nil } diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go index b7ecb3c7e..20c8b4292 100644 --- a/pkg/bindings/containers/logs.go +++ b/pkg/bindings/containers/logs.go @@ -1,8 +1,9 @@ package containers import ( + "bytes" "context" - "encoding/binary" + "fmt" "io" "net/http" "net/url" @@ -49,68 +50,34 @@ func Logs(ctx context.Context, nameOrID string, opts LogOptions, stdoutChan, std if err != nil { return err } + defer response.Body.Close() - // read 8 bytes - // first byte determines stderr=2|stdout=1 - // bytes 4-7 len(msg) in uint32 + buffer := make([]byte, 1024) for { - stream, msgSize, err := readHeader(response.Body) + fd, l, err := DemuxHeader(response.Body, buffer) if err != nil { - // In case the server side closes up shop because !follow - if err == io.EOF { - break + if errors.Is(err, io.EOF) { + return nil } - return errors.Wrap(err, "unable to read log header") + return err } - msg, err := readMsg(response.Body, msgSize) + frame, err := DemuxFrame(response.Body, buffer, l) if err != nil { - return errors.Wrap(err, "unable to read log message") + return err } - if stream == 1 { - stdoutChan <- msg - } else { - stderrChan <- msg - } - } - return nil -} + frame = bytes.Replace(frame[0:l], []byte{13}, []byte{10}, -1) -func readMsg(r io.Reader, msgSize int) (string, error) { - var msg []byte - size := msgSize - for { - b := make([]byte, size) - _, err := r.Read(b) - if err != nil { - return "", err - } - msg = append(msg, b...) - if len(msg) == msgSize { - break - } - size = msgSize - len(msg) - } - return string(msg), nil -} - -func readHeader(r io.Reader) (byte, int, error) { - var ( - header []byte - size = 8 - ) - for { - b := make([]byte, size) - _, err := r.Read(b) - if err != nil { - return 0, 0, err - } - header = append(header, b...) - if len(header) == 8 { - break + switch fd { + case 0: + stdoutChan <- string(frame) + case 1: + stdoutChan <- string(frame) + case 2: + stderrChan <- string(frame) + case 3: + return errors.New("error from service in stream: " + string(frame)) + default: + return fmt.Errorf("unrecognized input header: %d", fd) } - size = 8 - len(header) } - stream := header[0] - msgSize := int(binary.BigEndian.Uint32(header[4:]) - 8) - return stream, msgSize, nil } diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go index a15ce56e5..f9c02d199 100644 --- a/pkg/bindings/images/images.go +++ b/pkg/bindings/images/images.go @@ -1,6 +1,7 @@ package images import ( + "bytes" "context" "fmt" "io" @@ -8,10 +9,13 @@ import ( "net/url" "strconv" + "github.com/containers/buildah" "github.com/containers/image/v5/types" "github.com/containers/libpod/pkg/api/handlers" "github.com/containers/libpod/pkg/bindings" "github.com/containers/libpod/pkg/domain/entities" + "github.com/docker/go-units" + jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" ) @@ -146,7 +150,7 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, c _, err = io.Copy(w, response.Body) return err } - return nil + return response.Process(nil) } // Prune removes unused images from local storage. The optional filters can be used to further @@ -209,7 +213,108 @@ func Untag(ctx context.Context, nameOrID, tag, repo string) error { return response.Process(nil) } -func Build(nameOrId string) {} +// Build creates an image using a containerfile reference +func Build(ctx context.Context, containerFiles []string, options entities.BuildOptions, tarfile io.Reader) (*entities.BuildReport, error) { + var ( + platform string + report entities.BuildReport + ) + conn, err := bindings.GetClient(ctx) + if err != nil { + return nil, err + } + params := url.Values{} + params.Set("dockerfile", containerFiles[0]) + if t := options.Output; len(t) > 0 { + params.Set("t", t) + } + // TODO Remote, Quiet + if options.NoCache { + params.Set("nocache", "1") + } + // TODO cachefrom + if options.PullPolicy == buildah.PullAlways { + params.Set("pull", "1") + } + if options.RemoveIntermediateCtrs { + params.Set("rm", "1") + } + if options.ForceRmIntermediateCtrs { + params.Set("forcerm", "1") + } + if mem := options.CommonBuildOpts.Memory; mem > 0 { + params.Set("memory", strconv.Itoa(int(mem))) + } + if memSwap := options.CommonBuildOpts.MemorySwap; memSwap > 0 { + params.Set("memswap", strconv.Itoa(int(memSwap))) + } + if cpuShares := options.CommonBuildOpts.CPUShares; cpuShares > 0 { + params.Set("cpushares", strconv.Itoa(int(cpuShares))) + } + if cpuSetCpus := options.CommonBuildOpts.CPUSetCPUs; len(cpuSetCpus) > 0 { + params.Set("cpusetcpues", cpuSetCpus) + } + if cpuPeriod := options.CommonBuildOpts.CPUPeriod; cpuPeriod > 0 { + params.Set("cpuperiod", strconv.Itoa(int(cpuPeriod))) + } + if cpuQuota := options.CommonBuildOpts.CPUQuota; cpuQuota > 0 { + params.Set("cpuquota", strconv.Itoa(int(cpuQuota))) + } + if buildArgs := options.Args; len(buildArgs) > 0 { + bArgs, err := jsoniter.MarshalToString(buildArgs) + if err != nil { + return nil, err + } + params.Set("buildargs", bArgs) + } + if shmSize := options.CommonBuildOpts.ShmSize; len(shmSize) > 0 { + shmBytes, err := units.RAMInBytes(shmSize) + if err != nil { + return nil, err + } + params.Set("shmsize", strconv.Itoa(int(shmBytes))) + } + if options.Squash { + params.Set("squash", "1") + } + if labels := options.Labels; len(labels) > 0 { + l, err := jsoniter.MarshalToString(labels) + if err != nil { + return nil, err + } + params.Set("labels", l) + } + + // TODO network? + if OS := options.OS; len(OS) > 0 { + platform += OS + } + if arch := options.Architecture; len(arch) > 0 { + platform += "/" + arch + } + if len(platform) > 0 { + params.Set("platform", platform) + } + // TODO outputs? + + response, err := conn.DoRequest(tarfile, http.MethodPost, "/build", params) + if err != nil { + return nil, err + } + var streamReponse []byte + bb := bytes.NewBuffer(streamReponse) + if _, err = io.Copy(bb, response.Body); err != nil { + return nil, err + } + var s struct { + Stream string `json:"stream"` + } + if err := jsoniter.UnmarshalFromString(bb.String(), &s); err != nil { + return nil, err + } + fmt.Print(s.Stream) + return &report, nil +} // Imports 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 diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go index 3e0ef0325..f5ee31d93 100644 --- a/pkg/bindings/manifests/manifests.go +++ b/pkg/bindings/manifests/manifests.go @@ -112,17 +112,17 @@ func Push(ctx context.Context, name string, destination *string, all *bool) (str params := url.Values{} params.Set("image", name) if destination != nil { - dest = name + dest = *destination } params.Set("destination", dest) if all != nil { params.Set("all", strconv.FormatBool(*all)) } - response, err := conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, name) + _, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, name) if err != nil { return "", err } - return idr.ID, response.Process(&idr) + return idr.ID, err } // There is NO annotate endpoint. this binding could never work diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go index e567e7a86..5348d0cfb 100644 --- a/pkg/bindings/system/system.go +++ b/pkg/bindings/system/system.go @@ -112,29 +112,16 @@ func Version(ctx context.Context) (*entities.SystemVersionReport, error) { f, _ := strconv.ParseFloat(component.APIVersion, 64) b, _ := time.Parse(time.RFC3339, component.BuildTime) report.Server = &define.Version{ - RemoteAPIVersion: int64(f), - Version: component.Version.Version, - GoVersion: component.GoVersion, - GitCommit: component.GitCommit, - Built: b.Unix(), - OsArch: fmt.Sprintf("%s/%s", component.Os, component.Arch), + APIVersion: int64(f), + Version: component.Version.Version, + GoVersion: component.GoVersion, + GitCommit: component.GitCommit, + Built: b.Unix(), + OsArch: fmt.Sprintf("%s/%s", component.Os, component.Arch), } return &report, err } -// Reset removes all unused system data. -func Reset(ctx context.Context) error { - conn, err := bindings.GetClient(ctx) - if err != nil { - return err - } - response, err := conn.DoRequest(nil, http.MethodPost, "/system/reset", nil) - if err != nil { - return err - } - return response.Process(response) -} - // DiskUsage returns information about image, container, and volume disk // consumption func DiskUsage(ctx context.Context) (*entities.SystemDfReport, error) { diff --git a/pkg/bindings/test/attach_test.go b/pkg/bindings/test/attach_test.go index 906bd2950..6fb166828 100644 --- a/pkg/bindings/test/attach_test.go +++ b/pkg/bindings/test/attach_test.go @@ -54,7 +54,7 @@ var _ = Describe("Podman containers attach", func() { go func() { defer GinkgoRecover() - err := containers.Attach(bt.conn, id, nil, bindings.PTrue, bindings.PTrue, nil, stdout, stderr) + err := containers.Attach(bt.conn, id, nil, bindings.PTrue, bindings.PTrue, nil, stdout, stderr, nil) Expect(err).ShouldNot(HaveOccurred()) }() @@ -98,7 +98,7 @@ var _ = Describe("Podman containers attach", func() { go func() { defer GinkgoRecover() - err := containers.Attach(bt.conn, ctnr.ID, nil, bindings.PFalse, bindings.PTrue, stdin, stdout, stderr) + err := containers.Attach(bt.conn, ctnr.ID, nil, bindings.PFalse, bindings.PTrue, stdin, stdout, stderr, nil) Expect(err).ShouldNot(HaveOccurred()) }() diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index f725d1cf2..3b94b10eb 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -378,9 +378,9 @@ var _ = Describe("Podman containers ", func() { containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil) }() o := <-stdoutChan - o = strings.ReplaceAll(o, "\r", "") + o = strings.TrimSpace(o) _, err = time.Parse(time.RFC1123Z, o) - Expect(err).To(BeNil()) + Expect(err).ShouldNot(HaveOccurred()) }) It("podman top", func() { diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go index fb2df258b..27ab2f555 100644 --- a/pkg/bindings/test/system_test.go +++ b/pkg/bindings/test/system_test.go @@ -5,7 +5,6 @@ import ( "github.com/containers/libpod/pkg/bindings" "github.com/containers/libpod/pkg/bindings/containers" - "github.com/containers/libpod/pkg/bindings/images" "github.com/containers/libpod/pkg/bindings/pods" "github.com/containers/libpod/pkg/bindings/system" "github.com/containers/libpod/pkg/bindings/volumes" @@ -150,45 +149,4 @@ var _ = Describe("Podman system", func() { // Volume should be pruned now as flag set true Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1)) }) - - It("podman system reset", func() { - // Adding an unused volume should work - _, err := volumes.Create(bt.conn, entities.VolumeCreateOptions{}) - Expect(err).To(BeNil()) - - vols, err := volumes.List(bt.conn, nil) - Expect(err).To(BeNil()) - Expect(len(vols)).To(Equal(1)) - - // Start a pod and leave it running - _, err = pods.Start(bt.conn, newpod) - Expect(err).To(BeNil()) - - imageSummary, err := images.List(bt.conn, nil, nil) - Expect(err).To(BeNil()) - // Since in the begin context images are created - Expect(len(imageSummary)).To(Equal(3)) - - err = system.Reset(bt.conn) - Expect(err).To(BeNil()) - - // re-establish connection - s = bt.startAPIService() - time.Sleep(1 * time.Second) - - // No pods - podSummary, err := pods.List(bt.conn, nil) - Expect(err).To(BeNil()) - Expect(len(podSummary)).To(Equal(0)) - - // No images - imageSummary, err = images.List(bt.conn, bindings.PTrue, nil) - Expect(err).To(BeNil()) - Expect(len(imageSummary)).To(Equal(0)) - - // no volumes - vols, err = volumes.List(bt.conn, nil) - Expect(err).To(BeNil()) - Expect(len(vols)).To(BeZero()) - }) }) |