diff options
Diffstat (limited to 'pkg/bindings')
-rw-r--r-- | pkg/bindings/containers/types.go | 1 | ||||
-rw-r--r-- | pkg/bindings/containers/types_start_options.go | 16 | ||||
-rw-r--r-- | pkg/bindings/images/build.go | 21 | ||||
-rw-r--r-- | pkg/bindings/network/network.go | 10 | ||||
-rw-r--r-- | pkg/bindings/network/types.go | 3 | ||||
-rw-r--r-- | pkg/bindings/network/types_prune_options.go | 16 | ||||
-rw-r--r-- | pkg/bindings/play/types.go | 4 | ||||
-rw-r--r-- | pkg/bindings/play/types_kube_options.go | 17 | ||||
-rw-r--r-- | pkg/bindings/test/networks_test.go | 133 | ||||
-rw-r--r-- | pkg/bindings/test/volumes_test.go | 8 |
10 files changed, 223 insertions, 6 deletions
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index f63e35bf1..0d22c32f8 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -154,6 +154,7 @@ type RestartOptions struct { // StartOptions are optional options for starting containers type StartOptions struct { DetachKeys *string + Recursive *bool } //go:generate go run ../generator/generator.go StatsOptions diff --git a/pkg/bindings/containers/types_start_options.go b/pkg/bindings/containers/types_start_options.go index f8ba29623..d419c755c 100644 --- a/pkg/bindings/containers/types_start_options.go +++ b/pkg/bindings/containers/types_start_options.go @@ -35,3 +35,19 @@ func (o *StartOptions) GetDetachKeys() string { } return *o.DetachKeys } + +// WithRecursive +func (o *StartOptions) WithRecursive(value bool) *StartOptions { + v := &value + o.Recursive = v + return o +} + +// GetRecursive +func (o *StartOptions) GetRecursive() bool { + var recursive bool + if o.Recursive == nil { + return recursive + } + return *o.Recursive +} diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index c47a16551..c0e5706a5 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -12,6 +12,7 @@ import ( "os" "path/filepath" "regexp" + "runtime" "strconv" "strings" @@ -190,6 +191,10 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO platform = "linux" } platform += "/" + options.Architecture + } else { + if len(platform) > 0 { + platform += "/" + runtime.GOARCH + } } if len(platform) > 0 { params.Set("platform", platform) @@ -335,6 +340,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO re := regexp.MustCompile(`[0-9a-f]{12}`) var id string + var mErr error for { var s struct { Stream string `json:"stream,omitempty"` @@ -342,11 +348,21 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } if err := dec.Decode(&s); err != nil { if errors.Is(err, io.EOF) { - return &entities.BuildReport{ID: id}, nil + if mErr == nil && id == "" { + mErr = errors.New("stream dropped, unexpected failure") + } + break } s.Error = err.Error() + "\n" } + select { + case <-response.Request.Context().Done(): + return &entities.BuildReport{ID: id}, mErr + default: + // non-blocking select + } + switch { case s.Stream != "": stdout.Write([]byte(s.Stream)) @@ -354,11 +370,12 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO id = strings.TrimSuffix(s.Stream, "\n") } case s.Error != "": - return nil, errors.New(s.Error) + mErr = errors.New(s.Error) default: return &entities.BuildReport{ID: id}, errors.New("failed to parse build results stream, unexpected input") } } + return &entities.BuildReport{ID: id}, mErr } func nTar(excludes []string, sources ...string) (io.ReadCloser, error) { diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go index 6f3aa8594..17451c273 100644 --- a/pkg/bindings/network/network.go +++ b/pkg/bindings/network/network.go @@ -184,7 +184,13 @@ func Exists(ctx context.Context, nameOrID string, options *ExistsOptions) (bool, // Prune removes unused CNI networks func Prune(ctx context.Context, options *PruneOptions) ([]*entities.NetworkPruneReport, error) { - // TODO Filters is not implemented + if options == nil { + options = new(PruneOptions) + } + params, err := options.ToParams() + if err != nil { + return nil, err + } var ( prunedNetworks []*entities.NetworkPruneReport ) @@ -193,7 +199,7 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*entities.NetworkPrune return nil, err } - response, err := conn.DoRequest(nil, http.MethodPost, "/networks/prune", nil, nil) + response, err := conn.DoRequest(nil, http.MethodPost, "/networks/prune", params, nil) if err != nil { return nil, err } diff --git a/pkg/bindings/network/types.go b/pkg/bindings/network/types.go index 47dce67c7..e62ae8f52 100644 --- a/pkg/bindings/network/types.go +++ b/pkg/bindings/network/types.go @@ -79,4 +79,7 @@ type ExistsOptions struct { // PruneOptions are optional options for removing unused // CNI networks type PruneOptions struct { + // Filters are applied to the prune of networks to be more + // specific on choosing + Filters map[string][]string } diff --git a/pkg/bindings/network/types_prune_options.go b/pkg/bindings/network/types_prune_options.go index 84e1a8b32..f17e09d69 100644 --- a/pkg/bindings/network/types_prune_options.go +++ b/pkg/bindings/network/types_prune_options.go @@ -19,3 +19,19 @@ func (o *PruneOptions) Changed(fieldName string) bool { func (o *PruneOptions) ToParams() (url.Values, error) { return util.ToParams(o) } + +// WithFilters +func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions { + v := value + o.Filters = v + return o +} + +// GetFilters +func (o *PruneOptions) GetFilters() map[string][]string { + var filters map[string][]string + if o.Filters == nil { + return filters + } + return o.Filters +} diff --git a/pkg/bindings/play/types.go b/pkg/bindings/play/types.go index 5fb9a4d41..6598ec3c2 100644 --- a/pkg/bindings/play/types.go +++ b/pkg/bindings/play/types.go @@ -1,5 +1,7 @@ package play +import "net" + //go:generate go run ../generator/generator.go KubeOptions // KubeOptions are optional options for replaying kube YAML files type KubeOptions struct { @@ -23,6 +25,8 @@ type KubeOptions struct { // SeccompProfileRoot - path to a directory containing seccomp // profiles. SeccompProfileRoot *string + // StaticIPs - Static IP address used by the pod(s). + StaticIPs *[]net.IP // ConfigMaps - slice of pathnames to kubernetes configmap YAMLs. ConfigMaps *[]string // LogDriver for the container. For example: journald diff --git a/pkg/bindings/play/types_kube_options.go b/pkg/bindings/play/types_kube_options.go index 78396a090..a1786f553 100644 --- a/pkg/bindings/play/types_kube_options.go +++ b/pkg/bindings/play/types_kube_options.go @@ -1,6 +1,7 @@ package play import ( + "net" "net/url" "github.com/containers/podman/v3/pkg/bindings/internal/util" @@ -164,6 +165,22 @@ func (o *KubeOptions) GetSeccompProfileRoot() string { return *o.SeccompProfileRoot } +// WithStaticIPs +func (o *KubeOptions) WithStaticIPs(value []net.IP) *KubeOptions { + v := &value + o.StaticIPs = v + return o +} + +// GetStaticIPs +func (o *KubeOptions) GetStaticIPs() []net.IP { + var staticIPs []net.IP + if o.StaticIPs == nil { + return staticIPs + } + return *o.StaticIPs +} + // WithConfigMaps func (o *KubeOptions) WithConfigMaps(value []string) *KubeOptions { v := &value diff --git a/pkg/bindings/test/networks_test.go b/pkg/bindings/test/networks_test.go index ef20235ae..b53fc4bd3 100644 --- a/pkg/bindings/test/networks_test.go +++ b/pkg/bindings/test/networks_test.go @@ -2,10 +2,12 @@ package test_bindings import ( "context" + "fmt" "net/http" "time" "github.com/containers/podman/v3/pkg/bindings" + "github.com/containers/podman/v3/pkg/bindings/containers" "github.com/containers/podman/v3/pkg/bindings/network" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -37,6 +39,53 @@ var _ = Describe("Podman networks", func() { bt.cleanup() }) + It("podman prune unused networks with filters", func() { + name := "foobar" + opts := network.CreateOptions{ + Name: &name, + } + _, err = network.Create(connText, &opts) + Expect(err).To(BeNil()) + + // Invalid filters should return error + filtersIncorrect := map[string][]string{ + "status": {"dummy"}, + } + _, err = network.Prune(connText, new(network.PruneOptions).WithFilters(filtersIncorrect)) + Expect(err).ToNot(BeNil()) + + // List filter params should not work with prune. + filtersIncorrect = map[string][]string{ + "name": {name}, + } + _, err = network.Prune(connText, new(network.PruneOptions).WithFilters(filtersIncorrect)) + Expect(err).ToNot(BeNil()) + + // Mismatched label, correct filter params => no network should be pruned. + filtersIncorrect = map[string][]string{ + "label": {"xyz"}, + } + pruneResponse, err := network.Prune(connText, new(network.PruneOptions).WithFilters(filtersIncorrect)) + Expect(err).To(BeNil()) + Expect(len(pruneResponse)).To(Equal(0)) + + // Mismatched until, correct filter params => no network should be pruned. + filters := map[string][]string{ + "until": {"50"}, // January 1, 1970 + } + pruneResponse, err = network.Prune(connText, new(network.PruneOptions).WithFilters(filters)) + Expect(err).To(BeNil()) + Expect(len(pruneResponse)).To(Equal(0)) + + // Valid filter params => network should be pruned now. + filters = map[string][]string{ + "until": {"5000000000"}, //June 11, 2128 + } + pruneResponse, err = network.Prune(connText, new(network.PruneOptions).WithFilters(filters)) + Expect(err).To(BeNil()) + Expect(len(pruneResponse)).To(Equal(1)) + }) + It("create network", func() { // create a network with blank config should work _, err = network.Create(connText, &network.CreateOptions{}) @@ -69,4 +118,88 @@ var _ = Describe("Podman networks", func() { Expect(err).To(BeNil()) Expect(data[0]["name"]).To(Equal(name)) }) + + It("list networks", func() { + // create a bunch of named networks and make verify with list + netNames := []string{"homer", "bart", "lisa", "maggie", "marge"} + for i := 0; i < 5; i++ { + opts := network.CreateOptions{ + Name: &netNames[i], + } + _, err = network.Create(connText, &opts) + Expect(err).To(BeNil()) + } + list, err := network.List(connText, nil) + Expect(err).To(BeNil()) + Expect(len(list)).To(BeNumerically(">=", 5)) + for _, n := range list { + if n.Name != "podman" { + Expect(StringInSlice(n.Name, netNames)).To(BeTrue()) + } + } + + // list with bad filter should be 500 + filters := make(map[string][]string) + filters["foobar"] = []string{"1234"} + options := new(network.ListOptions).WithFilters(filters) + _, err = network.List(connText, options) + Expect(err).ToNot(BeNil()) + code, _ := bindings.CheckResponseCode(err) + Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) + + // filter list with success + filters = make(map[string][]string) + filters["name"] = []string{"homer"} + options = new(network.ListOptions).WithFilters(filters) + list, err = network.List(connText, options) + Expect(err).To(BeNil()) + Expect(len(list)).To(BeNumerically("==", 1)) + Expect(list[0].Name).To(Equal("homer")) + }) + + It("remove network", func() { + // removing a noName network should result in 404 + _, err := network.Remove(connText, "noName", nil) + code, err := bindings.CheckResponseCode(err) + Expect(err).To(BeNil()) + Expect(code).To(BeNumerically("==", http.StatusNotFound)) + + // Removing an unused network should work + name := "unused" + opts := network.CreateOptions{ + Name: &name, + } + _, err = network.Create(connText, &opts) + Expect(err).To(BeNil()) + report, err := network.Remove(connText, name, nil) + Expect(err).To(BeNil()) + Expect(report[0].Name).To(Equal(name)) + + // Removing a network that is being used without force should be 500 + name = "used" + opts = network.CreateOptions{ + Name: &name, + } + _, err = network.Create(connText, &opts) + Expect(err).To(BeNil()) + + // Start container and wait + container := "ntest" + session := bt.runPodman([]string{"run", "-dt", fmt.Sprintf("--network=%s", name), "--name", container, alpine.name, "top"}) + session.Wait(45) + Expect(session.ExitCode()).To(BeZero()) + + _, err = network.Remove(connText, name, nil) + code, err = bindings.CheckResponseCode(err) + Expect(err).To(BeNil()) + Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) + + // Removing with a network in use with force should work with a stopped container + err = containers.Stop(connText, container, new(containers.StopOptions).WithTimeout(0)) + Expect(err).To(BeNil()) + options := new(network.RemoveOptions).WithForce(true) + report, err = network.Remove(connText, name, options) + Expect(err).To(BeNil()) + Expect(report[0].Name).To(Equal(name)) + }) }) diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go index 91f6444cc..14bda114e 100644 --- a/pkg/bindings/test/volumes_test.go +++ b/pkg/bindings/test/volumes_test.go @@ -83,7 +83,8 @@ var _ = Describe("Podman volumes", func() { It("remove volume", func() { // removing a bogus volume should result in 404 err := volumes.Remove(connText, "foobar", nil) - code, _ := bindings.CheckResponseCode(err) + code, err := bindings.CheckResponseCode(err) + Expect(err).To(BeNil()) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Removing an unused volume should work @@ -97,9 +98,12 @@ var _ = Describe("Podman volumes", func() { Expect(err).To(BeNil()) session := bt.runPodman([]string{"run", "-dt", "-v", fmt.Sprintf("%s:/foobar", vol.Name), "--name", "vtest", alpine.name, "top"}) session.Wait(45) + Expect(session.ExitCode()).To(BeZero()) + err = volumes.Remove(connText, vol.Name, nil) Expect(err).ToNot(BeNil()) - code, _ = bindings.CheckResponseCode(err) + code, err = bindings.CheckResponseCode(err) + Expect(err).To(BeNil()) Expect(code).To(BeNumerically("==", http.StatusConflict)) // Removing with a volume in use with force should work with a stopped container |