Skip to content

Commit

Permalink
podman network inspect: include running containers
Browse files Browse the repository at this point in the history
Like docker podman network inspect should output the information of
running container with their ip/mac address on this network.
However the output format is not docker compatible as this cannot
include all the info we have and the previous output was already not
compatible so this is not new.

New example output:
```
[
     {
          ...
          "containers": {
               "7c0d295779cee4a6db7adc07a99e635909413a390eeab9f951edbc4aac406bf1": {
                    "name": "c2",
                    "interfaces": {
                         "eth0": {
                              "subnets": [
                                   {
                                        "ipnet": "10.89.0.4/24",
                                        "gateway": "10.89.0.1"
                                   },
                                   {
                                        "ipnet": "fda3:b4da:da1e:7e9d::4/64",
                                        "gateway": "fda3:b4da:da1e:7e9d::1"
                                   }
                              ],
                              "mac_address": "1a:bd:ca:ea:4b:3a"
                         }
                    }
               },
               "b17c6651ae6d9cc7d5825968e01d6b1e67f44460bb0c140bcc32bd9d436ac11d": {
                    "name": "c1",
                    "interfaces": {
                         "eth0": {
                              "subnets": [
                                   {
                                        "ipnet": "10.89.0.3/24",
                                        "gateway": "10.89.0.1"
                                   },
                                   {
                                        "ipnet": "fda3:b4da:da1e:7e9d::3/64",
                                        "gateway": "fda3:b4da:da1e:7e9d::1"
                                   }
                              ],
                              "mac_address": "f6:50:e6:22:d9:55"
                         }
                    }
               }
          }
     }
]
```

Fixes containers#14126
Fixes https://issues.redhat.com/browse/RHEL-3153

Signed-off-by: Paul Holzinger <[email protected]>
  • Loading branch information
Luap99 committed Feb 28, 2024
1 parent 031e7a1 commit 5952486
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 65 deletions.
2 changes: 1 addition & 1 deletion cmd/podman/common/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ func getEntityType(cmd *cobra.Command, args []string, o interface{}) interface{}
}
// network logic
if networks, _ := getNetworks(cmd, args[0], completeDefault); len(networks) > 0 {
return &types.Network{}
return &entities.NetworkInspectReport{}
}
return o
}
Expand Down
3 changes: 1 addition & 2 deletions cmd/podman/networks/inspect.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package network

import (
"github.com/containers/common/libnetwork/types"
"github.com/containers/podman/v5/cmd/podman/common"
"github.com/containers/podman/v5/cmd/podman/inspect"
"github.com/containers/podman/v5/cmd/podman/registry"
Expand Down Expand Up @@ -33,7 +32,7 @@ func init() {

formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "", "Pretty-print network to JSON or using a Go template")
_ = networkinspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&types.Network{}))
_ = networkinspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&entities.NetworkInspectReport{}))
}

func networkInspect(_ *cobra.Command, args []string) error {
Expand Down
2 changes: 2 additions & 0 deletions docs/source/markdown/podman-network-inspect.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Pretty-print networks to JSON or using a Go template.

| **Placeholder** | **Description** |
|--------------------|-------------------------------------------|
| .Containers ... | Running containers on this network. |
| .Created ... | Timestamp when the network was created |
| .DNSEnabled | Network has dns enabled (boolean) |
| .Driver | Network driver |
Expand All @@ -25,6 +26,7 @@ Pretty-print networks to JSON or using a Go template.
| .IPv6Enabled | Network has ipv6 subnet (boolean) |
| .Labels ... | Network labels |
| .Name | Network name |
| .Network ... | Nested Network type |
| .NetworkDNSServers | Array of DNS servers used in this network |
| .NetworkInterface | Name of the network interface on the host |
| .Options ... | Network options |
Expand Down
43 changes: 7 additions & 36 deletions pkg/api/handlers/compat/networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,6 @@ import (
"github.com/sirupsen/logrus"
)

type containerNetStatus struct {
name string
id string
status map[string]nettypes.StatusBlock
}

func getContainerNetStatuses(rt *libpod.Runtime) ([]containerNetStatus, error) {
cons, err := rt.GetAllContainers()
if err != nil {
return nil, err
}
statuses := make([]containerNetStatus, 0, len(cons))
for _, con := range cons {
status, err := con.GetNetworkStatus()
if err != nil {
if errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved) {
continue
}
return nil, err
}

statuses = append(statuses, containerNetStatus{
id: con.ID(),
name: con.Name(),
status: status,
})
}
return statuses, nil
}

