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
}
// 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
// defined for the container
func (c *Container) HasHealthCheck() bool {
@ -1356,6 +1339,21 @@ func (d ContainerNetworkDescriptions) getInterfaceByName(networkName string) (st
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
// 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.

View File

@ -22,6 +22,36 @@ 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
@ -56,45 +86,42 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
utils.NetworkNotFound(w, name, err)
return
}
report, err := convertLibpodNetworktoDockerNetwork(runtime, &net, changed)
statuses, err := getContainerNetStatuses(runtime)
if err != nil {
utils.InternalServerError(w, err)
return
}
report := convertLibpodNetworktoDockerNetwork(runtime, statuses, &net, changed)
utils.WriteResponse(w, http.StatusOK, report)
}
func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network *nettypes.Network, changeDefaultName bool) (*types.NetworkResource, error) {
cons, err := runtime.GetAllContainers()
if err != nil {
return nil, err
}
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 {
func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, statuses []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 {
ipv4Address := ""
if netData.IPAddress != "" {
ipv4Address = fmt.Sprintf("%s/%d", netData.IPAddress, netData.IPPrefixLen)
}
ipv6Address := ""
if netData.GlobalIPv6Address != "" {
ipv6Address = fmt.Sprintf("%s/%d", netData.GlobalIPv6Address, netData.GlobalIPv6PrefixLen)
macAddr := ""
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{
Name: con.Name(),
EndpointID: netData.EndpointID,
MacAddress: netData.MacAddress,
Name: st.name,
MacAddress: macAddr,
IPv4Address: ipv4Address,
IPv6Address: ipv6Address,
}
containerEndpoints[con.ID()] = containerEndpoint
containerEndpoints[st.id] = containerEndpoint
}
}
ipamConfigs := make([]dockerNetwork.IPAMConfig, 0, len(network.Subnets))
@ -144,7 +171,7 @@ func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network *netty
Peers: nil,
Services: nil,
}
return &report, nil
return &report
}
func ListNetworks(w http.ResponseWriter, r *http.Request) {
@ -165,13 +192,14 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
statuses, err := getContainerNetStatuses(runtime)
if err != nil {
utils.InternalServerError(w, err)
return
}
reports := make([]*types.NetworkResource, 0, len(nets))
for _, net := range nets {
report, err := convertLibpodNetworktoDockerNetwork(runtime, &net, true)
if err != nil {
utils.InternalServerError(w, err)
return
}
report := convertLibpodNetworktoDockerNetwork(runtime, statuses, &net, true)
reports = append(reports, report)
}
utils.WriteResponse(w, http.StatusOK, reports)