Merge pull request #20056 from Luap99/fast-net-ls

compat API: speed up network list
This commit is contained in:
OpenShift Merge Robot 2023-09-20 16:43:00 +02:00 committed by GitHub
commit c5be3aecde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 48 deletions

View File

@ -1220,23 +1220,6 @@ func (c *Container) HostNetwork() bool {
return true return true
} }
// ContainerState returns containerstate struct
func (c *Container) ContainerState() (*ContainerState, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return nil, err
}
}
returnConfig := new(ContainerState)
if err := JSONDeepCopy(c.state, returnConfig); err != nil {
return nil, fmt.Errorf("copying container %s state: %w", c.ID(), err)
}
return c.state, nil
}
// HasHealthCheck returns bool as to whether there is a health check // HasHealthCheck returns bool as to whether there is a health check
// defined for the container // defined for the container
func (c *Container) HasHealthCheck() bool { func (c *Container) HasHealthCheck() bool {
@ -1356,6 +1339,21 @@ func (d ContainerNetworkDescriptions) getInterfaceByName(networkName string) (st
return fmt.Sprintf("eth%d", val), exists return fmt.Sprintf("eth%d", val), exists
} }
// GetNetworkStatus returns the current network status for this container.
// This returns a map without deep copying which means this should only ever
// be used as read only access, do not modify this status.
func (c *Container) GetNetworkStatus() (map[string]types.StatusBlock, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return nil, err
}
}
return c.getNetworkStatus(), nil
}
// getNetworkStatus get the current network status from the state. If the container // getNetworkStatus get the current network status from the state. If the container
// still uses the old network status it is converted to the new format. This function // still uses the old network status it is converted to the new format. This function
// should be used instead of reading c.state.NetworkStatus directly. // should be used instead of reading c.state.NetworkStatus directly.

View File

@ -22,6 +22,36 @@ import (
"github.com/sirupsen/logrus" "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) { func normalizeNetworkName(rt *libpod.Runtime, name string) (string, bool) {
if name == nettypes.BridgeNetworkDriver { if name == nettypes.BridgeNetworkDriver {
return rt.Network().DefaultNetworkName(), true return rt.Network().DefaultNetworkName(), true
@ -56,45 +86,42 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
utils.NetworkNotFound(w, name, err) utils.NetworkNotFound(w, name, err)
return return
} }
report, err := convertLibpodNetworktoDockerNetwork(runtime, &net, changed) statuses, err := getContainerNetStatuses(runtime)
if err != nil { if err != nil {
utils.InternalServerError(w, err) utils.InternalServerError(w, err)
return return
} }
report := convertLibpodNetworktoDockerNetwork(runtime, statuses, &net, changed)
utils.WriteResponse(w, http.StatusOK, report) utils.WriteResponse(w, http.StatusOK, report)
} }
func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network *nettypes.Network, changeDefaultName bool) (*types.NetworkResource, error) { func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, statuses []containerNetStatus, network *nettypes.Network, changeDefaultName bool) *types.NetworkResource {
cons, err := runtime.GetAllContainers() containerEndpoints := make(map[string]types.EndpointResource, len(statuses))
if err != nil { for _, st := range statuses {
return nil, err if netData, ok := st.status[network.Name]; ok {
}
containerEndpoints := make(map[string]types.EndpointResource, len(cons))
for _, con := range cons {
data, err := con.Inspect(false)
if err != nil {
if errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved) {
continue
}
return nil, err
}
if netData, ok := data.NetworkSettings.Networks[network.Name]; ok {
ipv4Address := "" ipv4Address := ""
if netData.IPAddress != "" {
ipv4Address = fmt.Sprintf("%s/%d", netData.IPAddress, netData.IPPrefixLen)
}
ipv6Address := "" ipv6Address := ""
if netData.GlobalIPv6Address != "" { macAddr := ""
ipv6Address = fmt.Sprintf("%s/%d", netData.GlobalIPv6Address, netData.GlobalIPv6PrefixLen) for _, dev := range netData.Interfaces {
for _, subnet := range dev.Subnets {
// Note the docker API really wants the full CIDR subnet not just a single ip.
// https://github.com/containers/podman/pull/12328
if netutil.IsIPv4(subnet.IPNet.IP) {
ipv4Address = subnet.IPNet.String()
} else {
ipv6Address = subnet.IPNet.String()
}
}
macAddr = dev.MacAddress.String()
break
} }
containerEndpoint := types.EndpointResource{ containerEndpoint := types.EndpointResource{
Name: con.Name(), Name: st.name,
EndpointID: netData.EndpointID, MacAddress: macAddr,
MacAddress: netData.MacAddress,
IPv4Address: ipv4Address, IPv4Address: ipv4Address,
IPv6Address: ipv6Address, IPv6Address: ipv6Address,
} }
containerEndpoints[con.ID()] = containerEndpoint containerEndpoints[st.id] = containerEndpoint
} }
} }
ipamConfigs := make([]dockerNetwork.IPAMConfig, 0, len(network.Subnets)) ipamConfigs := make([]dockerNetwork.IPAMConfig, 0, len(network.Subnets))
@ -144,7 +171,7 @@ func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network *netty
Peers: nil, Peers: nil,
Services: nil, Services: nil,
} }
return &report, nil return &report
} }
func ListNetworks(w http.ResponseWriter, r *http.Request) { func ListNetworks(w http.ResponseWriter, r *http.Request) {
@ -165,13 +192,14 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err) utils.InternalServerError(w, err)
return return
} }
statuses, err := getContainerNetStatuses(runtime)
if err != nil {
utils.InternalServerError(w, err)
return
}
reports := make([]*types.NetworkResource, 0, len(nets)) reports := make([]*types.NetworkResource, 0, len(nets))
for _, net := range nets { for _, net := range nets {
report, err := convertLibpodNetworktoDockerNetwork(runtime, &net, true) report := convertLibpodNetworktoDockerNetwork(runtime, statuses, &net, true)
if err != nil {
utils.InternalServerError(w, err)
return
}
reports = append(reports, report) reports = append(reports, report)
} }
utils.WriteResponse(w, http.StatusOK, reports) utils.WriteResponse(w, http.StatusOK, reports)