func normalizeNetworkName(rt *libpod.Runtime, name string) (string, bool) {
if name == nettypes.BridgeNetworkDriver {
return rt.Network().DefaultNetworkName(), true
Expand Down Expand Up @@ -86,7 +56,8 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
utils.NetworkNotFound(w, name, err)
return
}
statuses, err := getContainerNetStatuses(runtime)
ic := abi.ContainerEngine{Libpod: runtime}
statuses, err := ic.GetContainerNetStatuses()
if err != nil {
utils.InternalServerError(w, err)
return
Expand All @@ -95,10 +66,10 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, report)
}

func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, statuses []containerNetStatus, network *nettypes.Network, changeDefaultName bool) *types.NetworkResource {
func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, statuses []abi.ContainerNetStatus, network *nettypes.Network, changeDefaultName bool) *types.NetworkResource {
containerEndpoints := make(map[string]types.EndpointResource, len(statuses))
for _, st := range statuses {
if netData, ok := st.status[network.Name]; ok {
if netData, ok := st.Status[network.Name]; ok {
ipv4Address := ""
ipv6Address := ""
macAddr := ""
Expand All @@ -116,12 +87,12 @@ func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, statuses []con
break
}
containerEndpoint := types.EndpointResource{
Name: st.name,
Name: st.Name,
MacAddress: macAddr,
IPv4Address: ipv4Address,
IPv6Address: ipv6Address,
}
containerEndpoints[st.id] = containerEndpoint
containerEndpoints[st.ID] = containerEndpoint
}
}
ipamConfigs := make([]dockerNetwork.IPAMConfig, 0, len(network.Subnets))
Expand Down Expand Up @@ -192,7 +163,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
statuses, err := getContainerNetStatuses(runtime)
statuses, err := ic.GetContainerNetStatuses()
if err != nil {
utils.InternalServerError(w, err)
return
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/handlers/swagger/responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ type networkRmResponse struct {
// swagger:response
type networkInspectResponse struct {
// in:body
Body types.Network
Body entities.NetworkInspectReport
}

// Network list
Expand Down
4 changes: 2 additions & 2 deletions pkg/bindings/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ func Update(ctx context.Context, netNameOrID string, options *UpdateOptions) err
}

// Inspect returns information about a network configuration
func Inspect(ctx context.Context, nameOrID string, _ *InspectOptions) (types.Network, error) {
var net types.Network
func Inspect(ctx context.Context, nameOrID string, _ *InspectOptions) (entitiesTypes.NetworkInspectReport, error) {
var net entitiesTypes.NetworkInspectReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return net, err
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/entities/engine_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ type ContainerEngine interface { //nolint:interfacebloat
NetworkUpdate(ctx context.Context, networkname string, options NetworkUpdateOptions) 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) ([]netTypes.Network, []error, error)
NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]NetworkInspectReport, []error, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]netTypes.Network, error)
NetworkPrune(ctx context.Context, options NetworkPruneOptions) ([]*NetworkPruneReport, error)
NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, error)
Expand Down
3 changes: 3 additions & 0 deletions pkg/domain/entities/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,6 @@ type NetworkPruneReport = entitiesTypes.NetworkPruneReport
type NetworkPruneOptions struct {
Filters map[string][]string
}

type NetworkInspectReport = entitiesTypes.NetworkInspectReport
type NetworkContainerInfo = entitiesTypes.NetworkContainerInfo
14 changes: 14 additions & 0 deletions pkg/domain/entities/types/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,17 @@ type NetworkRmReport struct {
type NetworkCreateReport struct {
Name string
}

type NetworkInspectReport struct {
commonTypes.Network

Containers map[string]NetworkContainerInfo `json:"containers"`
}

type NetworkContainerInfo struct {
// Name of the container
Name string `json:"name"`

// Interfaces configured for this container with their addresses
Interfaces map[string]commonTypes.NetInterface `json:"interfaces,omitempty"`
}
58 changes: 55 additions & 3 deletions pkg/domain/infra/abi/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,13 @@ func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.Net
return nets, err
}

