mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 02:00:43 +00:00
synthesise k8s service network from service IPs
This prevents cluttering host.LocalNetworks with lots of /32 addresses. These were unsightly and rather distracting in the UI. They also bloated the report and slowed down server-side rendering. Fixes #2748.
This commit is contained in:
@@ -2,6 +2,7 @@ package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@@ -294,23 +295,32 @@ func (r *Reporter) serviceTopology() (report.Topology, []Service, error) {
|
||||
return result, services, err
|
||||
}
|
||||
|
||||
// FIXME: Hideous hack to remove persistent-connection edges to virtual service
|
||||
// IPs attributed to the internet. We add each service IP as a /32 network
|
||||
// (the global service-cluster-ip-range is not exposed by the API
|
||||
// server so we treat each IP as a /32 network see
|
||||
// https://github.com/kubernetes/kubernetes/issues/25533).
|
||||
// The right way of fixing this is performing DNAT mapping on persistent
|
||||
// connections for which we don't have a robust solution
|
||||
// (see https://github.com/weaveworks/scope/issues/1491)
|
||||
// FIXME: Hideous hack to remove persistent-connection edges to
|
||||
// virtual service IPs attributed to the internet. The global
|
||||
// service-cluster-ip-range is not exposed by the API server (see
|
||||
// https://github.com/kubernetes/kubernetes/issues/25533), so instead
|
||||
// we synthesise it by computing the smallest network that contains
|
||||
// all service IPs. That network may be smaller than the actual range
|
||||
// but that is ok, since in the end all we care about is that it
|
||||
// contains all the service IPs.
|
||||
//
|
||||
// The right way of fixing this is performing DNAT mapping on
|
||||
// persistent connections for which we don't have a robust solution
|
||||
// (see https://github.com/weaveworks/scope/issues/1491).
|
||||
func (r *Reporter) hostTopology(services []Service) report.Topology {
|
||||
localNetworks := report.MakeStringSet()
|
||||
serviceIPs := make([]net.IP, 0, len(services))
|
||||
for _, service := range services {
|
||||
localNetworks = localNetworks.Add(service.ClusterIP() + "/32")
|
||||
if ip := net.ParseIP(service.ClusterIP()).To4(); ip != nil {
|
||||
serviceIPs = append(serviceIPs, ip)
|
||||
}
|
||||
}
|
||||
node := report.MakeNode(report.MakeHostNodeID(r.hostID))
|
||||
node = node.WithSets(report.MakeSets().
|
||||
Add(host.LocalNetworks, localNetworks))
|
||||
return report.MakeTopology().AddNode(node)
|
||||
serviceNetwork := report.ContainingIPv4Network(serviceIPs)
|
||||
if serviceNetwork == nil {
|
||||
return report.MakeTopology()
|
||||
}
|
||||
return report.MakeTopology().AddNode(
|
||||
report.MakeNode(report.MakeHostNodeID(r.hostID)).
|
||||
WithSets(report.MakeSets().Add(host.LocalNetworks, report.MakeStringSet(serviceNetwork.String()))))
|
||||
}
|
||||
|
||||
func (r *Reporter) deploymentTopology(probeID string) (report.Topology, []Deployment, error) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
@@ -105,3 +106,32 @@ func ipv4Nets(addrs []net.Addr) []*net.IPNet {
|
||||
}
|
||||
return nets
|
||||
}
|
||||
|
||||
// ContainingIPv4Network determines the smallest network containing
|
||||
// the given IPv4 addresses. When no addresses are specified, nil is
|
||||
// returned.
|
||||
func ContainingIPv4Network(ips []net.IP) *net.IPNet {
|
||||
if len(ips) == 0 {
|
||||
return nil
|
||||
}
|
||||
network := net.IPNet{
|
||||
IP: ips[0],
|
||||
Mask: net.CIDRMask(net.IPv4len*8, net.IPv4len*8),
|
||||
}
|
||||
for _, ip := range ips[1:] {
|
||||
network.Mask = net.CIDRMask(commonIPv4PrefixLen(network.IP, ip), net.IPv4len*8)
|
||||
network.IP = network.IP.Mask(network.Mask)
|
||||
}
|
||||
return &network
|
||||
}
|
||||
|
||||
func commonIPv4PrefixLen(a, b net.IP) int {
|
||||
x := binary.BigEndian.Uint32(a)
|
||||
y := binary.BigEndian.Uint32(b)
|
||||
cpl := 32
|
||||
for ; x != y; cpl-- {
|
||||
x >>= 1
|
||||
y >>= 1
|
||||
}
|
||||
return cpl
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
@@ -23,3 +24,18 @@ func TestContains(t *testing.T) {
|
||||
t.Errorf("10.0.0.1 in %v", networks)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainingIPv4Network(t *testing.T) {
|
||||
assert.Nil(t, containingIPv4Networks([]string{}))
|
||||
assert.Equal(t, "10.0.0.1/32", containingIPv4Networks([]string{"10.0.0.1"}).String())
|
||||
assert.Equal(t, "10.0.0.0/17", containingIPv4Networks([]string{"10.0.0.1", "10.0.2.55", "10.0.106.48"}).String())
|
||||
assert.Equal(t, "0.0.0.0/0", containingIPv4Networks([]string{"10.0.0.1", "192.168.0.1"}).String())
|
||||
}
|
||||
|
||||
func containingIPv4Networks(ipstrings []string) *net.IPNet {
|
||||
ips := make([]net.IP, len(ipstrings))
|
||||
for i, ip := range ipstrings {
|
||||
ips[i] = net.ParseIP(ip).To4()
|
||||
}
|
||||
return report.ContainingIPv4Network(ips)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user