Skip to content

Commit

Permalink
gateway metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubdyszkiewicz committed Feb 13, 2020
1 parent a39a586 commit b195671
Show file tree
Hide file tree
Showing 15 changed files with 268 additions and 83 deletions.
64 changes: 54 additions & 10 deletions api/mesh/v1alpha1/dataplane_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,33 @@ func ParseOutboundInterface(text string) (OutboundInterface, error) {
}, nil
}

func (n *Dataplane_Networking) GetOutboundInterfaces() ([]OutboundInterface, error) {
if n == nil {
return nil, nil
}
ofaces := make([]OutboundInterface, len(n.Outbound))
for i, outbound := range n.Outbound {
if outbound.Interface != "" { // legacy format
oface, err := ParseOutboundInterface(outbound.Interface)
if err != nil {
return nil, err
}
ofaces[i] = oface
} else {
oface := OutboundInterface{
DataplanePort: outbound.Port,
}
if outbound.Address != "" {
oface.DataplaneIP = outbound.Address
} else {
oface.DataplaneIP = "127.0.0.1"
}
ofaces[i] = oface
}
}
return ofaces, nil
}

func ParsePort(text string) (uint32, error) {
port, err := strconv.ParseUint(text, 10, 32)
if err != nil {
Expand All @@ -143,15 +170,15 @@ func ParseIP(text string) (string, error) {
}

func (n *Dataplane_Networking) GetInboundInterface(service string) (*InboundInterface, error) {
for _, inbound := range n.Inbound {
ifaces, err := n.GetInboundInterfaces()
if err != nil {
return nil, err
}
for i, inbound := range n.Inbound {
if inbound.Tags[ServiceTag] != service {
continue
}
iface, err := ParseInboundInterface(inbound.Interface)
if err != nil {
return nil, err
}
return &iface, nil
return &ifaces[i], nil
}
return nil, errors.Errorf("Dataplane has no Inbound Interface for service %q", service)
}
Expand All @@ -162,11 +189,28 @@ func (n *Dataplane_Networking) GetInboundInterfaces() ([]InboundInterface, error
}
ifaces := make([]InboundInterface, len(n.Inbound))
for i, inbound := range n.Inbound {
iface, err := ParseInboundInterface(inbound.Interface)
if err != nil {
return nil, err
if inbound.Interface != "" {
iface, err := ParseInboundInterface(inbound.Interface)
if err != nil {
return nil, err
}
ifaces[i] = iface
} else {
iface := InboundInterface{
DataplanePort: inbound.Port,
}
if inbound.Address != "" {
iface.DataplaneIP = inbound.Address
} else {
iface.DataplaneIP = n.Address
}
if inbound.ServicePort != 0 {
iface.WorkloadPort = inbound.ServicePort
} else {
iface.WorkloadPort = inbound.Port
}
ifaces[i] = iface
}
ifaces[i] = iface
}
return ifaces, nil
}
Expand Down
104 changes: 103 additions & 1 deletion api/mesh/v1alpha1/dataplane_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,89 @@ var _ = Describe("ParseOutboundInterface(..)", func() {

var _ = Describe("Dataplane_Networking", func() {

Describe("GetOutboundInterfaces()", func() {
Context("valid input values", func() {
type testCase struct {
input *Dataplane_Networking
expected []OutboundInterface
}

DescribeTable("should parse valid input values",
func(given testCase) {
// when
ofaces, err := given.input.GetOutboundInterfaces()
// then
Expect(err).ToNot(HaveOccurred())
// and
Expect(ofaces).To(Equal(given.expected))
},
Entry("nil", testCase{
input: nil,
expected: nil,
}),
Entry("empty", testCase{
input: &Dataplane_Networking{},
expected: []OutboundInterface{},
}),
Entry("legacy - 2 outbound interfaces", testCase{
input: &Dataplane_Networking{
Outbound: []*Dataplane_Networking_Outbound{
{Interface: ":8080"},
{Interface: "192.168.0.1:443"},
},
},
expected: []OutboundInterface{
{DataplaneIP: "127.0.0.1", DataplanePort: 8080},
{DataplaneIP: "192.168.0.1", DataplanePort: 443},
},
}),
Entry("2 outbound interfaces", testCase{
input: &Dataplane_Networking{
Outbound: []*Dataplane_Networking_Outbound{
{
Port: 8080,
},
{
Address: "192.168.0.1",
Port: 443,
},
},
},
expected: []OutboundInterface{
{DataplaneIP: "127.0.0.1", DataplanePort: 8080},
{DataplaneIP: "192.168.0.1", DataplanePort: 443},
},
}),
)
})

Context("invalid input values", func() {
type testCase struct {
input *Dataplane_Networking
expectedErr gomega_types.GomegaMatcher
}

DescribeTable("should fail on invalid input values",
func(given testCase) {
// when
ifaces, err := given.input.GetOutboundInterfaces()
// then
Expect(ifaces).To(BeNil())
// and
Expect(err.Error()).To(given.expectedErr)
},
Entry("dataplane IP address is missing", testCase{
input: &Dataplane_Networking{
Outbound: []*Dataplane_Networking_Outbound{
{Interface: ":443:8443"},
},
},
expectedErr: Equal(`invalid format: expected "[ IPv4 | '[' IPv6 ']' ] ':' DATAPLANE_PORT", got ":443:8443"`),
}),
)
})
})

Describe("GetInboundInterfaces()", func() {

Context("valid input values", func() {
Expand All @@ -344,7 +427,7 @@ var _ = Describe("Dataplane_Networking", func() {
input: &Dataplane_Networking{},
expected: []InboundInterface{},
}),
Entry("2 inbound interfaces", testCase{
Entry("legacy - 2 inbound interfaces", testCase{
input: &Dataplane_Networking{
Inbound: []*Dataplane_Networking_Inbound{
{Interface: "192.168.0.1:80:8080"},
Expand All @@ -356,6 +439,25 @@ var _ = Describe("Dataplane_Networking", func() {
{DataplaneIP: "192.168.0.1", DataplanePort: 443, WorkloadPort: 8443},
},
}),
Entry("2 inbound interfaces", testCase{
input: &Dataplane_Networking{
Address: "192.168.0.1",
Inbound: []*Dataplane_Networking_Inbound{
{
Port: 80,
},
{
Address: "192.168.0.1",
Port: 443,
ServicePort: 8443,
},
},
},
expected: []InboundInterface{
{DataplaneIP: "192.168.0.1", DataplanePort: 80, WorkloadPort: 80},
{DataplaneIP: "192.168.0.1", DataplanePort: 443, WorkloadPort: 8443},
},
}),
)
})

Expand Down
19 changes: 11 additions & 8 deletions pkg/core/permissions/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ type TrafficPermissionsMatcher struct {
ResourceManager manager.ResourceManager
}

type MatchedPermissions map[string]*mesh_core.TrafficPermissionResourceList
type MatchedPermissions map[mesh_proto.InboundInterface]*mesh_core.TrafficPermissionResourceList

func (m MatchedPermissions) Get(inbound string) *mesh_core.TrafficPermissionResourceList {
func (m MatchedPermissions) Get(inbound mesh_proto.InboundInterface) *mesh_core.TrafficPermissionResourceList {
matched, ok := m[inbound]
if ok {
return matched
Expand All @@ -28,24 +28,27 @@ func (m *TrafficPermissionsMatcher) Match(ctx context.Context, dataplane *mesh_c
if err := m.ResourceManager.List(ctx, permissions, store.ListByMesh(dataplane.GetMeta().GetMesh())); err != nil {
return nil, err
}
return MatchDataplaneTrafficPermissions(&dataplane.Spec, permissions), nil
return MatchDataplaneTrafficPermissions(&dataplane.Spec, permissions)
}

func MatchDataplaneTrafficPermissions(dataplane *mesh_proto.Dataplane, permissions *mesh_core.TrafficPermissionResourceList) MatchedPermissions {
func MatchDataplaneTrafficPermissions(dataplane *mesh_proto.Dataplane, permissions *mesh_core.TrafficPermissionResourceList) (MatchedPermissions, error) {
matchedPermissions := make(MatchedPermissions)
for _, inbound := range dataplane.GetNetworking().GetInbound() {
matchedPermissions[inbound.Interface] = &mesh_core.TrafficPermissionResourceList{
ifaces, err := dataplane.GetNetworking().GetInboundInterfaces()
if err != nil {
return nil, err
}
for i, inbound := range dataplane.GetNetworking().GetInbound() {
matchedPermissions[ifaces[i]] = &mesh_core.TrafficPermissionResourceList{
Items: matchInbound(inbound, permissions),
}
}
return matchedPermissions
return matchedPermissions, nil
}

func matchInbound(inbound *mesh_proto.Dataplane_Networking_Inbound, trafficPermissions *mesh_core.TrafficPermissionResourceList) []*mesh_core.TrafficPermissionResource {
matchedPerms := []*mesh_core.TrafficPermissionResource{}
for _, perm := range trafficPermissions.Items {
if len(perm.Spec.Sources) == 0 {
// todo(jakubdyszkiewicz) there shouldn't be any rule with 0 sources. Move to validation logic in a manager
continue
}
for _, dest := range perm.Spec.Destinations {
Expand Down
15 changes: 12 additions & 3 deletions pkg/core/permissions/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,15 @@ var _ = Describe("Matcher", func() {
}

// when
matchedPerms := MatchDataplaneTrafficPermissions(&dataplane, &permissions)
matchedPerms, err := MatchDataplaneTrafficPermissions(&dataplane, &permissions)

// then
backendMatches := matchedPerms.Get("192.168.0.1:8080:80")
Expect(err).ToNot(HaveOccurred())
backendMatches := matchedPerms.Get(mesh_proto.InboundInterface{
DataplaneIP: "192.168.0.1",
DataplanePort: 8080,
WorkloadPort: 80,
})
expectedBackendMatches := core_mesh.TrafficPermissionResourceList{
Items: []*core_mesh.TrafficPermissionResource{
{
Expand Down Expand Up @@ -204,7 +209,11 @@ var _ = Describe("Matcher", func() {
},
},
}
webMatches := matchedPerms.Get("192.168.0.1:8090:90")
webMatches := matchedPerms.Get(mesh_proto.InboundInterface{
DataplaneIP: "192.168.0.1",
DataplanePort: 8090,
WorkloadPort: 90,
})
Expect(*webMatches).To(Equal(expectedWebMatches))
})
})
24 changes: 14 additions & 10 deletions pkg/core/resources/apis/mesh/dataplane_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ func (d *DataplaneResource) UsesInboundInterface(address net.IP, port uint32) bo
if d == nil {
return false
}
for _, inbound := range d.Spec.Networking.GetInbound() {
iface, err := mesh_proto.ParseInboundInterface(inbound.Interface)
if err != nil {
continue
}
ifaces, err := d.Spec.Networking.GetInboundInterfaces()
if err != nil {
return false
}
for _, iface := range ifaces {
// compare against port and IP address of the dataplane
if port == iface.DataplanePort && overlap(address, net.ParseIP(iface.DataplaneIP)) {
return true
Expand All @@ -39,11 +39,11 @@ func (d *DataplaneResource) UsesOutboundInterface(address net.IP, port uint32) b
if d == nil {
return false
}
for _, outbound := range d.Spec.Networking.GetOutbound() {
oface, err := mesh_proto.ParseOutboundInterface(outbound.Interface)
if err != nil {
continue
}
ofaces, err := d.Spec.Networking.GetOutboundInterfaces()
if err != nil {
return false
}
for _, oface := range ofaces {
// compare against port and IP address of the dataplane
if port == oface.DataplanePort && overlap(address, net.ParseIP(oface.DataplaneIP)) {
return true
Expand Down Expand Up @@ -75,6 +75,10 @@ func (d *DataplaneResource) GetIP() string {
if d == nil {
return ""
}
if d.Spec.Networking.Address != "" {
return d.Spec.Networking.Address
}
// fallback to legacy format
ifaces, err := d.Spec.Networking.GetInboundInterfaces()
if err != nil {
return ""
Expand Down
15 changes: 13 additions & 2 deletions pkg/core/resources/apis/mesh/dataplane_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,18 @@ var _ = Describe("Dataplane", func() {
`,
expected: "",
}),
Entry("dataplane with 1 inbound interface", testCase{
Entry("dataplane with address in networking", testCase{
dataplane: `
networking:
address: 192.168.0.1
inbound:
- port: 8080
tags:
service: backend
`,
expected: "192.168.0.1",
}),
Entry("legacy - dataplane with 1 inbound interface", testCase{
dataplane: `
networking:
inbound:
Expand All @@ -383,7 +394,7 @@ var _ = Describe("Dataplane", func() {
`,
expected: "192.168.0.1",
}),
Entry("dataplane with 2 inbound interfaces", testCase{
Entry("legacy - dataplane with 2 inbound interfaces", testCase{
dataplane: `
networking:
inbound:
Expand Down
6 changes: 3 additions & 3 deletions pkg/mads/reconcile/snapshot_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,13 @@ var _ = Describe("snapshotGenerator", func() {
},
Spec: mesh_proto.Dataplane{
Networking: &mesh_proto.Dataplane_Networking{
Inbound: []*mesh_proto.Dataplane_Networking_Inbound{{
Interface: "192.168.0.3:3000:3000",
Address: "192.168.0.3",
Gateway: &mesh_proto.Dataplane_Networking_Gateway{
Tags: map[string]string{
"service": "web",
"env": "test",
},
}},
},
},
Metrics: &mesh_proto.Metrics{
Prometheus: &mesh_proto.Metrics_Prometheus{
Expand Down
Loading

0 comments on commit b195671

Please sign in to comment.