func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]types.Network, []error, error) {
func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
var errs []error
networks := make([]types.Network, 0, len(namesOrIds))
statuses, err := ic.GetContainerNetStatuses()
if err != nil {
return nil, nil, fmt.Errorf("failed to get network status for containers: %w", err)
}
networks := make([]entities.NetworkInspectReport, 0, len(namesOrIds))
for _, name := range namesOrIds {
net, err := ic.Libpod.Network().NetworkInspect(name)
if err != nil {
Expand All @@ -77,7 +81,22 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri
return nil, nil, fmt.Errorf("inspecting network %s: %w", name, err)
}
}
networks = append(networks, net)
containerMap := make(map[string]entities.NetworkContainerInfo)
for _, st := range statuses {
// Make sure to only show the info for the correct network
if sb, ok := st.Status[net.Name]; ok {
containerMap[st.ID] = entities.NetworkContainerInfo{
Name: st.Name,
Interfaces: sb.Interfaces,
}
}
}

netReport := entities.NetworkInspectReport{
Network: net,
Containers: containerMap,
}
networks = append(networks, netReport)
}
return networks, errs, nil
}
Expand Down Expand Up @@ -243,3 +262,36 @@ func (ic *ContainerEngine) createDanglingFilterFunc(wantDangling bool) (types.Fi
return wantDangling
}, nil
}

type ContainerNetStatus struct {
// Name of the container
Name string
// ID of the container
ID string
// Status contains the net status, the key is the network name
Status map[string]types.StatusBlock
}

func (ic *ContainerEngine) GetContainerNetStatuses() ([]ContainerNetStatus, error) {
cons, err := ic.Libpod.GetAllContainers()
if err != nil {
return nil, err
}
statuses := make([]ContainerNetStatus, 0, len(cons))
for _, con := range cons {
status, err := con.GetNetworkStatus()
if err != nil {
if errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved) {
continue
}
return nil, err
}

statuses = append(statuses, ContainerNetStatus{
ID: con.ID(),
Name: con.Name(),
Status: status,
})
}
return statuses, nil
}
4 changes: 2 additions & 2 deletions pkg/domain/infra/tunnel/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ func (ic *ContainerEngine) NetworkList(ctx context.Context, opts entities.Networ
return network.List(ic.ClientCtx, options)
}

func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]types.Network, []error, error) {
func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, opts entities.InspectOptions) ([]entities.NetworkInspectReport, []error, error) {
var (
reports = make([]types.Network, 0, len(namesOrIds))
reports = make([]entities.NetworkInspectReport, 0, len(namesOrIds))
errs = []error{}
)
options := new(network.InspectOptions)
Expand Down
19 changes: 10 additions & 9 deletions test/e2e/network_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net"

"github.com/containers/common/libnetwork/types"
"github.com/containers/podman/v5/pkg/domain/entities"
. "github.com/containers/podman/v5/test/utils"
"github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -32,7 +33,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down Expand Up @@ -84,7 +85,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down Expand Up @@ -125,7 +126,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down Expand Up @@ -168,7 +169,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down Expand Up @@ -213,7 +214,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down Expand Up @@ -254,7 +255,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down Expand Up @@ -284,7 +285,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down Expand Up @@ -323,7 +324,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down Expand Up @@ -711,7 +712,7 @@ var _ = Describe("Podman network create", func() {
Expect(inspect).Should(ExitCleanly())

// JSON the network configuration into something usable
var results []types.Network
var results []entities.NetworkInspectReport
err := json.Unmarshal([]byte(inspect.OutputToString()), &results)
Expect(err).ToNot(HaveOccurred())
Expect(results).To(HaveLen(1))
Expand Down
Loading

0 comments on commit 5952486

Please sign in to comment.