diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/images_build.go | 183 | ||||
-rw-r--r-- | pkg/api/handlers/compat/networks.go | 22 | ||||
-rw-r--r-- | pkg/api/handlers/compat/swagger.go | 7 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/networks.go | 14 | ||||
-rw-r--r-- | pkg/api/server/register_networks.go | 66 | ||||
-rw-r--r-- | pkg/bindings/images/build.go | 154 | ||||
-rw-r--r-- | pkg/bindings/network/network.go | 18 | ||||
-rw-r--r-- | pkg/bindings/network/types.go | 6 | ||||
-rw-r--r-- | pkg/bindings/network/types_prune_options.go | 75 | ||||
-rw-r--r-- | pkg/domain/entities/engine_container.go | 1 | ||||
-rw-r--r-- | pkg/domain/entities/network.go | 12 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 17 | ||||
-rw-r--r-- | pkg/domain/infra/abi/network.go | 25 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 11 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/network.go | 5 |
15 files changed, 481 insertions, 135 deletions
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 415ff85cd..0f27a090f 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -60,29 +60,39 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { }() query := struct { - BuildArgs string `schema:"buildargs"` - CacheFrom string `schema:"cachefrom"` - CpuPeriod uint64 `schema:"cpuperiod"` // nolint - CpuQuota int64 `schema:"cpuquota"` // nolint - CpuSetCpus string `schema:"cpusetcpus"` // nolint - CpuShares uint64 `schema:"cpushares"` // nolint - Dockerfile string `schema:"dockerfile"` - ExtraHosts string `schema:"extrahosts"` - ForceRm bool `schema:"forcerm"` - HTTPProxy bool `schema:"httpproxy"` - Labels string `schema:"labels"` - Layers bool `schema:"layers"` - MemSwap int64 `schema:"memswap"` - Memory int64 `schema:"memory"` - NetworkMode string `schema:"networkmode"` - NoCache bool `schema:"nocache"` - Outputs string `schema:"outputs"` - Platform string `schema:"platform"` - Pull bool `schema:"pull"` - Quiet bool `schema:"q"` - Registry string `schema:"registry"` - Remote string `schema:"remote"` - Rm bool `schema:"rm"` + AddHosts string `schema:"extrahosts"` + AdditionalCapabilities string `schema:"addcaps"` + Annotations string `schema:"annotations"` + BuildArgs string `schema:"buildargs"` + CacheFrom string `schema:"cachefrom"` + ConfigureNetwork int64 `schema:"networkmode"` + CpuPeriod uint64 `schema:"cpuperiod"` // nolint + CpuQuota int64 `schema:"cpuquota"` // nolint + CpuSetCpus string `schema:"cpusetcpus"` // nolint + CpuShares uint64 `schema:"cpushares"` // nolint + Devices string `schema:"devices"` + Dockerfile string `schema:"dockerfile"` + DropCapabilities string `schema:"dropcaps"` + ForceRm bool `schema:"forcerm"` + From string `schema:"from"` + HTTPProxy bool `schema:"httpproxy"` + Isolation int64 `schema:"isolation"` + Jobs uint64 `schema:"jobs"` // nolint + Labels string `schema:"labels"` + Layers bool `schema:"layers"` + LogRusage bool `schema:"rusage"` + Manifest string `schema:"manifest"` + MemSwap int64 `schema:"memswap"` + Memory int64 `schema:"memory"` + NoCache bool `schema:"nocache"` + OutputFormat string `schema:"outputformat"` + Platform string `schema:"platform"` + Pull bool `schema:"pull"` + Quiet bool `schema:"q"` + Registry string `schema:"registry"` + Rm bool `schema:"rm"` + //FIXME SecurityOpt in remote API is not handled + SecurityOpt string `schema:"securityopt"` ShmSize int `schema:"shmsize"` Squash bool `schema:"squash"` Tag []string `schema:"t"` @@ -101,14 +111,57 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { return } + // convert label formats + var addCaps = []string{} + if _, found := r.URL.Query()["addcaps"]; found { + var m = []string{} + if err := json.Unmarshal([]byte(query.AdditionalCapabilities), &m); err != nil { + utils.BadRequest(w, "addcaps", query.AdditionalCapabilities, err) + return + } + addCaps = m + } + addhosts := []string{} + if _, found := r.URL.Query()["extrahosts"]; found { + if err := json.Unmarshal([]byte(query.AddHosts), &addhosts); err != nil { + utils.BadRequest(w, "extrahosts", query.AddHosts, err) + return + } + } + + // convert label formats + var dropCaps = []string{} + if _, found := r.URL.Query()["dropcaps"]; found { + var m = []string{} + if err := json.Unmarshal([]byte(query.DropCapabilities), &m); err != nil { + utils.BadRequest(w, "dropcaps", query.DropCapabilities, err) + return + } + dropCaps = m + } + + // convert label formats + var devices = []string{} + if _, found := r.URL.Query()["devices"]; found { + var m = []string{} + if err := json.Unmarshal([]byte(query.DropCapabilities), &m); err != nil { + utils.BadRequest(w, "devices", query.DropCapabilities, err) + return + } + devices = m + } + var output string if len(query.Tag) > 0 { output = query.Tag[0] } - - var additionalNames []string + format := buildah.Dockerv2ImageManifest + if utils.IsLibpodRequest(r) { + format = query.OutputFormat + } + var additionalTags []string if len(query.Tag) > 1 { - additionalNames = query.Tag[1:] + additionalTags = query.Tag[1:] } var buildArgs = map[string]string{} @@ -120,17 +173,21 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { } // convert label formats + var annotations = []string{} + if _, found := r.URL.Query()["annotations"]; found { + if err := json.Unmarshal([]byte(query.Annotations), &annotations); err != nil { + utils.BadRequest(w, "annotations", query.Annotations, err) + return + } + } + + // convert label formats var labels = []string{} if _, found := r.URL.Query()["labels"]; found { - var m = map[string]string{} - if err := json.Unmarshal([]byte(query.Labels), &m); err != nil { + if err := json.Unmarshal([]byte(query.Labels), &labels); err != nil { utils.BadRequest(w, "labels", query.Labels, err) return } - - for k, v := range m { - labels = append(labels, k+"="+v) - } } pullPolicy := buildah.PullIfMissing @@ -160,27 +217,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { reporter := channel.NewWriter(make(chan []byte, 1)) defer reporter.Close() + buildOptions := imagebuildah.BuildOptions{ - ContextDirectory: contextDirectory, - PullPolicy: pullPolicy, - Registry: query.Registry, - IgnoreUnrecognizedInstructions: true, - Quiet: query.Quiet, - Layers: query.Layers, - Isolation: buildah.IsolationChroot, - Compression: archive.Gzip, - Args: buildArgs, - Output: output, - AdditionalTags: additionalNames, - Out: stdout, - Err: auxout, - ReportWriter: reporter, - OutputFormat: buildah.Dockerv2ImageManifest, - SystemContext: &types.SystemContext{ - AuthFilePath: authfile, - DockerAuthConfig: creds, - }, + AddCapabilities: addCaps, + AdditionalTags: additionalTags, + Annotations: annotations, + Args: buildArgs, CommonBuildOpts: &buildah.CommonBuildOptions{ + AddHost: addhosts, CPUPeriod: query.CpuPeriod, CPUQuota: query.CpuQuota, CPUShares: query.CpuShares, @@ -190,12 +234,37 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { MemorySwap: query.MemSwap, ShmSize: strconv.Itoa(query.ShmSize), }, - Squash: query.Squash, - Labels: labels, - NoCache: query.NoCache, - RemoveIntermediateCtrs: query.Rm, - ForceRmIntermediateCtrs: query.ForceRm, - Target: query.Target, + Compression: archive.Gzip, + ConfigureNetwork: buildah.NetworkConfigurationPolicy(query.ConfigureNetwork), + ContextDirectory: contextDirectory, + Devices: devices, + DropCapabilities: dropCaps, + Err: auxout, + ForceRmIntermediateCtrs: query.ForceRm, + From: query.From, + IgnoreUnrecognizedInstructions: true, + // FIXME, This is very broken. Buildah will only work with chroot + // Isolation: buildah.Isolation(query.Isolation), + Isolation: buildah.IsolationChroot, + + Labels: labels, + Layers: query.Layers, + Manifest: query.Manifest, + NoCache: query.NoCache, + Out: stdout, + Output: output, + OutputFormat: format, + PullPolicy: pullPolicy, + Quiet: query.Quiet, + Registry: query.Registry, + RemoveIntermediateCtrs: query.Rm, + ReportWriter: reporter, + Squash: query.Squash, + SystemContext: &types.SystemContext{ + AuthFilePath: authfile, + DockerAuthConfig: creds, + }, + Target: query.Target, } runtime := r.Context().Value("runtime").(*libpod.Runtime) diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index f0b922885..f7a70816f 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -388,3 +388,25 @@ func Disconnect(w http.ResponseWriter, r *http.Request) { } utils.WriteResponse(w, http.StatusOK, "OK") } + +// Prune removes unused networks +func Prune(w http.ResponseWriter, r *http.Request) { + // TODO Filters are not implemented + runtime := r.Context().Value("runtime").(*libpod.Runtime) + ic := abi.ContainerEngine{Libpod: runtime} + pruneOptions := entities.NetworkPruneOptions{} + pruneReports, err := ic.NetworkPrune(r.Context(), pruneOptions) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + var prunedNetworks []string //nolint + for _, pr := range pruneReports { + if pr.Error != nil { + logrus.Error(pr.Error) + continue + } + prunedNetworks = append(prunedNetworks, pr.Name) + } + utils.WriteResponse(w, http.StatusOK, prunedNetworks) +} diff --git a/pkg/api/handlers/compat/swagger.go b/pkg/api/handlers/compat/swagger.go index 0a514822b..1d1f1ecf2 100644 --- a/pkg/api/handlers/compat/swagger.go +++ b/pkg/api/handlers/compat/swagger.go @@ -77,3 +77,10 @@ type swagCompatNetworkDisconnectRequest struct { // in:body Body struct{ types.NetworkDisconnect } } + +// Network prune +// swagger:response NetworkPruneResponse +type swagCompatNetworkPruneResponse struct { + // in:body + Body []string +} diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go index d3bf06988..998f89d96 100644 --- a/pkg/api/handlers/libpod/networks.go +++ b/pkg/api/handlers/libpod/networks.go @@ -175,3 +175,17 @@ func ExistsNetwork(w http.ResponseWriter, r *http.Request) { } utils.WriteResponse(w, http.StatusNoContent, "") } + +// Prune removes unused networks +func Prune(w http.ResponseWriter, r *http.Request) { + // TODO Filters are not implemented + runtime := r.Context().Value("runtime").(*libpod.Runtime) + ic := abi.ContainerEngine{Libpod: runtime} + pruneOptions := entities.NetworkPruneOptions{} + pruneReports, err := ic.NetworkPrune(r.Context(), pruneOptions) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + utils.WriteResponse(w, http.StatusOK, pruneReports) +} diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go index 3d9e7fb89..d3345d8da 100644 --- a/pkg/api/server/register_networks.go +++ b/pkg/api/server/register_networks.go @@ -9,19 +9,6 @@ import ( ) func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { - // swagger:operation POST /networks/prune compat compatPruneNetwork - // --- - // tags: - // - networks (compat) - // Summary: Delete unused networks - // description: Not supported - // produces: - // - application/json - // responses: - // 404: - // $ref: "#/responses/NoSuchNetwork" - r.HandleFunc(VersionedPath("/networks/prune"), compat.UnsupportedHandler).Methods(http.MethodPost) - r.HandleFunc("/networks/prune", compat.UnsupportedHandler).Methods(http.MethodPost) // swagger:operation DELETE /networks/{name} compat compatRemoveNetwork // --- // tags: @@ -172,6 +159,35 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/networks/{name}/disconnect"), s.APIHandler(compat.Disconnect)).Methods(http.MethodPost) r.HandleFunc("/networks/{name}/disconnect", s.APIHandler(compat.Disconnect)).Methods(http.MethodPost) + // swagger:operation POST /networks/prune compat compatPruneNetwork + // --- + // tags: + // - networks (compat) + // summary: Delete unused networks + // description: Remove CNI networks that do not have containers + // produces: + // - application/json + // parameters: + // - in: query + // name: filters + // type: string + // description: | + // NOT IMPLEMENTED + // Filters to process on the prune list, encoded as JSON (a map[string][]string). + // Available filters: + // - until=<timestamp> Prune networks created before this timestamp. The <timestamp> can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the daemon machine’s time. + // - label (label=<key>, label=<key>=<value>, label!=<key>, or label!=<key>=<value>) Prune networks with (or without, in case label!=... is used) the specified labels. + // responses: + // 200: + // description: OK + // schema: + // type: array + // items: + // type: string + // 500: + // $ref: "#/responses/InternalError" + r.HandleFunc(VersionedPath("/networks/prune"), s.APIHandler(compat.Prune)).Methods(http.MethodPost) + r.HandleFunc("/networks/prune", s.APIHandler(compat.Prune)).Methods(http.MethodPost) // swagger:operation DELETE /libpod/networks/{name} libpod libpodRemoveNetwork // --- @@ -353,5 +369,29 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/libpod/networks/{name}/disconnect"), s.APIHandler(compat.Disconnect)).Methods(http.MethodPost) + // swagger:operation POST /libpod/networks/prune libpod libpodPruneNetwork + // --- + // tags: + // - networks + // summary: Delete unused networks + // description: Remove CNI networks that do not have containers + // produces: + // - application/json + // parameters: + // - in: query + // name: filters + // type: string + // description: | + // NOT IMPLEMENTED + // Filters to process on the prune list, encoded as JSON (a map[string][]string). + // Available filters: + // - until=<timestamp> Prune networks created before this timestamp. The <timestamp> can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the daemon machine’s time. + // - label (label=<key>, label=<key>=<value>, label!=<key>, or label!=<key>=<value>) Prune networks with (or without, in case label!=... is used) the specified labels. + // responses: + // 200: + // $ref: "#/responses/NetworkPruneResponse" + // 500: + // $ref: "#/responses/InternalError" + r.HandleFunc(VersionedPath("/libpod/networks/prune"), s.APIHandler(libpod.Prune)).Methods(http.MethodPost) return nil } diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 02765816f..8ea09b881 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -31,36 +31,31 @@ import ( func Build(ctx context.Context, containerFiles []string, options entities.BuildOptions) (*entities.BuildReport, error) { params := url.Values{} - if t := options.Output; len(t) > 0 { - params.Set("t", t) + if caps := options.AddCapabilities; len(caps) > 0 { + c, err := jsoniter.MarshalToString(caps) + if err != nil { + return nil, err + } + params.Add("addcaps", c) } + + if annotations := options.Annotations; len(annotations) > 0 { + l, err := jsoniter.MarshalToString(annotations) + if err != nil { + return nil, err + } + params.Set("annotations", l) + } + params.Add("t", options.Output) for _, tag := range options.AdditionalTags { params.Add("t", tag) } - if options.Quiet { - params.Set("q", "1") - } - if options.NoCache { - params.Set("nocache", "1") - } - if options.Layers { - params.Set("layers", "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 buildArgs := options.Args; len(buildArgs) > 0 { + bArgs, err := jsoniter.MarshalToString(buildArgs) + if err != nil { + return nil, err + } + params.Set("buildargs", bArgs) } if cpuShares := options.CommonBuildOpts.CPUShares; cpuShares > 0 { params.Set("cpushares", strconv.Itoa(int(cpuShares))) @@ -74,22 +69,38 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO 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) + params.Set("networkmode", strconv.Itoa(int(options.ConfigureNetwork))) + params.Set("outputformat", options.OutputFormat) + + if devices := options.Devices; len(devices) > 0 { + d, err := jsoniter.MarshalToString(devices) if err != nil { return nil, err } - params.Set("buildargs", bArgs) + params.Add("devices", d) } - if shmSize := options.CommonBuildOpts.ShmSize; len(shmSize) > 0 { - shmBytes, err := units.RAMInBytes(shmSize) + + if caps := options.DropCapabilities; len(caps) > 0 { + c, err := jsoniter.MarshalToString(caps) if err != nil { return nil, err } - params.Set("shmsize", strconv.Itoa(int(shmBytes))) + params.Add("dropcaps", c) } - if options.Squash { - params.Set("squash", "1") + + if options.ForceRmIntermediateCtrs { + params.Set("forcerm", "1") + } + if len(options.From) > 0 { + params.Set("from", options.From) + } + + params.Set("isolation", strconv.Itoa(int(options.Isolation))) + if options.CommonBuildOpts.HTTPProxy { + params.Set("httpproxy", "1") + } + if options.Jobs != nil { + params.Set("jobs", strconv.FormatUint(uint64(*options.Jobs), 10)) } if labels := options.Labels; len(labels) > 0 { l, err := jsoniter.MarshalToString(labels) @@ -98,10 +109,66 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } params.Set("labels", l) } - if options.CommonBuildOpts.HTTPProxy { - params.Set("httpproxy", "1") + if options.Layers { + params.Set("layers", "1") + } + if options.LogRusage { + params.Set("rusage", "1") + } + if len(options.Manifest) > 0 { + params.Set("manifest", options.Manifest) + } + if memSwap := options.CommonBuildOpts.MemorySwap; memSwap > 0 { + params.Set("memswap", strconv.Itoa(int(memSwap))) + } + if mem := options.CommonBuildOpts.Memory; mem > 0 { + params.Set("memory", strconv.Itoa(int(mem))) + } + if options.NoCache { + params.Set("nocache", "1") + } + if t := options.Output; len(t) > 0 { + params.Set("output", t) + } + var platform string + if len(options.OS) > 0 { + platform = options.OS + } + if len(options.Architecture) > 0 { + if len(platform) == 0 { + platform = "linux" + } + platform += "/" + options.Architecture + } + if len(platform) > 0 { + params.Set("platform", platform) + } + if options.PullPolicy == buildah.PullAlways { + params.Set("pull", "1") + } + if options.Quiet { + params.Set("q", "1") + } + if options.RemoveIntermediateCtrs { + params.Set("rm", "1") + } + if hosts := options.CommonBuildOpts.AddHost; len(hosts) > 0 { + h, err := jsoniter.MarshalToString(hosts) + if err != nil { + return nil, err + } + params.Set("extrahosts", h) + } + 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") } - var ( headers map[string]string err error @@ -124,19 +191,6 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO stdout = options.Out } - // TODO network? - - var platform string - 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) - } - entries := make([]string, len(containerFiles)) copy(entries, containerFiles) entries = append(entries, options.ContextDirectory) diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go index 8debeee84..428e60cf2 100644 --- a/pkg/bindings/network/network.go +++ b/pkg/bindings/network/network.go @@ -180,3 +180,21 @@ func Exists(ctx context.Context, nameOrID string, options *ExistsOptions) (bool, } return response.IsSuccess(), nil } + +// Prune removes unused CNI networks +func Prune(ctx context.Context, options *PruneOptions) ([]*entities.NetworkPruneReport, error) { + // TODO Filters is not implemented + var ( + prunedNetworks []*entities.NetworkPruneReport + ) + conn, err := bindings.GetClient(ctx) + if err != nil { + return nil, err + } + + response, err := conn.DoRequest(nil, http.MethodPost, "/networks/prune", nil, nil) + if err != nil { + return nil, err + } + return prunedNetworks, response.Process(&prunedNetworks) +} diff --git a/pkg/bindings/network/types.go b/pkg/bindings/network/types.go index 91cbcf044..47dce67c7 100644 --- a/pkg/bindings/network/types.go +++ b/pkg/bindings/network/types.go @@ -74,3 +74,9 @@ type ConnectOptions struct { // if a network exists type ExistsOptions struct { } + +//go:generate go run ../generator/generator.go PruneOptions +// PruneOptions are optional options for removing unused +// CNI networks +type PruneOptions struct { +} diff --git a/pkg/bindings/network/types_prune_options.go b/pkg/bindings/network/types_prune_options.go new file mode 100644 index 000000000..c56dcd0d3 --- /dev/null +++ b/pkg/bindings/network/types_prune_options.go @@ -0,0 +1,75 @@ +package network + +import ( + "net/url" + "reflect" + "strings" + + "github.com/containers/podman/v2/pkg/bindings/util" + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. +*/ + +// Changed +func (o *PruneOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *PruneOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + fieldName = strings.ToLower(fieldName) + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch { + case util.IsSimpleType(f): + params.Set(fieldName, util.SimpleTypeToParam(f)) + case f.Kind() == reflect.Slice: + for i := 0; i < f.Len(); i++ { + elem := f.Index(i) + if util.IsSimpleType(elem) { + params.Add(fieldName, util.SimpleTypeToParam(elem)) + } else { + return nil, errors.New("slices must contain only simple types") + } + } + case f.Kind() == reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + } + + } + return params, nil +} diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 9ff1714e7..d43b422a3 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -63,6 +63,7 @@ type ContainerEngine interface { NetworkExists(ctx context.Context, networkname string) (*BoolReport, error) NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]NetworkInspectReport, []error, error) NetworkList(ctx context.Context, options NetworkListOptions) ([]*NetworkListReport, error) + NetworkPrune(ctx context.Context, options NetworkPruneOptions) ([]*NetworkPruneReport, error) NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, error) NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error) PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error) diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go index b76bfcac7..1859f920e 100644 --- a/pkg/domain/entities/network.go +++ b/pkg/domain/entities/network.go @@ -80,3 +80,15 @@ type NetworkConnectOptions struct { Aliases []string Container string } + +// NetworkPruneReport containers the name of network and an error +// associated in its pruning (removal) +// swagger:model NetworkPruneReport +type NetworkPruneReport struct { + Name string + Error error +} + +// NetworkPruneOptions describes options for pruning +// unused cni networks +type NetworkPruneOptions struct{} diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 8ca93e770..f2d0f2c39 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -580,12 +580,21 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie // without having to pass all local data around. deleteImage := func(img *image.Image) error { results, err := ir.Libpod.RemoveImage(ctx, img, opts.Force) - if err != nil { + switch errors.Cause(err) { + case nil: + // Removal worked, so let's report it. + report.Deleted = append(report.Deleted, results.Deleted) + report.Untagged = append(report.Untagged, results.Untagged...) + return nil + case storage.ErrImageUnknown: + // The image must have been removed already (see #6510). + report.Deleted = append(report.Deleted, img.ID()) + report.Untagged = append(report.Untagged, img.ID()) + return nil + default: + // Fatal error. return err } - report.Deleted = append(report.Deleted, results.Deleted) - report.Untagged = append(report.Untagged, results.Untagged...) - return nil } // Delete all images from the local storage. diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go index bc4328fcd..13fabe89d 100644 --- a/pkg/domain/infra/abi/network.go +++ b/pkg/domain/infra/abi/network.go @@ -155,3 +155,28 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string Value: exists, }, nil } + +// Network prune removes unused cni networks +func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) { + runtimeConfig, err := ic.Libpod.GetConfig() + if err != nil { + return nil, err + } + cons, err := ic.Libpod.GetAllContainers() + if err != nil { + return nil, err + } + // Gather up all the non-default networks that the + // containers want + usedNetworks := make(map[string]bool) + for _, c := range cons { + nets, _, err := c.Networks() + if err != nil { + return nil, err + } + for _, n := range nets { + usedNetworks[n] = true + } + } + return network.PruneNetworks(runtimeConfig, usedNetworks) +} diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index f10c8c175..daad911cd 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -350,17 +350,6 @@ func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts en if err != nil { return nil, err } - // For remote clients, if the option for writing to a file was - // selected, we need to write to the *client's* filesystem. - if len(opts.IIDFile) > 0 { - f, err := os.Create(opts.IIDFile) - if err != nil { - return nil, err - } - if _, err := f.WriteString(report.ID); err != nil { - return nil, err - } - } return report, nil } diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go index bdb1beb03..990bfa880 100644 --- a/pkg/domain/infra/tunnel/network.go +++ b/pkg/domain/infra/tunnel/network.go @@ -89,3 +89,8 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string Value: exists, }, nil } + +// Network prune removes unused cni networks +func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) { + return network.Prune(ic.ClientCtx, nil) +} |