summaryrefslogtreecommitdiff
path: root/pkg/bindings
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/bindings')
-rw-r--r--pkg/bindings/containers/containers.go21
-rw-r--r--pkg/bindings/containers/logs.go77
-rw-r--r--pkg/bindings/images/images.go109
-rw-r--r--pkg/bindings/manifests/manifests.go6
-rw-r--r--pkg/bindings/system/system.go25
-rw-r--r--pkg/bindings/test/attach_test.go4
-rw-r--r--pkg/bindings/test/containers_test.go4
-rw-r--r--pkg/bindings/test/system_test.go42
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())
- })
})