diff options
author | Paul Holzinger <pholzing@redhat.com> | 2021-08-16 16:11:26 +0200 |
---|---|---|
committer | Paul Holzinger <pholzing@redhat.com> | 2021-09-15 20:00:20 +0200 |
commit | 85e8fbf7f33717ef6a0d6cf9e2143b52c874c2de (patch) | |
tree | 82b0c29102d2779c18ea8a6f10df5dc1139e3817 /pkg | |
parent | 218f132fdf4939d9e0374ef860d534f19e71df54 (diff) | |
download | podman-85e8fbf7f33717ef6a0d6cf9e2143b52c874c2de.tar.gz podman-85e8fbf7f33717ef6a0d6cf9e2143b52c874c2de.tar.bz2 podman-85e8fbf7f33717ef6a0d6cf9e2143b52c874c2de.zip |
Wire network interface into libpod
Make use of the new network interface in libpod.
This commit contains several breaking changes:
- podman network create only outputs the new network name and not file
path.
- podman network ls shows the network driver instead of the cni version
and plugins.
- podman network inspect outputs the new network struct and not the cni
conflist.
- The bindings and libpod api endpoints have been changed to use the new
network structure.
The container network status is stored in a new field in the state. The
status should be received with the new `c.getNetworkStatus`. This will
migrate the old status to the new format. Therefore old containers should
contine to work correctly in all cases even when network connect/
disconnect is used.
New features:
- podman network reload keeps the ip and mac for more than one network.
- podman container restore keeps the ip and mac for more than one
network.
- The network create compat endpoint can now use more than one ipam
config.
The man pages and the swagger doc are updated to reflect the latest
changes.
Signed-off-by: Paul Holzinger <pholzing@redhat.com>
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/networks.go | 264 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/networks.go | 25 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/swagger.go | 14 | ||||
-rw-r--r-- | pkg/api/server/register_networks.go | 10 | ||||
-rw-r--r-- | pkg/bindings/network/network.go | 49 | ||||
-rw-r--r-- | pkg/bindings/test/networks_test.go | 45 | ||||
-rw-r--r-- | pkg/domain/entities/engine_container.go | 7 | ||||
-rw-r--r-- | pkg/domain/entities/network.go | 14 | ||||
-rw-r--r-- | pkg/domain/infra/abi/network.go | 122 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/network.go | 23 |
10 files changed, 229 insertions, 344 deletions
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index 847e6dcff..28727a22b 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -4,20 +4,15 @@ import ( "encoding/json" "net" "net/http" - "os" - "strings" - "syscall" - "time" - "github.com/containernetworking/cni/libcni" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" - "github.com/containers/podman/v3/libpod/network" + nettypes "github.com/containers/podman/v3/libpod/network/types" + netutil "github.com/containers/podman/v3/libpod/network/util" "github.com/containers/podman/v3/pkg/api/handlers/utils" api "github.com/containers/podman/v3/pkg/api/types" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/infra/abi" - networkid "github.com/containers/podman/v3/pkg/network" "github.com/containers/podman/v3/pkg/util" "github.com/docker/docker/api/types" @@ -27,12 +22,6 @@ import ( "github.com/sirupsen/logrus" ) -type pluginInterface struct { - PluginType string `json:"type"` - IPAM network.IPAMConfig `json:"ipam"` - IsGW bool `json:"isGateway"` -} - func InspectNetwork(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) @@ -54,18 +43,13 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Invalid scope value. Can only be local.", http.StatusBadRequest, define.ErrInvalidArg) return } - config, err := runtime.GetConfig() - if err != nil { - utils.InternalServerError(w, err) - return - } name := utils.GetName(r) - _, err = network.InspectNetwork(config, name) + net, err := runtime.Network().NetworkInspect(name) if err != nil { utils.NetworkNotFound(w, name, err) return } - report, err := getNetworkResourceByNameOrID(name, runtime, nil) + report, err := convertLibpodNetworktoDockerNetwork(runtime, net) if err != nil { utils.InternalServerError(w, err) return @@ -73,65 +57,18 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) { utils.WriteResponse(w, http.StatusOK, report) } -func getNetworkResourceByNameOrID(nameOrID string, runtime *libpod.Runtime, filters map[string][]string) (*types.NetworkResource, error) { - var ( - ipamConfigs []dockerNetwork.IPAMConfig - ) - config, err := runtime.GetConfig() - if err != nil { - return nil, err - } - containerEndpoints := map[string]types.EndpointResource{} - // Get the network path so we can get created time - networkConfigPath, err := network.GetCNIConfigPathByNameOrID(config, nameOrID) - if err != nil { - return nil, err - } - f, err := os.Stat(networkConfigPath) - if err != nil { - return nil, err - } - stat := f.Sys().(*syscall.Stat_t) +func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network nettypes.Network) (*types.NetworkResource, error) { cons, err := runtime.GetAllContainers() if err != nil { return nil, err } - conf, err := libcni.ConfListFromFile(networkConfigPath) - if err != nil { - return nil, err - } - if len(filters) > 0 { - ok, err := network.IfPassesFilter(conf, filters) - if err != nil { - return nil, err - } - if !ok { - // do not return the config if we did not match the filter - return nil, nil - } - } - - plugin, err := getPlugin(conf.Plugins) - if err != nil { - return nil, err - } - - for _, outer := range plugin.IPAM.Ranges { - for _, n := range outer { - ipamConfig := dockerNetwork.IPAMConfig{ - Subnet: n.Subnet, - Gateway: n.Gateway, - } - ipamConfigs = append(ipamConfigs, ipamConfig) - } - } - + containerEndpoints := make(map[string]types.EndpointResource, len(cons)) for _, con := range cons { data, err := con.Inspect(false) if err != nil { return nil, err } - if netData, ok := data.NetworkSettings.Networks[conf.Name]; ok { + if netData, ok := data.NetworkSettings.Networks[network.Name]; ok { containerEndpoint := types.EndpointResource{ Name: netData.NetworkID, EndpointID: netData.EndpointID, @@ -142,60 +79,47 @@ func getNetworkResourceByNameOrID(nameOrID string, runtime *libpod.Runtime, filt containerEndpoints[con.ID()] = containerEndpoint } } - - labels := network.GetNetworkLabels(conf) - if labels == nil { - labels = map[string]string{} + ipamConfigs := make([]dockerNetwork.IPAMConfig, 0, len(network.Subnets)) + for _, sub := range network.Subnets { + ipamConfig := dockerNetwork.IPAMConfig{ + Subnet: sub.Subnet.String(), + Gateway: sub.Gateway.String(), + // TODO add range + } + ipamConfigs = append(ipamConfigs, ipamConfig) } - - isInternal := false - dockerDriver := plugin.PluginType - if plugin.PluginType == network.DefaultNetworkDriver { - isInternal = !plugin.IsGW - dockerDriver = "default" + ipamDriver := network.IPAMOptions["driver"] + if ipamDriver == nettypes.HostLocalIPAMDriver { + ipamDriver = "default" + } + ipam := dockerNetwork.IPAM{ + Driver: ipamDriver, + Options: network.IPAMOptions, + Config: ipamConfigs, } report := types.NetworkResource{ - Name: conf.Name, - ID: networkid.GetNetworkID(conf.Name), - Created: time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)), // nolint: unconvert + Name: network.Name, + ID: network.ID, + Driver: network.Driver, + // TODO add Created: , + Internal: network.Internal, + EnableIPv6: network.IPv6Enabled, + Labels: network.Labels, + Options: network.Options, + IPAM: ipam, Scope: "local", - Driver: plugin.PluginType, - EnableIPv6: false, - IPAM: dockerNetwork.IPAM{ - Driver: dockerDriver, - Options: map[string]string{}, - Config: ipamConfigs, - }, - Internal: isInternal, Attachable: false, Ingress: false, ConfigFrom: dockerNetwork.ConfigReference{}, ConfigOnly: false, Containers: containerEndpoints, - Options: map[string]string{}, - Labels: labels, Peers: nil, Services: nil, } return &report, nil } -func getPlugin(plugins []*libcni.NetworkConfig) (pluginInterface, error) { - var plugin pluginInterface - - for _, p := range plugins { - for _, pluginType := range network.SupportedNetworkDrivers { - if pluginType == p.Network.Type { - err := json.Unmarshal(p.Bytes, &plugin) - return plugin, err - } - } - } - - return plugin, errors.New("unable to find supported plugin") -} - func ListNetworks(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) filterMap, err := util.PrepareFilters(r) @@ -204,37 +128,32 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) { return } - config, err := runtime.GetConfig() - if err != nil { - utils.InternalServerError(w, err) - return + options := entities.NetworkListOptions{ + Filters: *filterMap, } - netNames, err := network.GetNetworkNamesFromFileSystem(config) + ic := abi.ContainerEngine{Libpod: runtime} + nets, err := ic.NetworkList(r.Context(), options) if err != nil { utils.InternalServerError(w, err) return } - - reports := []*types.NetworkResource{} - logrus.Debugf("netNames: %q", strings.Join(netNames, ", ")) - for _, name := range netNames { - report, err := getNetworkResourceByNameOrID(name, runtime, *filterMap) + reports := make([]*types.NetworkResource, 0, len(nets)) + for _, net := range nets { + report, err := convertLibpodNetworktoDockerNetwork(runtime, net) if err != nil { utils.InternalServerError(w, err) return } - if report != nil { - reports = append(reports, report) - } + reports = append(reports, report) } utils.WriteResponse(w, http.StatusOK, reports) } func CreateNetwork(w http.ResponseWriter, r *http.Request) { var ( - name string networkCreate types.NetworkCreateRequest + network nettypes.Network ) runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) if err := json.NewDecoder(r.Body).Decode(&networkCreate); err != nil { @@ -242,65 +161,80 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) { return } - if len(networkCreate.Name) > 0 { - name = networkCreate.Name - } - if len(networkCreate.Driver) < 1 { - networkCreate.Driver = network.DefaultNetworkDriver + network.Name = networkCreate.Name + if networkCreate.Driver == "" { + networkCreate.Driver = nettypes.DefaultNetworkDriver } - // At present I think we should just support the bridge driver - // and allow demand to make us consider more - if networkCreate.Driver != network.DefaultNetworkDriver { - utils.InternalServerError(w, errors.New("network create only supports the bridge driver")) - return - } - ncOptions := entities.NetworkCreateOptions{ - Driver: network.DefaultNetworkDriver, - Internal: networkCreate.Internal, - Labels: networkCreate.Labels, + network.Driver = networkCreate.Driver + network.Labels = networkCreate.Labels + network.Internal = networkCreate.Internal + network.IPv6Enabled = networkCreate.EnableIPv6 + + // FIXME use docker options and convert them to valid libpod options + // network.Options = networkCreate.Options + + // dns is only enabled for the bridge driver + if network.Driver == nettypes.BridgeNetworkDriver { + network.DNSEnabled = true } - if networkCreate.IPAM != nil && len(networkCreate.IPAM.Config) > 0 { - if len(networkCreate.IPAM.Config) > 1 { - utils.InternalServerError(w, errors.New("compat network create can only support one IPAM config")) - return - } - if len(networkCreate.IPAM.Config[0].Subnet) > 0 { - _, subnet, err := net.ParseCIDR(networkCreate.IPAM.Config[0].Subnet) - if err != nil { - utils.InternalServerError(w, err) - return + if networkCreate.IPAM != nil && len(networkCreate.IPAM.Config) > 0 { + for _, conf := range networkCreate.IPAM.Config { + s := nettypes.Subnet{} + if len(conf.Subnet) > 0 { + var err error + subnet, err := nettypes.ParseCIDR(conf.Subnet) + if err != nil { + utils.InternalServerError(w, errors.Wrap(err, "failed to parse subnet")) + return + } + s.Subnet = subnet } - ncOptions.Subnet = *subnet - } - if len(networkCreate.IPAM.Config[0].Gateway) > 0 { - ncOptions.Gateway = net.ParseIP(networkCreate.IPAM.Config[0].Gateway) - } - if len(networkCreate.IPAM.Config[0].IPRange) > 0 { - _, IPRange, err := net.ParseCIDR(networkCreate.IPAM.Config[0].IPRange) - if err != nil { - utils.InternalServerError(w, err) - return + if len(conf.Gateway) > 0 { + gw := net.ParseIP(conf.Gateway) + if gw == nil { + utils.InternalServerError(w, errors.Errorf("failed to parse gateway ip %s", conf.Gateway)) + return + } + s.Gateway = gw + } + if len(conf.IPRange) > 0 { + _, net, err := net.ParseCIDR(conf.IPRange) + if err != nil { + utils.InternalServerError(w, errors.Wrap(err, "failed to parse ip range")) + return + } + startIP, err := netutil.FirstIPInSubnet(net) + if err != nil { + utils.InternalServerError(w, errors.Wrap(err, "failed to get first ip in range")) + return + } + lastIP, err := netutil.LastIPInSubnet(net) + if err != nil { + utils.InternalServerError(w, errors.Wrap(err, "failed to get last ip in range")) + return + } + s.LeaseRange = &nettypes.LeaseRange{ + StartIP: startIP, + EndIP: lastIP, + } } - ncOptions.Range = *IPRange + network.Subnets = append(network.Subnets, s) } - } - ce := abi.ContainerEngine{Libpod: runtime} - if _, err := ce.NetworkCreate(r.Context(), name, ncOptions); err != nil { - utils.InternalServerError(w, err) - return + // FIXME can we use the IPAM driver and options? } - net, err := getNetworkResourceByNameOrID(name, runtime, nil) + network, err := runtime.Network().NetworkCreate(network) if err != nil { utils.InternalServerError(w, err) return } + body := struct { ID string `json:"Id"` Warning []string }{ - ID: net.ID, + ID: network.ID, } utils.WriteResponse(w, http.StatusCreated, body) } diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go index 122ab1d3d..fcd8e0231 100644 --- a/pkg/api/handlers/libpod/networks.go +++ b/pkg/api/handlers/libpod/networks.go @@ -6,7 +6,7 @@ import ( "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" - "github.com/containers/podman/v3/libpod/network" + "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/api/handlers/utils" api "github.com/containers/podman/v3/pkg/api/types" "github.com/containers/podman/v3/pkg/domain/entities" @@ -18,27 +18,14 @@ import ( func CreateNetwork(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) - decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) - options := entities.NetworkCreateOptions{} - if err := json.NewDecoder(r.Body).Decode(&options); err != nil { - utils.Error(w, "unable to marshall input", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) + network := types.Network{} + if err := json.NewDecoder(r.Body).Decode(&network); err != nil { + utils.Error(w, "unable to marshall input", http.StatusInternalServerError, errors.Wrap(err, "decode body")) return } - query := struct { - Name string `schema:"name"` - }{ - // override any golang type defaults - } - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, - errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) - return - } - if len(options.Driver) < 1 { - options.Driver = network.DefaultNetworkDriver - } + ic := abi.ContainerEngine{Libpod: runtime} - report, err := ic.NetworkCreate(r.Context(), query.Name, options) + report, err := ic.Libpod.Network().NetworkCreate(network) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/handlers/libpod/swagger.go b/pkg/api/handlers/libpod/swagger.go index 6116a7274..7ccfdd0f3 100644 --- a/pkg/api/handlers/libpod/swagger.go +++ b/pkg/api/handlers/libpod/swagger.go @@ -4,9 +4,9 @@ import ( "net/http" "os" - "github.com/containernetworking/cni/libcni" "github.com/containers/image/v5/manifest" "github.com/containers/podman/v3/libpod/define" + "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/api/handlers/utils" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/pkg/errors" @@ -103,21 +103,27 @@ type swagNetworkRmReport struct { // swagger:response NetworkInspectReport type swagNetworkInspectReport struct { // in:body - Body libcni.NetworkConfigList + Body types.Network } // Network list // swagger:response NetworkListReport type swagNetworkListReport struct { // in:body - Body []entities.NetworkListReport + Body []types.Network +} + +// Network create +// swagger:model NetworkCreateLibpod +type swagNetworkCreateLibpod struct { + types.Network } // Network create // swagger:response NetworkCreateReport type swagNetworkCreateReport struct { // in:body - Body entities.NetworkCreateReport + Body types.Network } // Network prune diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go index cacf83a7f..641bce333 100644 --- a/pkg/api/server/register_networks.go +++ b/pkg/api/server/register_networks.go @@ -267,7 +267,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // - `id=[id]` Matches for full or partial ID. // - `driver=[driver]` Only bridge is supported. // - `label=[key]` or `label=[key=value]` Matches networks based on the presence of a label alone or a label and a value. - // - `plugin=[plugin]` Matches CNI plugins included in a network (e.g `bridge`,`portmap`,`firewall`,`tuning`,`dnsname`,`macvlan`) + // - `until=[timestamp]` Matches all networks that were create before the given timestamp. // produces: // - application/json // responses: @@ -306,19 +306,15 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // tags: // - networks // summary: Create network - // description: Create a new CNI network configuration + // description: Create a new network configuration // produces: // - application/json // parameters: - // - in: query - // name: name - // type: string - // description: optional name for new network // - in: body // name: create // description: attributes for creating a container // schema: - // $ref: "#/definitions/NetworkCreateOptions" + // $ref: "#/definitions/NetworkCreateLibpod" // responses: // 200: // $ref: "#/responses/NetworkCreateReport" diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go index 59207aa8d..5a0a34f56 100644 --- a/pkg/bindings/network/network.go +++ b/pkg/bindings/network/network.go @@ -6,58 +6,51 @@ import ( "net/url" "strings" + "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/domain/entities" jsoniter "github.com/json-iterator/go" ) // Create makes a new CNI network configuration -func Create(ctx context.Context, options *CreateOptions) (*entities.NetworkCreateReport, error) { - var report entities.NetworkCreateReport - if options == nil { - options = new(CreateOptions) - } +func Create(ctx context.Context, network *types.Network) (types.Network, error) { + var report types.Network conn, err := bindings.GetClient(ctx) if err != nil { - return nil, err + return report, err } - params := url.Values{} - if options.Name != nil { - params.Set("name", options.GetName()) + // create empty network if the caller did not provide one + if network == nil { + network = &types.Network{} } - networkConfig, err := jsoniter.MarshalToString(options) + networkConfig, err := jsoniter.MarshalToString(*network) if err != nil { - return nil, err + return report, err } - stringReader := strings.NewReader(networkConfig) - response, err := conn.DoRequest(stringReader, http.MethodPost, "/networks/create", params, nil) + reader := strings.NewReader(networkConfig) + response, err := conn.DoRequest(reader, http.MethodPost, "/networks/create", nil, nil) if err != nil { - return nil, err + return report, err } defer response.Body.Close() - return &report, response.Process(&report) + return report, response.Process(&report) } // Inspect returns low level information about a CNI network configuration -func Inspect(ctx context.Context, nameOrID string, options *InspectOptions) ([]entities.NetworkInspectReport, error) { - var reports []entities.NetworkInspectReport - reports = append(reports, entities.NetworkInspectReport{}) - if options == nil { - options = new(InspectOptions) - } - _ = options +func Inspect(ctx context.Context, nameOrID string, _ *InspectOptions) (types.Network, error) { + var net types.Network conn, err := bindings.GetClient(ctx) if err != nil { - return nil, err + return net, err } response, err := conn.DoRequest(nil, http.MethodGet, "/networks/%s/json", nil, nil, nameOrID) if err != nil { - return nil, err + return net, err } defer response.Body.Close() - return reports, response.Process(&reports[0]) + return net, response.Process(&net) } // Remove deletes a defined CNI network configuration by name. The optional force boolean @@ -86,10 +79,8 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) ([]*en } // List returns a summary of all CNI network configurations -func List(ctx context.Context, options *ListOptions) ([]*entities.NetworkListReport, error) { - var ( - netList []*entities.NetworkListReport - ) +func List(ctx context.Context, options *ListOptions) ([]types.Network, error) { + var netList []types.Network if options == nil { options = new(ListOptions) } diff --git a/pkg/bindings/test/networks_test.go b/pkg/bindings/test/networks_test.go index b53fc4bd3..85ceeb998 100644 --- a/pkg/bindings/test/networks_test.go +++ b/pkg/bindings/test/networks_test.go @@ -6,6 +6,7 @@ import ( "net/http" "time" + "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/bindings/containers" "github.com/containers/podman/v3/pkg/bindings/network" @@ -41,10 +42,10 @@ var _ = Describe("Podman networks", func() { It("podman prune unused networks with filters", func() { name := "foobar" - opts := network.CreateOptions{ - Name: &name, + net := types.Network{ + Name: name, } - _, err = network.Create(connText, &opts) + _, err = network.Create(connText, &net) Expect(err).To(BeNil()) // Invalid filters should return error @@ -88,20 +89,20 @@ var _ = Describe("Podman networks", func() { It("create network", func() { // create a network with blank config should work - _, err = network.Create(connText, &network.CreateOptions{}) + _, err = network.Create(connText, nil) Expect(err).To(BeNil()) name := "foobar" - opts := network.CreateOptions{ - Name: &name, + net := types.Network{ + Name: name, } - report, err := network.Create(connText, &opts) + report, err := network.Create(connText, &net) Expect(err).To(BeNil()) - Expect(report.Filename).To(ContainSubstring(name)) + Expect(report.Name).To(Equal(name)) // create network with same name should 500 - _, err = network.Create(connText, &opts) + _, err = network.Create(connText, &net) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -109,24 +110,24 @@ var _ = Describe("Podman networks", func() { It("inspect network", func() { name := "foobar" - opts := network.CreateOptions{ - Name: &name, + net := types.Network{ + Name: name, } - _, err = network.Create(connText, &opts) + _, err = network.Create(connText, &net) Expect(err).To(BeNil()) data, err := network.Inspect(connText, name, nil) Expect(err).To(BeNil()) - Expect(data[0]["name"]).To(Equal(name)) + Expect(data.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], + net := types.Network{ + Name: netNames[i], } - _, err = network.Create(connText, &opts) + _, err = network.Create(connText, &net) Expect(err).To(BeNil()) } list, err := network.List(connText, nil) @@ -166,10 +167,10 @@ var _ = Describe("Podman networks", func() { // Removing an unused network should work name := "unused" - opts := network.CreateOptions{ - Name: &name, + net := types.Network{ + Name: name, } - _, err = network.Create(connText, &opts) + _, err = network.Create(connText, &net) Expect(err).To(BeNil()) report, err := network.Remove(connText, name, nil) Expect(err).To(BeNil()) @@ -177,10 +178,10 @@ var _ = Describe("Podman networks", func() { // Removing a network that is being used without force should be 500 name = "used" - opts = network.CreateOptions{ - Name: &name, + net = types.Network{ + Name: name, } - _, err = network.Create(connText, &opts) + _, err = network.Create(connText, &net) Expect(err).To(BeNil()) // Start container and wait diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 3da31d8a0..b916d6fc6 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -6,6 +6,7 @@ import ( "github.com/containers/common/pkg/config" "github.com/containers/podman/v3/libpod/define" + "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/domain/entities/reports" "github.com/containers/podman/v3/pkg/specgen" ) @@ -58,11 +59,11 @@ type ContainerEngine interface { HealthCheckRun(ctx context.Context, nameOrID string, options HealthCheckOptions) (*define.HealthCheckResults, error) Info(ctx context.Context) (*define.Info, error) NetworkConnect(ctx context.Context, networkname string, options NetworkConnectOptions) error - NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (*NetworkCreateReport, error) + NetworkCreate(ctx context.Context, network types.Network) (*NetworkCreateReport, error) NetworkDisconnect(ctx context.Context, networkname string, options NetworkDisconnectOptions) error 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) + NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]types.Network, []error, error) + NetworkList(ctx context.Context, options NetworkListOptions) ([]types.Network, 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) diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go index a89501664..b61297d41 100644 --- a/pkg/domain/entities/network.go +++ b/pkg/domain/entities/network.go @@ -2,8 +2,6 @@ package entities import ( "net" - - "github.com/containernetworking/cni/libcni" ) // NetworkListOptions describes options for listing networks in cli @@ -13,15 +11,6 @@ type NetworkListOptions struct { Filters map[string][]string } -// NetworkListReport describes the results from listing networks -type NetworkListReport struct { - *libcni.NetworkConfigList - Labels map[string]string -} - -// NetworkInspectReport describes the results from inspect networks -type NetworkInspectReport map[string]interface{} - // NetworkReloadOptions describes options for reloading container network // configuration. type NetworkReloadOptions struct { @@ -48,7 +37,6 @@ type NetworkRmReport struct { } // NetworkCreateOptions describes options to create a network -// swagger:model NetworkCreateOptions type NetworkCreateOptions struct { DisableDNS bool Driver string @@ -65,7 +53,7 @@ type NetworkCreateOptions struct { // NetworkCreateReport describes a created network for the cli type NetworkCreateReport struct { - Filename string + Name string } // NetworkDisconnectOptions describes options for disconnecting diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go index 7900caaa6..45d2c6925 100644 --- a/pkg/domain/infra/abi/network.go +++ b/pkg/domain/infra/abi/network.go @@ -4,60 +4,38 @@ import ( "context" "github.com/containers/podman/v3/libpod/define" - "github.com/containers/podman/v3/libpod/network" + "github.com/containers/podman/v3/libpod/network/types" + netutil "github.com/containers/podman/v3/libpod/network/util" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/util" "github.com/pkg/errors" ) -func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]*entities.NetworkListReport, error) { - reports := make([]*entities.NetworkListReport, 0) - - config, err := ic.Libpod.GetConfig() - if err != nil { - return nil, err - } - - networks, err := network.LoadCNIConfsFromDir(network.GetCNIConfDir(config)) +func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]types.Network, error) { + filters, err := netutil.GenerateNetworkFilters(options.Filters) if err != nil { return nil, err } - - for _, n := range networks { - ok, err := network.IfPassesFilter(n, options.Filters) - if err != nil { - return nil, err - } - if ok { - reports = append(reports, &entities.NetworkListReport{ - NetworkConfigList: n, - Labels: network.GetNetworkLabels(n), - }) - } - } - return reports, nil + nets, err := ic.Libpod.Network().NetworkList(filters...) + return nets, err } -func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) { - config, err := ic.Libpod.GetConfig() - if err != nil { - return nil, nil, err - } +func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]types.Network, []error, error) { var errs []error - rawCNINetworks := make([]entities.NetworkInspectReport, 0, len(namesOrIds)) + networks := make([]types.Network, 0, len(namesOrIds)) for _, name := range namesOrIds { - rawList, err := network.InspectNetwork(config, name) + net, err := ic.Libpod.Network().NetworkInspect(name) if err != nil { if errors.Cause(err) == define.ErrNoSuchNetwork { - errs = append(errs, errors.Errorf("no such network %s", name)) + errs = append(errs, errors.Wrapf(err, "network %s", name)) continue } else { return nil, nil, errors.Wrapf(err, "error inspecting network %s", name) } } - rawCNINetworks = append(rawCNINetworks, rawList) + networks = append(networks, net) } - return rawCNINetworks, errs, nil + return networks, errs, nil } func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, options entities.NetworkReloadOptions) ([]*entities.NetworkReloadReport, error) { @@ -83,12 +61,7 @@ func (ic *ContainerEngine) NetworkReload(ctx context.Context, names []string, op } func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) { - reports := []*entities.NetworkRmReport{} - - config, err := ic.Libpod.GetConfig() - if err != nil { - return nil, err - } + reports := make([]*entities.NetworkRmReport, 0, len(namesOrIds)) for _, name := range namesOrIds { report := entities.NetworkRmReport{Name: name} @@ -126,7 +99,7 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o } } } - if err := network.RemoveNetwork(config, name); err != nil { + if err := ic.Libpod.Network().NetworkRemove(name); err != nil { report.Err = err } reports = append(reports, &report) @@ -134,12 +107,12 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o return reports, nil } -func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, options entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) { - runtimeConfig, err := ic.Libpod.GetConfig() +func (ic *ContainerEngine) NetworkCreate(ctx context.Context, network types.Network) (*entities.NetworkCreateReport, error) { + network, err := ic.Libpod.Network().NetworkCreate(network) if err != nil { return nil, err } - return network.Create(name, options, runtimeConfig) + return &entities.NetworkCreateReport{Name: network.Name}, nil } // NetworkDisconnect removes a container from a given network @@ -153,12 +126,12 @@ func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname strin // NetworkExists checks if the given network exists func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string) (*entities.BoolReport, error) { - config, err := ic.Libpod.GetConfig() - if err != nil { - return nil, err - } - exists, err := network.Exists(config, networkname) - if err != nil { + _, err := ic.Libpod.Network().NetworkInspect(networkname) + exists := true + // if err is ErrNoSuchNetwork do not return it + if errors.Is(err, define.ErrNoSuchNetwork) { + exists = false + } else if err != nil { return nil, err } return &entities.BoolReport{ @@ -168,19 +141,10 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string // 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 } - networks, err := network.LoadCNIConfsFromDir(network.GetCNIConfDir(runtimeConfig)) - if err != nil { - return nil, err - } - // Gather up all the non-default networks that the // containers want networksToKeep := make(map[string]bool) @@ -193,20 +157,34 @@ func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.Ne networksToKeep[n] = true } } - if len(options.Filters) != 0 { - for _, n := range networks { - // This network will be kept anyway - if _, found := networksToKeep[n.Name]; found { - continue - } - ok, err := network.IfPassesPruneFilter(runtimeConfig, n, options.Filters) - if err != nil { - return nil, err - } - if !ok { - networksToKeep[n.Name] = true + // ignore the default network, this one cannot be deleted + networksToKeep[ic.Libpod.GetDefaultNetworkName()] = true + + // get all filters + filters, err := netutil.GenerateNetworkPruneFilters(options.Filters) + if err != nil { + return nil, err + } + danglingFilterFunc := func(net types.Network) bool { + for network := range networksToKeep { + if network == net.Name { + return false } } + return true + } + filters = append(filters, danglingFilterFunc) + nets, err := ic.Libpod.Network().NetworkList(filters...) + if err != nil { + return nil, err + } + + pruneReport := make([]*entities.NetworkPruneReport, 0, len(nets)) + for _, net := range nets { + pruneReport = append(pruneReport, &entities.NetworkPruneReport{ + Name: net.Name, + Error: ic.Libpod.Network().NetworkRemove(net.Name), + }) } - return network.PruneNetworks(runtimeConfig, networksToKeep) + return pruneReport, nil } diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go index 7e59e44c2..711c2e00c 100644 --- a/pkg/domain/infra/tunnel/network.go +++ b/pkg/domain/infra/tunnel/network.go @@ -3,20 +3,22 @@ package tunnel import ( "context" + "github.com/containers/podman/v3/libpod/define" + "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/bindings/network" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/errorhandling" "github.com/pkg/errors" ) -func (ic *ContainerEngine) NetworkList(ctx context.Context, opts entities.NetworkListOptions) ([]*entities.NetworkListReport, error) { +func (ic *ContainerEngine) NetworkList(ctx context.Context, opts entities.NetworkListOptions) ([]types.Network, error) { options := new(network.ListOptions).WithFilters(opts.Filters) return network.List(ic.ClientCtx, options) } -func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) { +func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]types.Network, []error, error) { var ( - reports = make([]entities.NetworkInspectReport, 0, len(namesOrIds)) + reports = make([]types.Network, 0, len(namesOrIds)) errs = []error{} ) options := new(network.InspectOptions) @@ -28,12 +30,12 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri return nil, nil, err } if errModel.ResponseCode == 404 { - errs = append(errs, errors.Errorf("no such network %q", name)) + errs = append(errs, errors.Wrapf(define.ErrNoSuchNetwork, "network %s", name)) continue } return nil, nil, err } - reports = append(reports, report...) + reports = append(reports, report) } return reports, errs, nil } @@ -60,11 +62,12 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o return reports, nil } -func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, opts entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) { - options := new(network.CreateOptions).WithName(name).WithDisableDNS(opts.DisableDNS).WithDriver(opts.Driver).WithGateway(opts.Gateway) - options.WithInternal(opts.Internal).WithIPRange(opts.Range).WithIPv6(opts.IPv6).WithLabels(opts.Labels).WithIPv6(opts.IPv6) - options.WithMacVLAN(opts.MacVLAN).WithOptions(opts.Options).WithSubnet(opts.Subnet) - return network.Create(ic.ClientCtx, options) +func (ic *ContainerEngine) NetworkCreate(ctx context.Context, net types.Network) (*entities.NetworkCreateReport, error) { + net, err := network.Create(ic.ClientCtx, &net) + if err != nil { + return nil, err + } + return &entities.NetworkCreateReport{Name: net.Name}, nil } // NetworkDisconnect removes a container from a given network |